SPI has delays and quirky line behaviour

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderators: RoccoMarco, barthess

goeck
Posts: 92
Joined: Mon Feb 11, 2013 12:00 pm
Location: Germany

SPI has delays and quirky line behaviour

Postby goeck » Wed Apr 16, 2014 1:27 pm

Hey everyone,

I need a hint on the SPI peripheral optimization. I am using a L6470 dSPIN device at the SPI bus attached to a STM32F0Discovery, which pretty much works. If I look at the lines, I see ugly stuff though and I want to get rid of that, maybe one has some advices for me. Please have a look at the following screenshot showing a 4byte long communication with a selected L6470. I see some quirks:
    - MOSI line flips around in between transmission of single bytes (looks the same on a scope)
    - time between transmission of each byte takes very long
    - timespan from sending byte done until ENABLE goes high is very long
The L6470 has to be supplied with a ENABLE line double toggle after each byte is sent out, the high timespan has to be at least 800ns. If I do a spiExchange of N=4 bits this works yust like expected, but the L6470 just doesn't understand this. Basically I thought of just interrupting the quick transfer of bytes only by 1-2us. It turns out, I can't narrow the timegap closer than 28us :-(

The code looks like this

Code: Select all

/**
 * SPI1 configuration structure.
 * CPHA=0, CPOL=0, 8bits frames, MSb transmitted first.
 */
static SPIConfig dspin_spi_config = {
   NULL,
   /* HW dependent part.*/
   DSPIN_CS_PORT,
   DSPIN_CS_PIN,
   SPI_CR1_BR_0 | SPI_CR1_BR_1
};

/**
  * \brief  Transmits/Receives one byte to/from dSPIN over SPI.
  * \param  byte to be transmitted
  * \return Received byte
  */
/**
 * Acquires SPI bus for further transmissions.\n
 * Starts the SPI engine and selects a client -> dSPIN device
 */
void dSPIN_Acquire_Bus(void) {
   spiStart(&SPID1, &dspin_spi_config);
   spiSelect(&SPID1);
}

/**
 * Releases SPI bus.
 */
void dSPIN_Release_Bus(void) {   
   spiUnselect(&SPID1);
   spiStop(&SPID1);
}

uint8_t dSPIN_Write_Byte(uint8_t byte)
{
   uint8_t spiBufferTx[1] = { 0 };
   uint8_t spiBufferRx[1] = { 0 };
   spiBufferTx[0] = byte;

   dSPIN_Acquire_Bus();
   spiExchange(&SPID1, 1, spiBufferTx, spiBufferRx);
   dSPIN_Release_Bus();

   return spiBufferRx[0];
}
int main(){
   halInit();
   chSysInit();

   palSetPadMode(   SPI_MISO_PORT, SPI_MISO_PIN,
               PAL_MODE_ALTERNATE(0) | PAL_STM32_OSPEED_HIGHEST);
   palSetPadMode(   SPI_MOSI_PORT, SPI_MOSI_PIN,
               PAL_MODE_ALTERNATE(0) | PAL_STM32_OSPEED_HIGHEST);
   palSetPadMode(   SPI_SCK_PORT,  SPI_SCK_PIN,
               PAL_MODE_ALTERNATE(0) | PAL_STM32_OSPEED_HIGHEST);
   palSetPadMode(   DSPIN_CS_PORT,   DSPIN_CS_PIN,
               PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
   palSetPad(      DSPIN_CS_PORT, DSPIN_CS_PIN);
   spiObjectInit(&SPID1);

   spiAcquireBus(&SPID1);

   /* Send RUN operation code to dSPIN */
   dSPIN_Write_Byte(dSPIN_Command_RUN | direction);

   /* Send speed - byte 2 data dSPIN */
   dSPIN_Write_Byte((uint8_t)(speed >> 16));

   /* Send speed - byte 1 data dSPIN */
   dSPIN_Write_Byte((uint8_t)(speed >> 8));

   /* Send speed - byte 0 data dSPIN */
   dSPIN_Write_Byte((uint8_t)(speed));

   spiReleaseBus(&SPID1);

   while(TRUE){
      chThdSleepSeconds(2);
   }
}


I tried to post as a attachement the conf headers, but nothing gets through. If desired I paste the content or upload the elsewhere.

I would be evry happy to optimize this behaviour and get to a datasheet-clean communication.
Thanks in any case!

Cheers
Stefan
Attachments
screenshot.png
Saleae Logic analyzer screenshot
screenshot.png (98.88 KiB) Viewed 5047 times

User avatar
Giovanni
Site Admin
Posts: 14457
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: SPI has delays and quirky line behaviour

Postby Giovanni » Wed Apr 16, 2014 4:10 pm

You don't need to acquire the bus and release it for each byte, if you don't access the SPI from multiple threads you can omit acquire/release at all.
Also, you may use send/receive where appropriate, exchange is a bit heavier.

I don't understand the problem with L6470, there should be no reason it should not accept a continuous transmission. This makes me think you also have some HW problem there.

Giovanni

goeck
Posts: 92
Joined: Mon Feb 11, 2013 12:00 pm
Location: Germany

Re: SPI has delays and quirky line behaviour

Postby goeck » Thu Apr 17, 2014 12:15 pm

Hey Giovanni,

thanks for your thoughts.
I looked up the datasheet SPI section of the L6470 and have to say, I was right.
datasheet_L6470_SPI.png
datasheet_L6470_SPI.png (25.37 KiB) Viewed 5026 times


I also deleted the aquire-functions, but nothing changed. Also I made use of only a send function, instead of a exchange, no improvement. I even used the code without the actual data sending/exchanging function, so only this was left in the communication

Code: Select all

spiStart();
spiSelect();
spiUnselect();
spiStop();

Still the quirks and the timelags where there. One thing that I gathered from this was, I saw a certain fixed pattern on the MOSI line, that must come from the four left functions and the lld driver (I guess). Looking into it I only ended up with some dma dealing functions and thread waiting and waking... I saw nothing suspicious.

Any comments are highly appreciated
Cheers

User avatar
Giovanni
Site Admin
Posts: 14457
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: SPI has delays and quirky line behaviour

Postby Giovanni » Thu Apr 17, 2014 1:01 pm

You don't need to start/stop for each transfer. Starting and stopping is a very heavy operation because it configures the DMAs, clocks and the SPI itself, you should just start the driver then use select-send/receive/exchange-unselect.

Giovanni

goeck
Posts: 92
Joined: Mon Feb 11, 2013 12:00 pm
Location: Germany

Re: SPI has delays and quirky line behaviour

Postby goeck » Thu Apr 17, 2014 1:08 pm

Hey Giovanni,

I also want to use I2C in the project... As far as I read, I have to start/stop each DMA demanding service for each usage, so they don't interfere with each other and do fights over hardware usage.

User avatar
Giovanni
Site Admin
Posts: 14457
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: SPI has delays and quirky line behaviour

Postby Giovanni » Thu Apr 17, 2014 3:54 pm

I don't see other solution except using non-conflicting peripherals. Can you change ports?

Giovanni

goeck
Posts: 92
Joined: Mon Feb 11, 2013 12:00 pm
Location: Germany

Re: SPI has delays and quirky line behaviour

Postby goeck » Tue Apr 22, 2014 9:08 am

Hey,

I just figured out, I could use polled exchange (for testing purposes at least), since it's implemented in the LLD.
See what I've got with that portion of code:

Code: Select all

uint8_t dSPIN_Write_Byte(uint8_t byte)
{
   static uint8_t spiBufferTx[1] = { 0 };
   static uint8_t spiBufferRx[1] = { 0 };
   spiBufferTx[0] = byte;

   dSPIN_Acquire_Bus();
//   spiExchange(&SPID1, 1, spiBufferTx, spiBufferRx);
   spiBufferRx[0] = spi_lld_polled_exchange(&SPID1, byte);
   dSPIN_Release_Bus();

   return spiBufferRx[0];
}

Whole transmission takes 25us.
Conclusion would be, exactly the comment of spi_lld_polled_exchange(): laying calling thread asleep and awaking it after spiExchange has finished is too expensive when doing single byte transfers?

Cheers
Attachments
screenshot.png
Saleae screenshot using polled SPI exchange
screenshot.png (84.08 KiB) Viewed 4977 times

User avatar
Giovanni
Site Admin
Posts: 14457
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: SPI has delays and quirky line behaviour

Postby Giovanni » Tue Apr 22, 2014 9:42 am

Hi,

That is the reason for the spiPolledExchange(), it is convenient for exchanging single bytes at high speeds.

Giovanni

goeck
Posts: 92
Joined: Mon Feb 11, 2013 12:00 pm
Location: Germany

Re: SPI has delays and quirky line behaviour

Postby goeck » Wed Apr 23, 2014 2:52 pm

Ah, nice.
I just read the Programming Manual, Reference Manual and Datasheet of the STM32 and found something that saved my day.
There is a SPI feature called NSS Pulse, which actually exactly does what I want. After each byte in a consecutive byte sending, a toggle is executed on the NSS pin, one has to use hardware SlaveSelect though. In my case I either way already used the corect pin (SPI1: PA4). So in my SPI init routine i did not init the CS port/pin as output_push_pull, but as well as all other SPI pins as alternate function 0.
See what I've got: transmission time down to 13us :-)

Here's the relevant code:

Code: Select all

/**
 * SPI1 configuration structure.
 * CPHA=0, CPOL=0, 8bits frames, MSb transmitted first.
 * NSS Pulse mode (due to SPI @ L6470)
 */
static SPIConfig dspin_spi_config = {
//   spiSingleByteDone,
   NULL,
   /* HW dependent part.*/
   DSPIN_CS_PORT,
   DSPIN_CS_PIN,
   SPI_CR1_BR_1 | SPI_CR1_BR_0,   // Speed selection:  f_PCLK / 16
   SPI_CR2_NSSP               
};

/**
 * Initialise and start SPI hardware.
 */
void initSPI(void){
   palSetPadMode(   SPI_MISO_PORT, SPI_MISO_PIN,
               PAL_MODE_ALTERNATE(0) | PAL_STM32_OSPEED_HIGHEST);
   palSetPadMode(   SPI_MOSI_PORT, SPI_MOSI_PIN,
               PAL_MODE_ALTERNATE(0) | PAL_STM32_OSPEED_HIGHEST);
   palSetPadMode(   SPI_SCK_PORT,  SPI_SCK_PIN,
               PAL_MODE_ALTERNATE(0) | PAL_STM32_OSPEED_HIGHEST);

   // Use hardware NSS pin (software usage would lead to much
   palSetPadMode(   DSPIN_CS_PORT,   DSPIN_CS_PIN,
               PAL_MODE_ALTERNATE(0) | PAL_STM32_OSPEED_HIGHEST);
   palSetPad(      DSPIN_CS_PORT, DSPIN_CS_PIN);

   spiStart(&SPID1, &dspin_spi_config);
}

int main(void){
    ...

   uint8_t tx[4],rx[4];
   tx[0] = dSPIN_Command_RUN | direction;
   tx[1] = (uint8_t)(speed >> 16);
   tx[2] = (uint8_t)(speed >> 8);
   tx[3] = (uint8_t)(speed);

   spiExchange(&SPID1, 4, tx, rx);


Thanks for the thoughts, Giovanni.
Cheers
Stefan
Attachments
screenshot.png
Saleae screenshot with NSS pulse enabled
screenshot.png (70.01 KiB) Viewed 4958 times

User avatar
Giovanni
Site Admin
Posts: 14457
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: SPI has delays and quirky line behaviour

Postby Giovanni » Wed Apr 23, 2014 3:38 pm

Interesting solution, I never tested that mode directly on the STM32.

Giovanni


Return to “STM32 Support”

Who is online

Users browsing this forum: No registered users and 55 guests