Author Topic: Help with STM32 SPI slave and variable lenght  (Read 6421 times)

0 Members and 1 Guest are viewing this topic.

Offline dmendesfTopic starter

  • Frequent Contributor
  • **
  • Posts: 320
  • Country: br
Help with STM32 SPI slave and variable lenght
« on: July 16, 2021, 07:44:10 pm »
I'm doing a STM32 SPI slave with DMA and hardware NSS. I want to be able to read an arbitrary lenght of data. When the SPI transfer size and the DMA size matches all goes well. Example I have a buffer:

Code: [Select]
  uint8_t data[16] = { 1,2,3,4,5,6,7,8,9,10,11,12,13, 14, 15, 16};
If I keep calling:
Code: [Select]
        HAL_SPI_Transmit_DMA(&hspi2, data, 13);

and try to read exactly 13 bytes for SPI transfer all goes well... I receive  1,2,3,4,5,6,7,8,9,10,11,12,13.

But If I call
Code: [Select]
        HAL_SPI_Transmit_DMA(&hspi2, data, 16);
and read 13 bytes then I get scrooling data (1..13 in first transfer, then 14, 15, 16,1,2,... in the next and so on).
So I tried to restart the DMA after NSS goes up by calling:
Code: [Select]
            HAL_DMA_Abort(&hdma_spi2_tx);
            HAL_SPI_DMAStop(&hspi2);
then I get 13,1,2,3,4,5,6,7,8,9,10,11,12 in all transfers. Seems a last byte got stuck in the shift register. Any ideas about how to solve it?



 

Online DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5907
  • Country: es
Re: Help with STM32 SPI slave and variable lenght
« Reply #1 on: July 16, 2021, 11:53:15 pm »
This is your slave?
HAL_SPI_Transmit_DMA(&hspi2, data, 16);


What about your master? Sounds like you are using also DMA for receiving, but not setting 16 bytes in the transfer length.
So your master sends clock for 13 bytes, the slave is still waiting for more, and in the next transfer you get the remaining.

Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline dmendesfTopic starter

  • Frequent Contributor
  • **
  • Posts: 320
  • Country: br
Re: Help with STM32 SPI slave and variable lenght
« Reply #2 on: July 17, 2021, 01:18:15 am »
Yes, that's the idea. I want the option of reading just the first 13 bytes OR reading more (like 1k bytes). The slave will cope with both options on demand... It just needs to keep sending data while the master asks, but when CS is deasserted I need that the next transaction starts again from byte 0 and that's where I'm failing. Any hints?
 

Online MasterT

  • Frequent Contributor
  • **
  • Posts: 785
  • Country: ca
Re: Help with STM32 SPI slave and variable lenght
« Reply #3 on: July 17, 2021, 03:47:06 am »
I read somewhere on st.com that
HAL_StatusTypeDef HAL_SPIEx_FlushRxFifo(SPI_HandleTypeDef *hspi);
may help, though I didn't tested it yet.
 

Online DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5907
  • Country: es
Re: Help with STM32 SPI slave and variable lenght
« Reply #4 on: July 17, 2021, 04:37:19 am »
I had serious issues in slave spi if any clock was lost.
Nothing would reset the spi module.
Until I found __HAL_RCC_SPIx_FORCE_RESET()
Where x is your spi module.
You'll need to completely initialize spi after that, calling MX spi init, etc...
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 
The following users thanked this post: dmendesf

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: Help with STM32 SPI slave and variable lenght
« Reply #5 on: July 17, 2021, 06:18:42 am »
Every STM32 SPI peripheral is different, we would need to know the exact part number to give specific advice.

This being said, I have written variable-length SPI communication (using DMA, of course) for a few, including an older F7 and a newer H7, and can say for quite high certainty that variable-length slave DMA SPI is impossible, this isn't even a HAL limitation, but a hardware limitation.

The only workaround really is to register an EXTI interrupt for the nCS pin, and in that handler, completely reset the SPI peripheral. In the newest H7, this was possible by disabling the SPI from the SPI peripheral control register itself; in the earlier F7, it required a reset through the RCC reset register! (Looking back at my code, even the new H7 requires reset through RCC in some cases, such as if CRC is turned on. Because the SPI peripherals are full of silicon bugs and they maybe fix one per revision, it's best to always just reset the whole thing through RCC.)

Luckily, such total peripheral reset, even when it sounds radical, is not an expensive operation, but I'm not sure this is easy, efficient, or even possible using the HAL because now the total peripheral init becomes a part of your interrupt handler so every clock cycle matters and you can't afford any bloat.
« Last Edit: July 17, 2021, 06:21:53 am by Siwastaja »
 
The following users thanked this post: Kleinstein

Online Kjelt

  • Super Contributor
  • ***
  • Posts: 6460
  • Country: nl
Re: Help with STM32 SPI slave and variable lenght
« Reply #6 on: July 17, 2021, 07:19:43 am »
Just a thought, if you want variable length transfers than you need to address this in your protocol.
Eg first sent a fixed length header, which contains for instance the  command but also the lenghth of the next datapacket perhaps CRC etc and next use that info to receive that datapacket.
OR
just receive packets of 1 byte, not very optimal for dma transfer  :P
OR
Make a ring buffer large enough to receive the largest packets you will transfer, eg packetsize limitation, and fix the packagesize to fixed sizes.
 

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: Help with STM32 SPI slave and variable lenght
« Reply #7 on: July 17, 2021, 07:23:53 am »
Just a thought, if you want variable length transfers than you need to address this in your protocol.
Eg first sent a fixed length header, which contains for instance the  command but also the lenghth of the next datapacket

No you don't, the whole idea of the SPI is that includes hardware delimiting signal that separates packets. Compare with streams like UART or TCP where such signal is not available, so you indeed need to tell how many bytes of payload follow, and add error handling for cases when the stream can go "out of sync". SPI self-corrects on the next packet because the cycle starts over.

Falling nCS resets the receiver's state machine and sets the byte counter to 0. Then, each received byte increases the counter.

It's a miracle how such simple scheme is difficult to understand to ST's engineers.

With DMA, the only thing you should need is to guarantee some maximum size for a packet.
« Last Edit: July 17, 2021, 07:26:05 am by Siwastaja »
 
The following users thanked this post: Kjelt

Online Kjelt

  • Super Contributor
  • ***
  • Posts: 6460
  • Country: nl
Re: Help with STM32 SPI slave and variable lenght
« Reply #8 on: July 17, 2021, 07:29:50 am »
I agree but when the hardware does not (always) work like it supposed to, you need to fallback to something that does work.

 

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: Help with STM32 SPI slave and variable lenght
« Reply #9 on: July 17, 2021, 07:37:35 am »
I agree but when the hardware does not (always) work like it supposed to, you need to fallback to something that does work.

Yes, but (almost) every MCU (at least those capable of DMA) should have a working GPIO where the nCS pin can be configured to generate just a regular rising edge (or level change) interrupt. This way, you can reset the SPI and DMA manually with a few wasted clock cycles. The benefit is added robustness because a single missed clock doesn't break the whole system until power-down.
 

Offline dmendesfTopic starter

  • Frequent Contributor
  • **
  • Posts: 320
  • Country: br
Re: Help with STM32 SPI slave and variable lenght
« Reply #10 on: July 17, 2021, 01:32:01 pm »
That's my idea. Will try using the functions suggested on Monday.
 

Online MasterT

  • Frequent Contributor
  • **
  • Posts: 785
  • Country: ca
Re: Help with STM32 SPI slave and variable lenght
« Reply #11 on: July 17, 2021, 02:17:46 pm »
 TI_mode is better option than Motorola, tried on F4/F7/H7 SPI-slave. Issue is it requires +1 clock pulse, 33 with 32-bits data frame.
 

Offline dmendesfTopic starter

  • Frequent Contributor
  • **
  • Posts: 320
  • Country: br
Re: Help with STM32 SPI slave and variable lenght
« Reply #12 on: July 17, 2021, 06:34:55 pm »
I'm using a stm32f407 both as master and slave. I'm checking the results with a logic analyzer to be sure if the problems are in the master or slave side. For now I'm just dealing with the slave.
 

Online DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5907
  • Country: es
Re: Help with STM32 SPI slave and variable lenght
« Reply #13 on: July 17, 2021, 11:14:59 pm »
The nCS pin causes a lot of troubles, and the spi module doesn't reset properly by just disabling/enabling it.
Just try the HAL RCC Reset. It's a life saver.
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: Help with STM32 SPI slave and variable lenght
« Reply #14 on: July 18, 2021, 07:04:51 am »
The nCS pin causes a lot of troubles

The nCS pin, in itself, is the best thing since sliced bread.

I think what you mean is: STM32 SPI peripheral does not implement a working hardware nCS management mode despite bragging about it in the manual. This is indeed true. RCC reset being indeed needed to operate the device is a disgrace, as is the total inability of the ST engineers getting the SPI peripheral fixed, they have had years and years and it's still broken in every new device, year after year.
 

Offline dmendesfTopic starter

  • Frequent Contributor
  • **
  • Posts: 320
  • Country: br
Re: Help with STM32 SPI slave and variable lenght
« Reply #15 on: July 19, 2021, 01:40:04 pm »
I read somewhere on st.com that
HAL_StatusTypeDef HAL_SPIEx_FlushRxFifo(SPI_HandleTypeDef *hspi);
may help, though I didn't tested it yet.

Seems the STM32F4 has no such function, but thanks for your help.
 

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: Help with STM32 SPI slave and variable lenght
« Reply #16 on: July 19, 2021, 02:11:20 pm »
FIFO flushing function likely just does read operations of the data register until FIFO is empty, I'd guess.

If you require FIFO "flushing" that's a sign that you are not doing correct amount of reads of the FIFO. SPI is highly synchronous in nature so if your program logic is correct, FIFO should not accumulate anything "in excess".

OTOH, if the SPI peripheral "breaks down" / gets stuck like it does in certain cases on ST controllers, then just flushing the FIFO is rarely helpful, you need actual peripheral reset, in a lucky case through disabling and enabling SPI on its own CR, but usually through RCC is most effective.
 

Offline dmendesfTopic starter

  • Frequent Contributor
  • **
  • Posts: 320
  • Country: br
Re: Help with STM32 SPI slave and variable lenght
« Reply #17 on: July 19, 2021, 05:14:18 pm »
It's a variable lenght reading function, so it's acceptable that the DMA engine will read the next byte from the buffer and get stopped before SPI accepts the data (because the master ended the transaction). I did several tests and i'm 99% sure that the byte is stuck in the DMA but I don't know how to flush it. Calling

Code: [Select]
HAL_SPI_DMAStop(&hspi2);
to stop a transaction and then
Code: [Select]
HAL_SPI_Transmit_DMA(&hspi2, data, 13);

Makes the last unsent byte from the terminated transaction to go as the first byte in the next transaction. Any idea about how to flush a DMA?
 

Offline dmendesfTopic starter

  • Frequent Contributor
  • **
  • Posts: 320
  • Country: br
Re: Help with STM32 SPI slave and variable lenght
« Reply #18 on: July 19, 2021, 06:00:32 pm »
Ok, got it working. Earlier in the day I tried all the sugestions left in the forum and some ideas I had in the weekend. After exausting all options I revisited the
 
Code: [Select]
__HAL_RCC_SPIx_FORCE_RESET()
I tried it alone before and it completely stopped the SPI. I read more about it and found that after calling it you must call
Code: [Select]
__HAL_RCC_SPI2_RELEASE_RESET();
To enable the SPI again. Man, i felt like I hit the chip with a hammer, but surelly it worked  :-DD Thanks you all.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14472
  • Country: fr
Re: Help with STM32 SPI slave and variable lenght
« Reply #19 on: July 19, 2021, 06:12:47 pm »
I haven't used SPI in slave mode on STM32's so far, but having to reset the peripheral looks horrible to me. Does that affect all STM32 MCUs? A particular series? Or a particular model?
Also, do you need to reset it after each transaction? Or what is the condition?
 

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: Help with STM32 SPI slave and variable lenght
« Reply #20 on: July 19, 2021, 07:31:42 pm »
I haven't used SPI in slave mode on STM32's so far, but having to reset the peripheral looks horrible to me. Does that affect all STM32 MCUs? A particular series? Or a particular model?
Also, do you need to reset it after each transaction? Or what is the condition?

After each transaction (or "packet" delimited by nCS), i.e., when nCS goes to deactive state.

Obviously, if you just read bytes and don't use DMA, nothing of this matters, there is no need to reset anything; just get a  FIFO not empty interrupt and read out there.

DMA with nCS hardware management theoretically "just works" without resetting if
* All transactions are of the correct predetermined length,
* Clock skipping never occurs, nor does excess clock from EMI,
* You catch the very first communication correctly from the start

So even with fixed-length messaging, it isn't robust.

Affects at least F7 and H7 series but likely most of the older MCUs as well. When I migrated code from F7 to an even newer H7, I noticed they tried to fix the thing but failed. In any case, in a very basic case I was able to reset the SPI without RCC, but that broke down when I enabled CRC mode so clearly it's still best to reset with RCC reset register.

It isn't that bad in practice, just reset it, won't take too many clock cycles. But indeed it tells a story about ST's struggles making such simple thing work.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14472
  • Country: fr
Re: Help with STM32 SPI slave and variable lenght
« Reply #21 on: July 19, 2021, 07:39:10 pm »
OK I see. Well, to be honest, I've found the handling of the CS line in implementations of SPI (either master or slave, for different reasons) either lacking or just plain buggy on many different MCUs.
Not that it makes things better, but ST is not doing much worse than others here...
 

Offline dmendesfTopic starter

  • Frequent Contributor
  • **
  • Posts: 320
  • Country: br
Re: Help with STM32 SPI slave and variable lenght
« Reply #22 on: July 20, 2021, 12:37:23 am »
Your description matches exactly what I found out. Exact DMA size = OK, all other cases = FAIL without Reset.

I haven't used SPI in slave mode on STM32's so far, but having to reset the peripheral looks horrible to me. Does that affect all STM32 MCUs? A particular series? Or a particular model?
Also, do you need to reset it after each transaction? Or what is the condition?

After each transaction (or "packet" delimited by nCS), i.e., when nCS goes to deactive state.

Obviously, if you just read bytes and don't use DMA, nothing of this matters, there is no need to reset anything; just get a  FIFO not empty interrupt and read out there.

DMA with nCS hardware management theoretically "just works" without resetting if
* All transactions are of the correct predetermined length,
* Clock skipping never occurs, nor does excess clock from EMI,
* You catch the very first communication correctly from the start

So even with fixed-length messaging, it isn't robust.

Affects at least F7 and H7 series but likely most of the older MCUs as well. When I migrated code from F7 to an even newer H7, I noticed they tried to fix the thing but failed. In any case, in a very basic case I was able to reset the SPI without RCC, but that broke down when I enabled CRC mode so clearly it's still best to reset with RCC reset register.

It isn't that bad in practice, just reset it, won't take too many clock cycles. But indeed it tells a story about ST's struggles making such simple thing work.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf