2
\$\begingroup\$

Ive been trying really hard to get the SPI bus working on a DSPIC33EP128GM604. Ive configured SPI3 as a standard 8 bit master module and have designated a chip select pin so I can toggle slave devices.

I cannot get the chip select line to work properly, it seems as if the DSPIC does not wait for transmission to complete before toggling the chip select line from LOW to HIGH. Ive checked the Erratas and nothing seems relevant to this problem. Furthermore ive tried to swap the CS line to some other pin. Ive also tried SPI module 1, but problem persists.

Here is my code:

SPI 3 configuration:

void Init_SPI3 ( void )
{
IFS5bits.SPI3IF = 0; // Clear the Interrupt flag
IEC5bits.SPI3IE = 0; // Disable the interrupt
// SPI1CON1 Register Settings
SPI3CON1bits.DISSCK = 0; // Internal serial clock is enabled
SPI3CON1bits.DISSDO = 0; // SDOx pin is controlled by the module
SPI3CON1bits.MODE16 = 0; // Communication is word-wide (16 bits)
SPI3CON1bits.SSEN = 0; //No CS
SPI3CON1bits.MSTEN = 1; // Master mode disabled
SPI3CON1bits.PPRE = 2; //Pre-scaler
SPI3CON1bits.SPRE = 8;//Pre-scaler 2
SPI3CON1bits.SMP =1; // Input data is sampled at the middle of data output time
SPI3CON1bits.CKE =0; // Serial output data changes on transition from
SPI3CON1bits.CKP = 0; // Idle state for clock is a low level;
SPI3STATbits.SPIEN = 1; // Enable SPI module
// Interrupt Controller Settings
IFS5bits.SPI3IF = 0; // Clear the Interrupt flag
IEC5bits.SPI3IE = 1; // Enable the interrupt
}

SPI 3 Pin configuration:

TRISBbits.TRISB10 = 0; //Set SPI3CLK as output
TRISBbits.TRISB11 = 0; //Set SPI3DATAOUT as output

RPOR4bits.RP42R=32;  //SPI3_CLK out
RPOR4bits.RP43R=31;  //SPI3_DATA out

Chip select line pin configuration:

TRISBbits.TRISB4 = 0; //SPI3 CS is on Pin B4, set it to Output

Simple main routine:

    while(1==1){

    PORTBbits.RB4 = 0;//Set CS line to low  
   WriteSPI3(0xaa); //This is from the peripheral library to be safe....
  PORTBbits.RB4 = 1; //Set CS line to high
                    }

But here is the output:

enter image description here

\$\endgroup\$
  • \$\begingroup\$ Specifically, what is the problem that I should be seeing in the scope pic? \$\endgroup\$ – Scott Seidman Aug 10 '16 at 21:56
  • \$\begingroup\$ Where are you setting the SPI mode w/ CPOL and CPHA \$\endgroup\$ – Scott Seidman Aug 10 '16 at 21:57
  • \$\begingroup\$ the bits .CKE and .CKP? \$\endgroup\$ – Adil Malik Aug 10 '16 at 22:05
  • \$\begingroup\$ Sorry -- been a long time since using a dsPIC, and I'm used to STM32F CMSIS calls. Are you sure those values are right for the device you're trying to talk with? \$\endgroup\$ – Scott Seidman Aug 10 '16 at 22:07
  • \$\begingroup\$ I havnt even tried that yet. The problem is the CS line is not being toggled correctly. If you look at the purple trace (CS) it changes state prematurely. Im quite fed up with DSPIC tbh, im giving it one more day before I switch to the STM32s.... \$\endgroup\$ – Adil Malik Aug 10 '16 at 22:09
1
\$\begingroup\$

From the datasheet and example codes, the Receive Buffer Flag is sufficient to tell us when the TX event is complete and thus the CS can toggle. It is a bit strange why there isnt a flag for this chip that tells us when the SPI shift register has transmitted all its data. All the example code only check the Receive buffer flag.

After a lot of head scratching, trial and error and finally the microchip forums, i can confirm that this code works:

   uint8_t Write_SPI1(uint8_t command) { //Does work    
    SPI1BUF = command; // send data over SPI
    while(!SPI1STATbits.SPIRBF) ; //wait until SPIRBF goes high  
    return SPI1BUF; //KEY STATEMENT THAT MADE A DIFFERENCE, Return the actual data received
    }

Along with this code, if your peripheral depends on Peripheral Pin Select (SPI2,SPI3 etc), it is important to define not only a SPI Clock Out but also a SPI Clock In even if you are in master mode

However, what is rather baffling to me is that this code (that i think should do the same thing) does not work:

  void Write_SPI1(uint8_t command) { //Does not work, premature toggle of CS, tried this code initially....
    uint8_t garbage;
    SPI1BUF = command; // send data over SPI
    while(!SPI1STATbits.SPIRBF) ; //wait until SPIRBF goes high 
    garbage = SPI1BUF; // read dummy data, does not seem to clear the flag as expected
    }
\$\endgroup\$
  • \$\begingroup\$ Odd. Just a thought -- have you tried turning optimization off before you compile?? Looks like your compiler is taking shortcuts you don't want it to take, and turning optimization off might make things better. \$\endgroup\$ – Scott Seidman Aug 12 '16 at 14:09
  • \$\begingroup\$ In fact, the compiler might see "garbage" as never being used, and optimize out the whole line. It can't optimize away a return value. \$\endgroup\$ – Scott Seidman Aug 12 '16 at 14:10
  • \$\begingroup\$ ... or, try adding volatile to the garbage declaration. \$\endgroup\$ – Scott Seidman Aug 12 '16 at 14:19
  • \$\begingroup\$ adding volatile does not work. But returning garbage instead of SPI1BUF also works. Hmmm, sounds like a compiler perk. \$\endgroup\$ – Adil Malik Aug 12 '16 at 14:53
0
\$\begingroup\$

Wait until the SPI transmission is complete before un-asserting the chip select with something like

 while(SPI3_Tx_Buf_Full);  //wait till completion of transmission

See the example using SPI1 at http://pat.cybersites.ca/docs/PIC24F/SPI_Example1.html

\$\endgroup\$
  • \$\begingroup\$ I assumed the peripheral library would take care of that. Nonetheless i found the equivalent flag for my chip: while(SPI3STATbits.SPITBF){}; Makes no difference, is the flag being set incorrectly by the module somehow? \$\endgroup\$ – Adil Malik Aug 10 '16 at 19:11
  • 1
    \$\begingroup\$ SPITBF only indicates whether or not there are bits in the buffer, not whether it is still transmitting. After the while statement you added, try while(!SPI3STATbits.SPIRBF) to hold until transmission is finished and something has been put in the receive buffer (even if you don't do anything with it). \$\endgroup\$ – Cheibriados Aug 10 '16 at 19:19
  • 2
    \$\begingroup\$ @AdilMalik you're confusing the TX Buffer with the TX Shift Register. The Shift Register is where the bits are actually sent from, while the Buffer is where your code loads them. The module internally transfers your data byte from the Buffer to the Shift Register as it's getting ready to send it (giving you a SPITBF flag indication), but at this point, the bits are still in the Shift Register and haven't been sent out yet. if you use SPIRBF as a flag to tell you when the transaction is complete you need to make sure you empty the RX Buffer first so the the SPIRBF flag starts off cleared. \$\endgroup\$ – brhans Aug 10 '16 at 19:34
  • 1
    \$\begingroup\$ @AdilMalik - "is this a possible bug?" Assuming your -CS signal is the purple line on your 'scope photo, then no, I would not be looking for a DSPIC33 bug. That is because a -CS signal like that purple line would never work for a normal SPI slave, and a bug as serious as that would be well-known. I don't use that MCU, but if I was in your position, in addition to the helpful advice you are receiving, I would start by looking for working sample SPI code. Here is an EE.SE thread which contains a claimed-to-be-working SPI Master example. \$\endgroup\$ – SamGibson Aug 10 '16 at 21:21
  • 1
    \$\begingroup\$ So for the functionally same routine they are checking 2 difernet flags, nonetheless the idea is the same. It does not work in both cases. But if i waste a few cycles with a for loop, the CS pin toggles correctly as expected \$\endgroup\$ – Adil Malik Aug 10 '16 at 21:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.