2020-03-05 07:29 AM
Hello,
I'm trying to get a SPI communication in between two STM32 running with DMA. One is the STM32F051R8T7 (slave), the other ist the STM32F412ZET7 (master). There is nothing else on this SPI-bus. The best would be, if it runs with hardware controlled NSS. I'm facing various problems here and already tried a lot.
The basic problem I'm facing is, that I want to send multiple "messages" via SPI. A message should be any amount of bytes that are filled into one tx-Buffer and then send via SPI by the DMA. After one message, the data in the tx buffer will get modified and send again and so on.
My code is based on the examples of CubeMX, e.g. STM32F072RB-Nucleo\Examples_LL\SPI\SPI_TwoBoards_FullDuplex_DMA. It is working somehow, but I have some independend issues, depending on which way I go from here:
Best regards,
Christian
2020-03-05 01:23 PM
1. Yes this is the behaviour of NSS, hinted but not quite explained by the manual. Reenable SPI immediately after disable, or simply set NSS as GPIO Out and control it manually.
2. I don't understand what's the problem but maybe that's because I don't use Cube. Simply set up SPI, Rx DMA, then Tx DMA (including enabling) - that's enough for slave to start listening and for master to start the communication.
JW
2020-03-05 11:27 PM
Thank you for your answer.
1) It would be ok for me and all applications, that the NSS-signal is pushed to a high-level, when you disable the SPI function block. But the signal is not actively pushed to a high level, like I would expect from the push-pull-output, as you can see in the image of the scope. Reenabling the SPI immediatelly after disabling it will not cause a valid edge. This is what you can see in the image. And because this does not generates a valid edge/pulse, you cannot use it at all because it will always be luck whether or not the slave will actually interpret the NSS-signal as valid high-level.
2) As I already wrote, I can send data. But what I'm missing is a solid or official way, to initiate the sending of new data again and again manually. Currently I'm just diabling the RX and TX DMA Streams with LL_DMA_DisableStream() after the according interrupt occured. Then I'm updating and processing the data. After that, I'm enabling the RX and TX DMA Streams with LL_DMA_EnableStream() again and this causes the new data to be send. This is working, but the question is if this is the intended usage of if this might cause any troubles?
2020-03-06 12:26 AM
>Reenabling the SPI immediatelly after disabling it will not cause a valid edge.
Did you actually try? If you are concerned about voltage rise during the fraction of us this process should take, use pulldown instead of pullup. But I'd just leave the pin floating, held low by any parasitic capacitance present.
> if this is the intended usage of if this
The intended usage of DMA is, that you set it up and enable and it starts transferring when triggered. The SPI Tx triggers DMA by copy of the signal you can see as TXE bit in status register.
JW
2020-03-06 01:07 AM
> Did you actually try?
Please have a look at the image in my first post. The yellow curve is the NSS signal. The command LL_SPI_Disable() has been called a bit to the left of the middle of the screen (where CLK in cyan ends). The command LL_SPI_Enable() was called immediatelly after that! As you can see, this is no edge as you would expect it... Oh and a pull-up (as already written in the first post) does not fix this problem! It will make the slope a bit steeper, but still not as you would expect it...
> The intended usage of DMA is, that you set it up and enable and it starts transferring when triggered. The SPI Tx triggers DMA by copy of the signal you can see as TXE bit in status register.
Could you please clarify this a bit more? What I'm doing is basically this:
__LL_SPI_NSS_HIGH();
LL_SPI_EnableDMAReq_RX();
LL_SPI_EnableDMAReq_TX();
LL_DMA_ConfigAddresses(); // for RX and TX
LL_DMA_SetDataLength(); // for RX and TX
LL_DMA_EnableIT_TC(); // for RX and TX
LL_DMA_EnableStream(); // for RX and TX
__LL_SPI_NSS_LOW();
LL_SPI_Enable(SPI5); // this will start the sending of data
// in the DMA interrupt, for each RX and TX
LL_DMA_ClearFlag_TCx();
LL_DMA_DisableStream();
__LL_SPI_NSS_HIGH();
// after that, I start the next transmission with theses commands
__LL_SPI_NSS_LOW();
LL_DMA_EnableStream(); // for RX and TX ------> IS THIS THE RIGHT WAY TO INITIATE THE SENDING AGAIN?
2020-03-20 12:07 AM
According to the answer of ST to this topic (which is none ;) ), I assume that this behaviour is well known and will not be changed in the future, not to say "will be ignored"...
2020-03-20 02:42 AM
This forum is not the official support channel of ST, but a courtesy to their users, providing a platform to help each other and share ideas. ST employees visit here apparently when they have nothing better to do. Like the rest of us.
Back your actual problem, I would just configure the NSS pin as push-pull GPIO output, and toggle the pin directly instead of playing with SPE.
2020-03-20 04:30 AM
> Back your actual problem, I would just configure the NSS pin as push-pull GPIO output, and toggle the pin directly instead of playing with SPE.
Sorry for the previous confusion - I was under the false impression that NSS is high after SPE is enabled and goes down only with the first transmission.
(To be honest, it never occured to me to even try to use the NSS in this way, ever since I've read the description in the RM, which was clear enough to me to understand that it's unusable for most practical cases. I came to that above incorrect conclusion entirely based on the complaints I've read here over the years... mea culpa)
JW
2020-04-14 11:25 PM
> Back your actual problem, I would just configure the NSS pin as push-pull GPIO output, and toggle the pin directly instead of playing with SPE.
Well, that's what I actually did. But if you have always to do this in this way, why is the hardware NSS-mode implemented anyway?
2020-04-14 11:40 PM
The idea - also described in the RM, mind you - is, that in multimaster setting, you wire-OR all NSS togeter, leaving all parties as slaves. Should one of them turn to master, it would pull the line down, generating a frame for the others; after transmission it would then turn back to slave again.
I don't say it's a terribly useful scheme - neither is the per-frame "NSS pulsing" implemented in later incarnations of this module - but the SPI in STM32 are traditionally plagued with half-baked ideas (limited baudrate choice, data packing, hanging busy, incorrectly handled first bit in slave, clock fed back from actual pin in master (leading to erratum), and possibly more)
JW