cancel
Showing results for 
Search instead for 
Did you mean: 

STMF4 External interrupt → DMA 20-bit SPI xfer → completion interrupt to ISR

Background, using STM32F412CG:

- we have an external 20-bit ADC triggered by an external conversion strobe

- the ADC produces a signal when conversion is complete

- external ADC-complete signal must trigger DMA to read the ADC results (20-bit over SPI)

- DMA-completion of SPI xfer must trigger a transfer-complete interrupt (enter ISR after data received&ready)

I’ve done this with several other vendors’ parts but I’m a newbie to the STM family, so a few questions:

  1. I read application note AN4031 on DMA controller use, but I don’t see from this note how DMA can be triggered from an external pin? Any recommended example?
  2. How does the 16-bit SPI do a 20-bit transfer using DMA, and trigger an interrupt on completion? (SPI transfers >16-bit are very common so this must be possible)? Recommended examples?

Thanks in advance for any pointers,

Best Regards, Dave

1 ACCEPTED SOLUTION

Accepted Solutions

OK, I got this to work as follows (thanks again for the pointers @Community member​ @Bob S​ !):

  1. DMA for SPI TX (DMA1 stream 4) setup for 3 one-byte transfers for the outbound SPI data, triggered by SPI’s TX data empty, but not yet enabled.
  2. DMA for SPI RX (DMA1 stream 3) setup for 3 one-byte transfers, triggered by SPI RX data available, with the DMA transfer-complete interrupt enabled, and DMA enabled.
  3. DMA for TIMx_CC3 (DMA2 stream 6) set to transfer a 32-bit word to the DMA stream controlling SPI TX (so that TIMx_CC3 will effectively enable SPI transmit of 3 bytes), and DMA enabled.
  4. The externally-generated ADC conversion strobe CNV is connected to and triggers:
  • external ADC’s conversion strobe input
    • TIMx_ETR input, timer in slave trigger mode (on ETR) and One-Time-Pulse mode.
  1. TIMx_CC2 delays for ADC 3uSec conversion time, then lowers CH2 output (connected to SPI CS). At end of overall timer period (ARR = 5uSec), CH2 output reverts to high.
  2. TIMx_CC3 delays additional CS-time, then CC match triggers DMA request for memory→peripheral (DMA2 stream 6). This starts SPI transmission, which in turn starts SPI reception.
  3. After DMA for SPI RX (DMA1 stream 3) completes 3rd transfer, DMA-complete interrupt triggers ISR.
  4. ISR:
  • Process received 3 bytes of SPI data.
    • Reset all 3 DMA streams for next cycle. For each DMA stream:
  1. disable stream
    1. clear all DMA completion flags
    2. reset NTDR
    3. enable stream except SPI TX (SPI TX will be enabled by timer next cycle).

Here's the picture:

0690X000006CHn0QAG.png

PS: As you guys hinted, the HAL/LL stuff was more in the way then helpful, so I ended up doing the peripheral initialization the old-fashioned way (const structure to initialize entire peripheral register set, then enable when ready). Also CubeMX-generated code failed to initialize all the required registers.

View solution in original post

19 REPLIES 19

> how DMA can be triggered from an external pin

It can't be. Timers can be triggered from external pin, and then in turn trigger DMA transfer(s).

> SPI transfers >16-bit are very common so this must be possible

It is not. The 'F4xx SPI is capable only of 8- or 16-bit transfers. Maybe your ADC can tolerate 24-bit (= 3x8) transfers, or if you don't need individual transfers but continuous ADC conversions, you can group 2 conversions into 5x8-bit transfers.

JW

Thanks Jan, but Wow, that is a pretty kludgy business.

Can the timer-completion trigger the DMA SPI transfer directly?

Again, I need to avoid any CPU/ISR involvement until the data is in memory ready to process.

On the 20-bit SPI xfer, three 8-bit transfers would be fine but CS must be brought low only once.

Surely this is possible, there are a huge number of parts that need CS low for more than 16 bits (DAC, ADC, etc).

But how is it done with STMF4? Any examples?

Thanks again,

Best Regards, Dave

Dave,

> Wow, that is a pretty kludgy business.

Take it or leave it...

> On the 20-bit SPI xfer, three 8-bit transfers would be fine but CS must be brought low only once.

There is no CS driven from the SPI anyway...

> Can the timer-completion trigger the DMA SPI transfer directly?

What do you mean by timer *completion*? An external signal can be effectively "routed through" the timer to trigger DMA - it would cause Capture in the timer, and that Capture can be one of the DMA triggers. But you need 3 transfers and this would be only one of them. So you want to start the timer and make it produce the 3 transfers. That could be performed by some of those "better" timers which have Repetition Counter; other option is to use the timers linking feature.

And, as there's no usable CS output by SPI in STM32, you might want also this to be generated by the timer.

If you don't want to Tx on the SPI, there's also an option to spend one pin and generate the clocks entirely by timers, and use SPI Rx as slave.

Post more details, if you want to discuss this further. Waveforms, datasheet links, description of the requirements.

I'd say it might be perhaps easier to accomplish this task using SAI on a STM32 equipped with it - 'F446, 'L4xx, but as it's not a standard audio which is what these modules are primarily for, maybe it would need to investigate a bit more in depth.

JW

[forum software was so kind to double my above post]

Bob S
Principal

> I need to avoid any CPU/ISR involvement until the data is in memory ready to process.

ANY? wow. But OK.... have the timer's output compare assert the A/D's chip select line (in hardware) *and* trigger the DMA to transfer 3 bytes from the A/D (i.e. DMA count=3, datasize=8 bits). The DMA can then issue a "transfer complete" interrupt (which I presume is OK because data is now in memory waiting for you to deal with it). The ISR de-asserts the A/D's chip select and does something with the data.

This presumes a couple of things:

(1) That you have the flexibility to connect whatever pin the timer's output compare can toggle to your A/D chip select

(2) that the time from timer compare asserting CS to the SPI port's first clock pulse meets your A/D's "CS asserted" to "start of data transfer" spec. Experiment and see what the timing is from the STM32.

An 100MHz CPU isn't very useful while it's sitting inside ISR in a loop waiting for SPI or bit-banging CS lines!

I've been able to do this all via DMA using other vendors' parts; perhaps we should reconsider using STM32?

Here are a couple parts considered for the current project:

http://www.ti.com/lit/ds/symlink/ads8904b.pdf

https://www.maximintegrated.com/en/ds/MAX5717-MAX5719.pdf

Note in particular the CS requirements in the either datasheet above.

There many other 20-bit SPI parts with similar requirements (CS must be held low for 20-bit duration).

CS is controlled by SPI subsystem in many vendors' parts including long xfers...

I think I understand STM SPI slave requires CS toggle to latch data at least once every 16 bits, so slave mode won't work, right?

Thanks Jan and Bob for the timer suggestion; I'll have a look.

Have you folks been able to use the HAL, or LL functions for this kind of thing?

Or should one plan on writing the required drivers?

Thanks again for the help and pointers,

Best Regards, Dave

PS: Here's an example of what we did with a different vendor's DMA: Send excitation waveform via onboard DAC, initiate ADC once per excitation cycle, read ADC, accumulate 120 samples in a buffer, then invoke ISR. No CPU involvement until a pile of samples ready. Used 4 DMA channels and DMA chaining. Yes, ADC transfer was >16-bits (this MCU's SPI module supports >16 bit SPI with multiple transfers while holding CS):

0690X000006CBrfQAG.png

PPS: DMA use for a different product (and different MCU) I did last year where CPU activity was deferred until results loaded; didn't have long SPI xfers though: https://www.silabs.com/community/mcu/32-bit/forum.topic.html/giant_gecko_control-Dd4u

Ah, so this is a planning stage of things.

There are many "innovative" ways to design a serially connected device, and there's no single common standard upon which you can build, so it's always about a thorough reading of the datasheets and a bit of proof-of-concept experimenting.

So here are the facts: STM32 SPI does not manage CS in any reasonable way; many of sequencing requirements can be accomplished by using timers but one has to know exactly what he does.

Cube/HAL is intended for the "usual" cases, mostly those which can be clicked out of CubeMX, so once you want anything beyond "usual" it's inevitably more a nuissance than help - but that's the case with any Hardware Abstraction and "Library" and "Drivers". Cube/LL is just a way to rename registers, so IMO superfluous. If you call accessing a handful registers "driver", then yes, you are better off writing your own "driver".

But I don't understand one thing: you seem to have expertize in the geckos, and tout their DMA and SPI here, so why would you want to use STM32s at the first place?

JW

I'm hardly touting the Gecko (or the other much more capable MCU illustrated above), rather pointing out that many MCUs provide DMA usable for these kinds of applications, and that this is rather routine. Frankly I'm a bit horrified that ST products don't seem to properly support SPI (especially via DMA); normal SPI support will obviously include managing CS and >16 bit transfers. Also DMA chaining and direct initiation of DMA from an external signal seem to be missing, again rather basic features.

My customer has requested we take a look at the ST parts as they have a good range of packaging, speed, general features, availability, price, etc. But if they don't provide facilities we need we'll have to look elsewhere.

Thanks though for your help here, really, much appreciated!

Best Regards, Dave