Electronics > Microcontrollers

EXTI trigger of DMA receive from SPI (STM32U5)

<< < (2/2)

Use a 'trigger' for the SPI peripheral. EXTI can be configured as a trigger (exti4, exti9). See RM0456, chapter 59: "Serial peripheral interface (SPI)".
Then you can link a DMA channel to automatically save the transfered sample to a memory buffer.

No need to use timers or interrupts for this.


--- Quote from: davegravy on January 28, 2022, 07:36:57 pm ---
--- Quote from: uer166 on January 28, 2022, 07:17:44 pm ---
--- Quote from: davegravy on January 28, 2022, 02:25:51 pm ---I am trying to interface the LTC2512-24 precision ADC with STM32U5. The ADC uses standard unidirectional SPI and requires that communication happen within a fairly tight time window during its the conversion<->acquisition cycle. The ADC outputs a pulse on the Data Ready Line (DRL) and I need to read 24 or 32 bits from it within about 700ns after the DRL falling edge. Outside of this risks causing analog noise interference. I've tested using interrupts based on DRL and the response time is too slow.

--- End quote ---

To read 32 bits you'd need a SPI clock rate of ~45MHz, assuming zero latency on the interrupt/DMA which is quite fast for normal SPI. Never-mind, I see the ADC supports up to 100MHz SPI bus. Considering the STM32U5 runs at 160MHz tops, it would seem it's a hard target to beat. No specific advice, but I've had success with chaining and connecting timers to all kinds of peripherals, and I bet you can provide the DRL to a TIM input capture, and generate a DMA request using a timer. Would be quite interested in the solution you come up with.

--- End quote ---

Thanks.  Are you mentioning a TIM-based solution because there's something about using EXTI-triggered DMA (without software involvement) that's likely to not work? Or just because TIM is what's worked for you in the past?

--- End quote ---

Nope, just as a general comment about hacking in TIMs when all else fails. As SiliconWizard says, you better use the dedicated SPI hardware.


--- Quote from: uer166 on January 28, 2022, 08:31:04 pm ---Nope, just as a general comment about hacking in TIMs when all else fails. As SiliconWizard says, you better use the dedicated SPI hardware.

--- End quote ---
You can also use TIM (or chained TIMs) for all sorts of triggering and various clocks/framing signals generation, and feed them externally to SPI set as slave.


I modified this NUCLEO SPI-DMA example and finessed it to get me the timing I need. I had tried using the falling edge of DRL as the trigger for SPI autonomous mode however this was still leaving a ~320ns latency before the first SCK pulse and this meant I'd need to push the SPI clock to 80MHz to finish in time. 80Mhz was giving me some data corruption so I backed off to 40Mhz and used the rising edge of DRL with a 10 cycle delay (SPI_CFG2 MSSI[3:0]: Master SS Idleness) that eliminated the 320ns delay and gets me into compliance. It seems a bit risky but the DRL pulse width seems stable.

This is a low power application and the above solution requires implementing an ISR for the SPI rx complete callback to move the received 24 or 32 bits into a larger processing buffer, and get another DMA rx transfer setup. In other words I have to wake the CPU every sample that the ADC outputs, whereas I'd prefer to be able to wake and process a frame of samples.

I read this article a few times:


It says regarding SPI:

--- Quote ---The peripheral is not burst capable when doing GPDMA transfer. All transfers must be handled in single data
mode by the GPDMA controller, since the peripheral sends a new GPDMA request each time a data is needed
to be written/read
--- End quote ---

Burst mode I think allows one to use a large buffer and increment the destination address as each "beat" of data is received, but is not supported. It's not clear to me that even if it was supported if this would only apply to data that is sent continuously (i.e no gap in the SCK clock like I need) or if each beat can be triggered by DRL.

The NUCLEO example I am using doesn't use single data mode, it seems to use linked list and I'm still unclear if that can be adapted so I can avoid waking for each sample. I am open to suggestions.


The STM32U5's feature support for RDY to signal the SPI peripheral's readiness to transfer data. I decided the easiest strategy to have one long data transfer with carefully timed gaps in the middle was to leverage RDY, since RDY low causes the SPI transfer as well as its clock to suspend completely, effectively gating the transfer. While the ADC I'm using doesn't generate RDY, it does have Data Ready Line (DRL) which is useful for generating an RDY signal.

I needed RDY to be a pulse 32 SCK cycles wide, starting just after the falling edge of DRL. I used the falling edge of DRL as a slave trigger for TIM3, with TIM3 configured in PWM mode 2 (one pulse mode) and then patched this to the RDY pin. Turns out there's some latency between DRL trigger and the TIM3 pulse, as well as between the RDY rising edge and commencement of SCK, that meant I had a bunch of dead time I didn't want. So I switched to using the preceding rising edge of DRL instead and added delay to the pulse as necessary to place the SCK in the window I wanted. You can see the delays in the attached LA output.

I don't know how deterministic the latencies are, and this seems kind of open loop / fragile / prone to timing error. I'm stretching my (very recently developed) abilities in this field already so barring any brilliant ideas from others I'm stopping here for now. Also the last byte of the 32 bits is useable as a check bit, and in a few hundred samples taken I haven't seen a read error. I guess I have to do some more rigorous testing for errors, including under various MCU load conditions.

At 40Mhz SCK clock I'm just slightly over the target of 740ns to complete my 32bit read. I could drop the last byte (check byte) and be compliant but I like the idea of keeping it to catch data errors. Adjusting the prescaler to give 80Mhz is overkill, so I may need to tweak the clock config register values I copied from the CubeMX HAL code to get me something around 50MHz.

Then I need to figure out how to properly sleep/stop mode the MCU without impacting DMA. This MCU has Low Power Background Autonomous Mode (LPBAM), LPDMA, LPTIM, and all sorts of low power stuff I'm not yet sure I should be using.


[0] Message Index

[*] Previous page

There was an error while thanking
Go to full version