Author Topic: PIC24 SPI not working  (Read 9439 times)

0 Members and 1 Guest are viewing this topic.

Offline diyaudioTopic starter

  • Frequent Contributor
  • **
  • !
  • Posts: 683
  • Country: za
PIC24 SPI not working
« on: March 23, 2014, 10:26:39 am »
Hi Guys

I cannot get SPI to work, no clock nothing, I slapped together some SPI code after reading the PIC24F128210 after reading the datasheet a reasonable amount of times, I still cannot seem to understand why its not working.

The SPI is commanding a MCP4921 DAC. 

Here is the code


FOSC using internal 8MHZ clock. 
Code: [Select]
int main(int argc, char** argv)
{
    // G15 PORTG as output. (used as a test)
    TRISGbits.TRISG15 = 0;  // OUTPUT LED status flash
    TRISEbits.TRISE6 = 0;   // OUTPUT SCL-3
    TRISEbits.TRISE7 = 0;   // OUTPUT SDA-3
    TRISEbits.TRISE5 = 0;   // DAC Chip select.

    reset_clock();

    CS_DAC = 1;
   
    /* Init SPI-3  */

 
    /* ## SPI3CON1: SPIx CONTROL REGISTER 1 */

    // bit 1-0 PPRE<1:0>: Primary Prescale bits (Master mode)
    // 11  =  Primary prescale 1:1
    SPI3CON1bits.PPRE = 11;

    // bit 4-2 SPRE<2:0>: Secondary Prescale bits (Master mode)
    // 111  = Secondary prescale 1:1
    SPI3CON1bits.SPRE = 111;

    // bit 5 MSTEN: Master Mode Enable bit (1  = Master mode).
    SPI3CON1bits.MSTEN = 1;
   
    // bit 6 CKP: Clock Polarity Select bit
    // (1 = Idle state for the clock is a low level; active state is a high level).
    SPI3CON1bits.CKP = 0;

    // bit 8 CKE: SPIx Clock Edge Select bit(3)
    // 0  = Serial output data changes on transition from Idle clock state to active clock state (see bit 6).
    SPI3CON1bits.CKE = 0;
   
    // bit 10 MODE16: Word/Byte Communication Select bit
    // 1  = Communication is byte-wide (16 - bits).
    SPI3CON1bits.MODE16 = 0;

    // bit 11 DISSDO: Disable SDOx Pin bit(2)
    // 0  = SDOx pin is controlled by the module.
    SPI3CON1bits.DISSDO = 0;

    // bit 12 DISSCK: Disable SCKx Pin bit (SPI Master modes only)(1)
    // 0  = Internal SPI clock is enabled
    SPI3CON1bits.DISSCK = 0;
       
    // ## SPI3CON3: SPIx CONTROL REGISTER 2
    // bit 0 SPIBEN: Enhanced Buffer Enable bit
    // 0  = Enhanced buffer is disabled (Legacy mode)
    SPI3CON2bits.SPIBEN = 0;

    // 3. Clear the SPIROV bit (SPIxSTAT<6>).
    SPI3STATbits.SPIROV = 0;

    // 4. Enable SPI operation by setting the SPIEN bit. (SPIxSTAT<15>).
    SPI3STATbits.SPIEN = 1;



    while(1)
    {

       adc_spi_write(11);
       __delay_us(100);
    }

    return (EXIT_SUCCESS);
}

void adc_spi_write(unsigned int data)
{
    CS_DAC = 0;

    /* 5. Write the data to be transmitted to the SPIxBUF
          register. Transmission (and reception) will start
          as  soon  as  data  is  written  to  the  SPIxBUF
          register.
    */
    SPI3BUF = data;

     /*
       bit 1 SPITBF: SPIx Transmit Buffer Full Status bit
        1  = Transmit has not yet started, SPIxTXB is full
        0  = Transmit has started, SPIxTXB is empty

        In Standard Buffer mode:
        Automatically set in hardware when the CPU writes to the SPIxBUF location, loading SPIxTXB.
        Automatically cleared in hardware when the SPIx module transfers data from SPIxTXB to SPIxSR.
     */
    while(!SPI3STATbits.SPIRBF);

   
    CS_DAC = 1;
}

« Last Edit: March 23, 2014, 10:58:28 am by diyaudio »
 

Offline hans

  • Super Contributor
  • ***
  • Posts: 1720
  • Country: 00
Re: PIC24 SPI not working
« Reply #1 on: March 23, 2014, 11:50:05 am »
Code: [Select]
    TRISEbits.TRISE6 = 0;   // OUTPUT SCL-3
    TRISEbits.TRISE7 = 0;   // OUTPUT SDA-3

Unless you're using it elsewhere, that is not SPI but I2C. (They are the correct pins for I2C, but the MCP4921 isn't an I2C device. Also I2C pins are usually configured as inputs/open-drain, with pull-ups).
Some DAC's or ADC's are so minimalistic set-up, they only have a SDI (MOSI/DAC) or SDO (MISO/ADC), clock and chip select pin. Some DAC's don't have any registers to read from, so they saved a pin by leaving out the MISO

See the pinout of the chip and notice how the bold RPx are shown. These are pins that can have a variety of pins mapped to them. Peripherals like UART, SPI, most timer input/outputs, and most external interrupts are only active&accessible via PPS (peripheral pin select) module.

You have to map the pins to the reprogrammable Pins you use at start-up. For example (XC16 code):
Code: [Select]
#include <pps.h>

[..]
PPSUnLock; // unlocks PPS for configuration
iPPSOutput(OUT_PIN_PPS_RP7, OUT_FN_PPS_SCK1OUT); // Reprogrammable Pin 7 = SPI SCK 1
iPPSOutput(OUT_PIN_PPS_RP8, OUT_FN_PPS_SDO1); // Reprogrammable Pin 8 = SPI MOSI 1
iPPSInput(IN_FN_PPS_SDI1, IN_PIN_PPS_RP20); // Reprogrammable Pin 20 = SPI MISO 1
PPSLock;
[..]
You also need to set TRIS registers correctly for each pin, and also good thing to check if analog features are disabled (if available) for that pin.


Edit: I suspect you're using a PIC24FJ128GB210 or PIC24FJ128DA210, because those are only the few parts that end with 210.
« Last Edit: March 23, 2014, 11:59:36 am by hans »
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: PIC24 SPI not working
« Reply #2 on: March 23, 2014, 11:55:28 am »
Quote
PIC24 SPI not working

A more accurate description would be that you cannot make it work.

Quote
PIC24F128210

That's some chip. No one can help you, I am afraid.

The general process is this:

1) read and understand the datasheet;
2) code to the datasheet;
3) celebrate success.

For PIC24s, make sure you have assigned the spi pins to RPx.

Code: [Select]
void adc_spi_write(unsigned int data)
{
    CS_DAC = 0;

It is generally a bad idea to put framing signal inside of a spi byte transmission session, as you may need to transmitt multiple bytes in one frame.

Code: [Select]

    /* 5. Write the data to be transmitted to the SPIxBUF
          register. Transmission (and reception) will start
          as  soon  as  data  is  written  to  the  SPIxBUF
          register.
    */
    SPI3BUF = data;

The typical sequence would be something like this:

Code: [Select]
spi_write(data):
  while (spi buffer is not empty) continue; //wait for the buffer to be available
  SPIxBUF = data; //load up the buffer
  :end

your transmmmision sequence would be like this:
Code: [Select]
  activate CS;
  spi_write(data1);
  spi_write(data2);
  ...
  spi_write(last data);
  while (spi_busy) continue; //wait for the transmission to finish
  deactivate CS;

For spi modules with a buffer, this greatly speeds up the transmission, particularly at low baud rate.

For spi module without a buffer, those two conditions are the same.
================================
https://dannyelectronics.wordpress.com/
 

Offline diyaudioTopic starter

  • Frequent Contributor
  • **
  • !
  • Posts: 683
  • Country: za
Re: PIC24 SPI not working
« Reply #3 on: March 23, 2014, 12:22:06 pm »
Sorry Guys, I just started working with the PIC-24 Family now recently. I come from the PIC18F45K20 demo-board.

Correction. its a PIC24FJ128GB210, some clarity around the problem I mean nothing works as I mentioned, no clock on the scope, no data on the scope. (during SPI data transmission)

I think my problem is around the reprogrammable pins, you need at start-up. as @hans and you mentioned. (I'm new to this the datasheet says nothing around this during start-up)

Quote
It is generally a bad idea to put framing signal inside of a spi byte transmission session, as you may need to transmit multiple bytes in one frame.

I did this only as a first time test, but thanks for the tip i will keep this in mind. care to show me how you do it ?

I will look into the reprogrammable pins now... I am 100% sure its this.
 
« Last Edit: March 23, 2014, 12:25:58 pm by diyaudio »
 

Offline diyaudioTopic starter

  • Frequent Contributor
  • **
  • !
  • Posts: 683
  • Country: za
Re: PIC24 SPI not working
« Reply #4 on: March 23, 2014, 01:14:52 pm »
Code: [Select]

int main(int argc, char** argv)
{
    PPSUnLock; // unlocks PPS for configuration
        iPPSOutput(OUT_PIN_PPS_RP7, OUT_FN_PPS_SCK1OUT); // Reprogrammable Pin 7 = SPI SCK 1
        iPPSOutput(OUT_PIN_PPS_RP6, OUT_FN_PPS_SDO1); // Reprogrammable Pin 8 = SPI MOSI 1
       // iPPSInput(IN_FN_PPS_SDI1, IN_PIN_PPS_RP20); // Reprogrammable Pin 20 = SPI MISO 1
    PPSLock;

    // G15 PORTG as output. (used as a test)
    TRISGbits.TRISG15 = 0;  // OUTPUT LED status flash
    TRISEbits.TRISE5 = 0;   // DAC Chip select.

    reset_clock();

    CS_DAC = 1;
   
    /* Init SPI-3  */

    /* ## SPI3CON1: SPIx CONTROL REGISTER 1 */

    // bit 1-0 PPRE<1:0>: Primary Prescale bits (Master mode)
    // 11  =  Primary prescale 1:1
    SPI1CON1bits.PPRE = 110;

    // bit 4-2 SPRE<2:0>: Secondary Prescale bits (Master mode)
    // 111  = Secondary prescale 1:1
    SPI1CON1bits.SPRE = 111;

    // bit 5 MSTEN: Master Mode Enable bit (1  = Master mode).
    SPI1CON1bits.MSTEN = 1;
   
    // bit 6 CKP: Clock Polarity Select bit
    // (1 = Idle state for the clock is a low level; active state is a high level).
    SPI1CON1bits.CKP = 1;

    // bit 8 CKE: SPIx Clock Edge Select bit(3)
    // 0  = Serial output data changes on transition from Idle clock state to active clock state (see bit 6).
    SPI1CON1bits.CKE = 1;
   
    // bit 10 MODE16: Word/Byte Communication Select bit
    // 1  = Communication is byte-wide (16 - bits).
    SPI1CON1bits.MODE16 = 0;

    // bit 11 DISSDO: Disable SDOx Pin bit(2)
    // 0  = SDOx pin is controlled by the module.
    SPI1CON1bits.DISSDO = 0;

    // bit 12 DISSCK: Disable SCKx Pin bit (SPI Master modes only)(1)
    // 0  = Internal SPI clock is enabled
    SPI1CON1bits.DISSCK = 0;
       
    // ## SPI3CON3: SPIx CONTROL REGISTER 2
    // bit 0 SPIBEN: Enhanced Buffer Enable bit
    // 0  = Enhanced buffer is disabled (Legacy mode)
    SPI1CON2bits.SPIBEN = 0;

    // 3. Clear the SPIROV bit (SPIxSTAT<6>).
    SPI1STATbits.SPIROV = 0;

    // 4. Enable SPI operation by setting the SPIEN bit. (SPIxSTAT<15>).
    SPI1STATbits.SPIEN = 1;


    while(1)
    {
       adc_spi_write('U');
       __delay_us(10);
    }

    return (EXIT_SUCCESS);
}



void adc_spi_write(unsigned char data)
{
    CS_DAC = 0;

    /* 5. Write the data to be transmitted to the SPIxBUF
          register. Transmission (and reception) will start
          as  soon  as  data  is  written  to  the  SPIxBUF
          register.
    */

    SPI1BUF = data;

     /*
       bit 1 SPITBF: SPIx Transmit Buffer Full Status bit
        1  = Transmit has not yet started, SPIxTXB is full
        0  = Transmit has started, SPIxTXB is empty

        In Standard Buffer mode:
        Automatically set in hardware when the CPU writes to the SPIxBUF location, loading SPIxTXB.
        Automatically cleared in hardware when the SPIx module transfers data from SPIxTXB to SPIxSR.
     */
    while(!SPI1STATbits.SPIRBF);

   
    CS_DAC = 1;
}

Thanks, it works it was the reprogrammable pins, I have much to learn around this area.

Interesting not sure why the data packets look so dirty.
 
« Last Edit: March 23, 2014, 01:19:00 pm by diyaudio »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf