Author Topic: STM32 - using SPI with circular DMA  (Read 17660 times)

0 Members and 1 Guest are viewing this topic.

Offline ebastlerTopic starter

  • Super Contributor
  • ***
  • Posts: 6375
  • Country: de
STM32 - using SPI with circular DMA
« on: April 18, 2021, 07:23:49 am »
I would like to use an STM32F303 to receive a stream of synchronous serial data from an existing device. The source device provides

- a 5 MHz clock which is always active,
- a gating signal which periodically goes high, indicating a burst of valid data (burst length is always constant), and
- a binary data stream, which is valid/relevant during the gating signal.

So I thought I'd set up a "slave, RX only" SPI channel, with its hardware NSS input connected to my gating signal. Then configure circular DMA for this SPI channel, with a buffer length which equals the length of the data burst. I would like to only need to set this up once and then keep it running, without any interrupts or need to re-start SPI reception.

(The software does not need to know the exact point in time when a reception cycle is completed. It can simply assume that the DMA memory buffer contains the most recently received data burst at any time. Reading the data buffer in the middle of a new burst reception is also OK.)

First question: Can this work as sketched out above, or am I overlooking/misunderstanding anything?

My second question refers to the proper DMA configuration. I am using the latest CubeIDE version (1.6.1) with the graphical device configuration tool. Have configured SPI1 as sketched out above, assigned the SPI1_RX DMA request to DMA1, channel 2, and asked for a circular buffer with auto-incremented memory address. I have the code generation set up to use HAL drivers.

The generated initialization code for the DMA is shown below. It sets up an interrupt which I don't need (and can probably simply remove, assuming my general concept above makes sense). But where does it set up the DMA for circular buffer operation, and what else needs to be done to actually enable the DMA? It seems strange that information the graphical config tool asks for seems to go unused (circular buffer, auto-increment step size). Should more code be generated automatically?

Or, if I need to add this manually: How exactly? HAL_SPI_Receive_DMA(spiHandle, spiBuffer, SPI_BUFFER_SIZE) is probably what I want -- but where do I specifiy the circular buffer (and hence automated, continuous operation)? Some other call(s) must be required to set up the DMA?

Thanks for reading through a long post, and thanks for any helpful hints!

Code: [Select]
static void MX_DMA_Init(void)
{
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Channel2_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}
 


Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8166
  • Country: fi
Re: STM32 - using SPI with circular DMA
« Reply #2 on: April 18, 2021, 08:43:53 am »
Your approach sounds right at the first glance. The problem seemingly is libraries and autogeneration which claim to make things easier but apparently makes everything harder because without them, you'd have tested this out in less time than it took to write the forum post.

So open up the reference manual. As for DMA, assuming the F303 has the same DMA engine as the F3, F4, F7, H7 MCUs I have worked with (F0 devices have a different, even simpler DMA), there is not much to do to configure it: set M0AR, PAR, NDTR, CR, clear interrupt flags through LIFCR, and enable the channel through CR.

Code: [Select]
DMA2_Stream1->M0AR = (uint32_t)&databuf[0];
DMA2_Stream1->PAR = (uint32_t)&SPIwhatever->RXDR;
DMA2_Stream1->NDTR = 1234;
DMA2_Stream1->CR = 0UL<<25 /* the channel number, see the table in refman*/ |
0b01UL<<16 /*med prio*/ | 0b01UL<<13 /*16-bit mem*/ | 0b01UL<<11 /*16-bit periph*/ |
1UL<<10 /*mem increment*/ | 0b00UL<<6 /*periph-to-mem*/ | 0b110 /*err interrupts*/ | 1UL<<8 /*circular*/;
DMA_CLEAR_INTFLAGS(DMA2, 1);
DMA2_Stream1->CR |= 1UL; // enable it!

where DMA_CLEAR_INTFLAGS() is a helper I created once:
Code: [Select]
#define DMA_CLEAR_INTFLAGS(_dma_, _stream_) do{                   \
if     ((_stream_) == 0) (_dma_)->LIFCR = 0b111101UL<<0;  \
else if((_stream_) == 1) (_dma_)->LIFCR = 0b111101UL<<6;  \
else if((_stream_) == 2) (_dma_)->LIFCR = 0b111101UL<<16; \
else if((_stream_) == 3) (_dma_)->LIFCR = 0b111101UL<<22; \
else if((_stream_) == 4) (_dma_)->HIFCR = 0b111101UL<<0;  \
else if((_stream_) == 5) (_dma_)->HIFCR = 0b111101UL<<6;  \
else if((_stream_) == 6) (_dma_)->HIFCR = 0b111101UL<<16; \
else if((_stream_) == 7) (_dma_)->HIFCR = 0b111101UL<<22; \
}while(0)

Don't forget to
* Enable clock to DMA
* Enable clock to SPI
* Set SPI pins in Alternative Function mode with the right AF number
* Look up the correct DMA channel number for DMA CR register, to map the right SPI to the DMA
* Enable the DMA mode bit in the peripheral (in this case, SPI) config

As for SPI, most STM32 devices are still broken beyond laughable in how they handle hardware nCS. But if you have truly constant length communication and are not expecting any communication errors like a missed clock, it will work. For variable-length messaging (or a robust system), to make the rising nCS reset the SPI state machine, which is the basics of the basics, you need to write an interrupt handler triggered by rising nCS through EXTI, then on that handler, reset the whole SPI peripheral through the RCC reset register! On the newest STM32 models, they have semi-fixed this issue so that you can now reset the SPI by using the peripheral's own enable bit, still a long way to go to do it right.

Finally, STM32F303 has SPI FIFOs. It may be worth considering not using DMA, especially if your communication packet is short enough to fit in SPI FIFOs completely. In this case, you can enable the SPI peripheral in nCS falling ISR, and read out everything in 32-bit bus reads in nCS rising ISR; especially if you would process the data anyway after full reception. Though, in your pattern, make the SPI automagically update memory region with no sync/atomicity concerns, this would be extra overhead.
 
The following users thanked this post: ebastler

Offline ebastlerTopic starter

  • Super Contributor
  • ***
  • Posts: 6375
  • Country: de
Re: STM32 - using SPI with circular DMA
« Reply #3 on: April 18, 2021, 08:45:29 am »
Thank you! My data packets are 16 words @ 20 bits, which I intend to read as 20 words @ 16 bits, so not a power of two from the STM32's perspective. But that thread confirms that my general idea for an "autonomous" reception via DMA and circular buffer should work.

I just found the solution to the "mystery of the missing initialization code", I believe: There is an automatically generated file stm32f3xx_hal_msp.c which seems to have all the DMA initialization code (and more). Hadn't noticed that at all; duh...

I still need to figure out whether and when all of it is called automatically, or what I still need to add in my user code. Will need to wait a couple of days -- I managed to kill my ST-Link clone yesterday by shorting something out on the target. So it's gardening today instead of microcontrollers. ;-)
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8166
  • Country: fi
Re: STM32 - using SPI with circular DMA
« Reply #4 on: April 18, 2021, 08:48:08 am »
Note that DMA initialization code is so simple and small that you should really do it Just-In-Time, where needed, IMHO. It also takes just a few clock cycles so you can easily "initialize" DMA in interrupts, or whatever you need.

Limiting yourself to initialize DMA once in a big "MCU initialization" step is really limiting.
 
The following users thanked this post: ebastler

Offline ebastlerTopic starter

  • Super Contributor
  • ***
  • Posts: 6375
  • Country: de
Re: STM32 - using SPI with circular DMA
« Reply #5 on: April 18, 2021, 09:35:07 am »
Thanks, Siwastaja!

Agree, it would be more robust to re-initialize a DMA transfer for a 16*20 bit packet via an ISR every time the gate signal goes high. I am torn between the "auto-magical" background approach and the increased robustness of re-syncing on every transfer cycle...

The source is a hard-wired (TTL), scaled-down model of Turing's Pilot ACE computer, by the way. The ACE design fully relies on never missing a beat while the serial data stream is cycling through its delay line memories: All addressing is relative to the prior instruction time, and all delay lines need to stay in sync at all times. So I can trust the source to stay in sync and send constant-length data packets. As long as the STM32 SPI does not miss a beat either, the auto-magical approach should be fine.  ;)
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5890
  • Country: es
Re: STM32 - using SPI with circular DMA
« Reply #6 on: April 18, 2021, 11:36:51 am »
HAL_SPI_Receive_DMA(spiHandle, spiBuffer, SPI_BUFFER_SIZE)
Does everything for you. Enables the DMA, sets spiBuffer address and SPI_BUFFER_SIZE.
Easy as that.
« Last Edit: April 18, 2021, 11:39:22 am by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 
The following users thanked this post: ebastler

Offline ebastlerTopic starter

  • Super Contributor
  • ***
  • Posts: 6375
  • Country: de
Re: STM32 - using SPI with circular DMA
« Reply #7 on: April 18, 2021, 11:46:27 am »
HAL_SPI_Receive_DMA(spiHandle, spiBuffer, SPI_BUFFER_SIZE)
Does everything for you. Enables the DMA, sets spiBuffer address and SPI_BUFFER_SIZE.
Easy as that.

Thanks! As mentioned in my second post, I feel better about it now that I found the "missing" initialization code in stm32f3xx_hal_msp.c. See below -- that's all the stuff I "told" the graphical configuration tool and couldn't find anywhere in the generated code.

With those details being included in the initialization code, I can see how HAL_SPI_Receive_DMA can do its thing...  :-+

Code: [Select]

void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
[...]
   /* SPI1 DMA Init */
    /* SPI1_RX Init */
    hdma_spi1_rx.Instance = DMA1_Channel2;
    hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_spi1_rx.Init.Mode = DMA_CIRCULAR;
    hdma_spi1_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
    if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
    {
      Error_Handler();
    }
 

Offline ebastlerTopic starter

  • Super Contributor
  • ***
  • Posts: 6375
  • Country: de
Re: STM32 - using SPI with circular DMA
« Reply #8 on: April 21, 2021, 05:32:17 am »
I am "back in business" now, with a working ST-Link V2 dongle -- but can't seem to get this SPI reception via circular DMA to work.  :(

The goal is to let the µC continuously receive bursts of sixteen 20-bit words via SPI and put them into a memory buffer via DMA. The duration of a burst is indicated by an external select signal which goes low periodically. Here's what I set up in CubeMX:
  • SPI1 is a receive-only slave, hardware NSS, data size 10 bits.
  • SPI1_RX DMA is enabled: circular mode, auto-increment the memory address by half-words.
  • SPI and DMA interrupts are disabled.
  • Beyond the automatically generated code, I start the DMA via HAL_SPI_Receive_DMA (&hspi1, DMA_buf, sizeof(DMA_buf) in my main.c. The main loop then periodically displays the content of the DMA_buf on an attached display.
What I get is the following: After startup, the first byte of the reception buffer is changed once. The byte that gets written there does somehow depend on the MOSI data I feed in, although it is not what I expect. If the SPI clock and NSS signal are not present at startup, the buffer change will only happen once I switch those signals on. (They come from an external function generator for testing.)

But afterwards nothing else changes. No further byte in the buffer is ever affected, and the first byte does not change any further if I change the MOSI data and/or turn the SPI clock and NSS off and back on. It looks like the SPI interface or the DMA have turned themselves off or locked up in some way.

Can there be some error condition (framing?) causing this? I don't need to re-enable anything periodically in an interrupt handler, right? And should hence be OK to keep the SPI and DMA interrupts disabled? What else could I be overlooking?

I am stumped... Many thanks for your ideas!
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8166
  • Country: fi
Re: STM32 - using SPI with circular DMA
« Reply #9 on: April 21, 2021, 08:40:06 am »
The usual:

Reduce the problem to minimal code reproducing the problem, then post it here.

Obviously this is impossible because the Cube autogeneration bloats the 10 lines of actual code into 100 or who knows how much it is, possibly 1000 total. No one can look at it, so we are back at guessing.

Remove, remove, remove until you have the minimum case. Basically you are writing 2-3 registers in SPI peripheral and 4-6 in DMA. SPI peripheral have a few options one could call "trap bits" like when you don't use hardware nCS (as you often don't because it doesn't work) you need to know to set "SSI" bit to 1 otherwise the SPI peripheral turns itself off automatically making it pretty useless because they thought some weird-ass never-seen "multi-master SPI" is the default configuration and it's normal to "lose arbitration" in SPI, go figure. When we don't know your actual register configuration, it's hard to see where the problem might be.
« Last Edit: April 21, 2021, 08:43:43 am by Siwastaja »
 

Offline tru

  • Regular Contributor
  • *
  • Posts: 107
  • Country: gb
Re: STM32 - using SPI with circular DMA
« Reply #10 on: April 21, 2021, 09:26:26 am »
Not sure if this helps.

I'm using CubeIDE v1.5.0 and I'm pretty sure that in the CubeMX (device config tool), under the "Parameter Settings" tab for a SPI, there is only 8 bits and 16 bits option for SPI data size.
How were you able to set 10bits for data size?

I think the HAL library only supports 8 and 16bits anyway.
« Last Edit: April 21, 2021, 09:28:40 am by tru »
 

Offline ebastlerTopic starter

  • Super Contributor
  • ***
  • Posts: 6375
  • Country: de
Re: STM32 - using SPI with circular DMA
« Reply #11 on: April 21, 2021, 09:33:00 am »
I'm using CubeIDE v1.5.0 and I'm pretty sure that in the CubeMX (device config tool), under the "Parameter Settings" tab for a SPI, there is only 8 bits and 16 bits option for SPI data size.
How were you able to set 10bits for data size?

I think the HAL library only supports 8 and 16bits anyway, so for your 16 x 20-bit packets, perhaps set the SPI to 8-bits data size, and use a data buffer of 16 x 3 = 48 bytes.

Thanks for the idea, but I don't think that is the issue. The SPI capabilities of different STM32 chips do differ in that respect. Some support only 8 or 16 bit words, others allow any value between 4..16 bit. The STM32F303 which I use does offer the flexible setting, and CubeMX and the HAL library seem to support that nicely -- the created register settings look plausible.

(Actually I did not trust the odd word length and did try 8 bits yesterday night; didn't help...)
 

Offline ebastlerTopic starter

  • Super Contributor
  • ***
  • Posts: 6375
  • Country: de
Re: STM32 - using SPI with circular DMA
« Reply #12 on: April 21, 2021, 09:38:05 am »
The usual:
Reduce the problem to minimal code reproducing the problem, then post it here.

Obviously this is impossible because the Cube autogeneration bloats the 10 lines of actual code into 100 or who knows how much it is, possibly 1000 total. No one can look at it, so we are back at guessing.

Remove, remove, remove until you have the minimum case. Basically you are writing 2-3 registers in SPI peripheral and 4-6 in DMA.

That would mean starting from scratch without CubeMX, I guess -- which seems like a great way for me to introduce many new errors. ;)  I was hoping to avoid that, but if I don't make progress in another round of staring at the code and the debugger tonight, this would probably be the last resort... 
 

Offline tru

  • Regular Contributor
  • *
  • Posts: 107
  • Country: gb
Re: STM32 - using SPI with circular DMA
« Reply #13 on: April 21, 2021, 09:53:10 am »
Thanks for the idea, but I don't think that is the issue. The SPI capabilities of different STM32 chips do differ in that respect. Some support only 8 or 16 bit words, others allow any value between 4..16 bit. The STM32F303 which I use does offer the flexible setting, and CubeMX and the HAL library seem to support that nicely -- the created register settings look plausible.

(Actually I did not trust the odd word length and did try 8 bits yesterday night; didn't help...)
Ah, I see so other chips do support it, I was wrong, please ignore my comment about HAL support.  I've only used HAL library with DMA set to circular buffer and SPI data size of 16-bits, which does continuously receive after sending a call to the HAL_SPI_Receive_DMA function.  The SPI interrupt is disabled but the global DMA interrupt is enabled (this is locked and I cannot turn it off in CubeMX).  Note, I was not using hardware NSS so can't help in this part.
 
The following users thanked this post: ebastler

Offline ebastlerTopic starter

  • Super Contributor
  • ***
  • Posts: 6375
  • Country: de
Re: STM32 - using SPI with circular DMA
« Reply #14 on: April 21, 2021, 10:05:18 am »
I've only used HAL library with DMA set to circular buffer and SPI data size of 16-bits, which does continuously receive after sending a call to the HAL_SPI_Receive_DMA function.  The SPI interrupt is disabled but the global DMA interrupt is enabled (this is locked and I cannot turn it off in CubeMX).  Note, I was not using hardware NSS so can't help in this part.

Hmm, two more things to try and change, thank you!

DMA interrupts are indeed "forced on" by CubeMX by default. In the NVIC section, you can uncheck the "Force DMA channels interrupt" checkbox near the top of the dialog; then you can activate or deactivate these interrupts individually. I thought I should disable the DMA IRQ since I would not be using it; but maybe that was a bad idea and something useful is happening in a default IRQ handler? I will try reverting to the default tonight. -- Did you provide an IRQ handler in your code?

I had tried to always pull NSS low to avoid an impact from that side, but will try to disable hardware NSS entirely tonight.
 

Offline tru

  • Regular Contributor
  • *
  • Posts: 107
  • Country: gb
Re: STM32 - using SPI with circular DMA
« Reply #15 on: April 21, 2021, 10:51:52 am »
Did you provide an IRQ handler in your code?
No, I didn't add in my own IRQ handler, but added in the HAL predefined callback function to process each SPI data reception:
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef* hspi){
...
}
 
The following users thanked this post: ebastler

Offline aandrew

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: ca
Re: STM32 - using SPI with circular DMA
« Reply #16 on: April 21, 2021, 05:50:10 pm »
Reduce the problem to minimal code reproducing the problem, then post it here.

Obviously this is impossible because the Cube autogeneration bloats the 10 lines of actual code into 100 or who knows how much it is, possibly 1000 total. No one can look at it, so we are back at guessing.

Don't be daft. I'm no fan of Cube or the HAL library either but this isn't rocket science. All they need to do is paste the code that calls Init(), paste MspInit() and paste the loop that calls the HAL_SPI_Receive_DMA() function. If they haven't got callbacks enabled they'll also want to paste their HAL_SPI_RxCpltCallback(). The HAL code doesn't need to be pasted, but knowing WHICH version of the HAL they're using would help.
 

Offline ebastlerTopic starter

  • Super Contributor
  • ***
  • Posts: 6375
  • Country: de
Re: STM32 - using SPI with circular DMA
« Reply #17 on: April 21, 2021, 06:08:00 pm »
Thank you for your comments, aandrew. I have a couple of questions if I may:

[...] the loop that calls the HAL_SPI_Receive_DMA() function.

Hang on -- I am supposed to call HAL_SPI_Receive_DMA() in a loop?? If that is indeed required, it would explain why I get no further action. But as mentioned above, I am using DMA in circular mode, in an SPI slave device. Isn't the whole point that this keeps going on and on, after just one call to HAL_SPI_Receive_DMA()?

Quote
If they haven't got callbacks enabled they'll also want to paste their HAL_SPI_RxCpltCallback().

Sorry, you lost me there. Did you mean do write "If they have got callbacks, paste HAL_SPI_RxCpltCallback()"?

Quote
knowing WHICH version of the HAL they're using would help.

As mentioned in the OP, I am using STMCubeIDE 1.6.1, the most recent release version for Windows. If there is a separate version number for the HAL, where would I find this? The HAL source files I checked do not have any version numbers in their header.

Thanks!
 

Offline aandrew

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: ca
Re: STM32 - using SPI with circular DMA
« Reply #18 on: April 21, 2021, 08:04:17 pm »
Generally speaking, with circular DMA it just means it can re-use the buffer over and over again but the DMA requests still need to be triggered, either manually or via a timer or some other means. I don't know exactly how you're setting things up because I haven't seen your code, most importantly the code leading up to the SPI Init() and then the MspInit() that actually configures the peripheral.

I know it sounds counter-intuitive, but no, if you're *not* using callbacks then you must override the weakly-linked HAL function HAL_SPI_RxCpltCallback(), which by default does absolutely nothing. If you are using callbacks then you must register your RxCallback function with the driver. HAL used to not have callback functionality so your only choice was to override the weak functions, but part of their changes in the more recent versions of HAL is that they've introduced the ability to change the callback functions at runtime. It's always been callbacks internally, now they just give you a little more visibility into it and configurability. Personally I don't see the benefit, but it's there.

As for HAL version, you usually see that in the "Manage Embedded Software Packages" window under Cube's Help menu item.
 
The following users thanked this post: ebastler

Offline tru

  • Regular Contributor
  • *
  • Posts: 107
  • Country: gb
Re: STM32 - using SPI with circular DMA
« Reply #19 on: April 21, 2021, 09:09:08 pm »
Hmm, that wouldn't explain why there is a Normal and Circular mode for HAL driver because both use the same HAL_SPI_Receive_DMA(spiHandle, spiBuffer, SPI_BUFFER_SIZE) and spiBuffer needs to be passed.

Ok, just tried a few tests, and I think I've found a bug in CubeMX!

I confirm that with Circular buffer mode you do not call the HAL_SPI_Receive_DMA() repeatedly in a loop, it is to be called only once.  In contrast with Normal buffer mode you must call it repeatedly in a loop.

However, there is a bug that seems to stop it from working.  If I initially set the SPI to Full-Duplex Master mode and add 2x DMA streams:
1. DMA stream for SPI receive and set to circular
2. DMA stream for SPI transmit and set to normal

The HAL_SPI_Receive_DMA() function receives once but then hangs (I mean HAL_SPI_RxCpltCallback() is never called again)!  Like what ebastler said.

If I go back into CubeMX and set the DMA stream for transmit to circular, now the HAL_SPI_Receive_DMA() function works and continuously receives - the bug is gone.

Now, next problem is, when I go back into CubeMX and change the SPI to Receive only Master mode, it automagically removes the DMA stream for transmit (as mode is receive only) so leaving the DMA receive intact.

However, the HAL_SPI_Receive_DMA() function receives only once and then hangs!

But if I go back into CubeMX and toggle the Circular to Normal then back to Circular.  Then The HAL_SPI_Receive_DMA() function works!

Man!!
« Last Edit: April 21, 2021, 09:18:55 pm by tru »
 
The following users thanked this post: ebastler

Offline aandrew

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: ca
Re: STM32 - using SPI with circular DMA
« Reply #20 on: April 21, 2021, 09:26:59 pm »
Not discounting the rest of your message, but if you're using full-duplex wouldn't you use HAL_SPI_RxCpltCallback() ?
 

Offline aandrew

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: ca
Re: STM32 - using SPI with circular DMA
« Reply #21 on: April 21, 2021, 09:51:24 pm »
Just looking at the SPI driver, I see this in the top documentation:

       Circular mode restriction:
      (#) The DMA circular mode cannot be used when the SPI is configured in these modes:
          (##) Master 2Lines RxOnly
          (##) Master 1Line Rx


Is what you're after perhaps not supported?
 
The following users thanked this post: ebastler

Offline tru

  • Regular Contributor
  • *
  • Posts: 107
  • Country: gb
Re: STM32 - using SPI with circular DMA
« Reply #22 on: April 21, 2021, 10:02:19 pm »
Not discounting the rest of your message, but if you're using full-duplex wouldn't you use HAL_SPI_RxCpltCallback() ?
Yes, I am using the HAL_SPI_RxCpltCallback() in both cases which contains only code to flash a LED, and I'm not sending HAL_SPI_Receive_DMA() in there.  I didn't intend to test with full-duplex in circular mode, but because I started off by modifying an existing project which is using DMA with full-duplex in normal mode, I forgot to change it.

Interesting, I see so it has limitations - I think yes, not supported for certain config.

From the "STM32F446xx advanced Arm®-based 32-bit MCUsV6.0" reference manual I confirm DMA requests are continuous in circular mode (mentioned by the last sentence).
Quote
The circular mode is available to handle circular buffers and continuous data flows (e.g.
ADC scan mode). This feature can be enabled using the CIRC bit in the DMA_SxCR
register.
When the circular mode is activated, the number of data items to be transferred is
automatically reloaded with the initial value programmed during the stream configuration
phase, and the DMA requests continue to be served.
« Last Edit: April 21, 2021, 10:11:07 pm by tru »
 

Offline aandrew

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: ca
Re: STM32 - using SPI with circular DMA
« Reply #23 on: April 21, 2021, 10:07:45 pm »
maybe just use bidir mode (it eats another DMA channel but that's probably not an issue), set your SPI MOSI GPIO so it's *not* using the correct AF (so it doesn't actually transmit) and point the TX buffer to a zeroed bit of memory. That's probably a good workaround which'll give you circular rx transfers.
 

Offline ebastlerTopic starter

  • Super Contributor
  • ***
  • Posts: 6375
  • Country: de
Re: STM32 - using SPI with circular DMA
« Reply #24 on: April 22, 2021, 05:54:43 am »
Thank you very much for digging into this, tru and aandrew! Since I have been trying to use Rx-only mode with circular DMA, the restrictions you found might be relevant -- although the driver comments only seem to indicate restrictions in master mode, while I use slave mode.

Unfortunately, switching to full-duplex slave mode and a adding circular Tx DMA has not changed the behavior of my setup. I am still stuck with receiving one (mangled?) byte only.

More likely than not, I am making a totally stupid mistake somewhere... I will put this project aside for a few days, re-read the µC and HAL documentation, and get back to the debugger then. I will update this thread when I figure out what's going on (or when I give up  ::)). Thank you for your help so far!
« Last Edit: April 22, 2021, 06:15:02 am by ebastler »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf