cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4: TIM Triggered SPI Transmit

tkurmann
Associate II
Posted on May 13, 2013 at 23:27

Hi,

I am trying to interface the STM32F4Discovery board with an external A/D-converter. The A/D generates a GPIO interrupt as soon as the data is sampled and ready to be retrieved. After that 3 * 8 bytes have to be retrieved over SPI. To read the data out of the ADC I ofcourse have to send dummy bytes so the clock is generated. Now, I mapped the GPIO (PE9) to the TIM1 Ch1 and it is properly generating DMA requests on DMA2 Stream 1 Channel 6 to start the DMA transfer. The DMA, after it is triggered by TIM1 CH1 CC1, should send out all data in the buffer, but it only sends out one single 8 bit or 16 bit sequence (depending on SPI definition). According to the reference manual, the Tx Buffer is only one word, so my worst case guess is that what I am intending on doing is impossible. Anyway, here are some parts of the code, maybe somebody can help me on this :) TIM1 initialization

TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_ICInit(TIM1, &TIM_ICInitStructure);
TIM_TIxExternalClockConfig (TIM1, TIM_TS_TI1FP1, TIM_ICPolarity_Rising, 0) ;
TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_External1);
TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);
TIM_DMACmd(TIM1,TIM_DMA_CC1,ENABLE);
TIM_Cmd (TIM1, ENABLE);

SPI DMA with TIM DMA request

DMA_InitStructureTIM.DMA_BufferSize = 24 ;
DMA_InitStructureTIM.DMA_FIFOMode = DMA_FIFOMode_Disable ;
DMA_InitStructureTIM.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull ;
DMA_InitStructureTIM.DMA_MemoryBurst = DMA_MemoryBurst_Single ;
DMA_InitStructureTIM.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructureTIM.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructureTIM.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructureTIM.DMA_PeripheralBaseAddr =(uint32_t) (&(SPIx->DR)) ;
DMA_InitStructureTIM.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructureTIM.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructureTIM.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructureTIM.DMA_Priority = DMA_Priority_High;
/* Configure TX DMA */
DMA_InitStructureTIM.DMA_Channel = TIM1CC1_DMA_CHANNEL ;
DMA_InitStructureTIM.DMA_DIR = DMA_DIR_MemoryToPeripheral ;
DMA_InitStructureTIM.DMA_Memory0BaseAddr =(uint32_t)aTxBuffer ;
DMA_Init(TIM1CC1_DMA_STREAM, &DMA_InitStructureTIM);

Thanks! #tim-spi-dma
8 REPLIES 8
Posted on May 14, 2013 at 01:50

I'm not convinced that is a viable path. I'd probably try to create two SPI DMA tasks (TX, RX) and light them off using an EXTI interrupt on a desired pin. Circular DMA would not be a good plan as it would keep going once lit.

In the one clock per transfer domain, sending a word to the DMA controller may be sufficient to enable an SPI transaction.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
tkurmann
Associate II
Posted on May 14, 2013 at 10:06

If I understand you correctly, you would start the transfer in the interrupt handler of the EXTI, right?

Since I would like to have a high sampling rate of around 10 kHz, I am a bit worried that this will consume too much CPU time, but I will give it a try.

Posted on May 14, 2013 at 10:11

I am not sure if this is what Clive meant, but you might try to set up the ''regular'' SPI-Tx-triggered DMA channel except enabling it, and then the timer-triggered DMA could write to the SPI-Tx-triggered-DMA's control register to start the transfer.

JW
Posted on May 14, 2013 at 12:26

In pondering some more, you could probably do the RX with circular DMA, as it would be limited by the TX side generating the clocks.

Slaving the STM32 and generating 192 SPI clocks in response to the ADC request might also work. I think the timers repetition count is 8-bit so that should fit.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
tkurmann
Associate II
Posted on May 14, 2013 at 13:33

That sounds plausible, theoretically. Practically I am having a hard time finding the control Register (except for the FIFO control register), you do mean a DMA register not a SPI, right?

Thanks!

tkurmann
Associate II
Posted on May 15, 2013 at 08:44

Never mind my last post, I reread the documentation and believe I know what waclawek.jan meant. After every timer DMA request, the DMA_SxCR of the SPI Tx has to have EN set again. The only problem is, that the EN bit can only be set if the interrupt flags (TCIF, HTIF) are 0. Even though I disabled these interrupts they seemingly still keep coming and this makes waclawek.jan approach impossible.

@clive1

With your approach, I assume that I will have problems with the NSS of the slave. Keeping it active all the time seems prone to trigger due to external influences.

Anyway, I implemented the DMA transfer triggering in the IRQ handler of the Timer. This costs me (with API functions) around 500 ns per sample. So at 10 kHz this is costing me 0.5% CPU time.

Posted on May 15, 2013 at 10:24

> Never mind my last post, I reread the documentation and believe I know what waclawek.jan meant.

> After every timer DMA request, the DMA_SxCR of the SPI Tx has to have EN set again.

Yes. Thanks for filling in the register/flags names - it was only a half-baked quick idea so I did not care to be more precise.

> The only problem is, that the EN bit can only be set if the interrupt flags (TCIF, HTIF) are 0.

> Even though I disabled these interrupts they seemingly still keep coming and this makes waclawek.jan approach impossible.

As I said, a half-baked idea it was.

The individual peripheral's (including the DMA controller's) construction with regard of the order of ''event latch (= status flag) - interrupt ena/disa flag'' is inconsistent. This is understandable, as the whole chip was stitched together as a heterogeneous bunch of IP cores purchased from several vendors - most if not all the 32-bitters today are ''generated'' in this way. But the real pity is, that the ''integrator'', ST, does not care to produce a consistent and concise enough documentation for the chip; so one has to infer minor but important details such as this either from indirect hints elsewhere in the documentation, or from experimenting with the real chip... :(

I believe there might be more problems with this approach. For example, while - again according to experiments - once a DMA trigger occurs, it remains latched at the DMA stream input even if EN is cleared, consequently a DMA transfer occurs immediately after EN is enabled; the manual does not explicitly describe this behaviour (which, btw., while beneficial in this particular case, is adverse in other cases), so this might potentially change in a future revision of the silicon, ergo I personally would not rely on it.

> @clive1

> With your approach, I assume that I will have problems with the NSS of the slave. Keeping it

> active all the time seems prone to trigger due to external influences.

Generating several dozens of clocks would require at least two timers in chain. I'd say, one of them could generate the NSS as required, too.

JW

holcomb
Associate
Posted on July 24, 2013 at 02:31

Hello,

This is exactly what I want to do but only with one word each trigger, so the problem version you describe is exactly what I need.  If you could post/send the complete listing it would be greatly appreciated.

Thanks!