Showing results for 
Search instead for 
Did you mean: 

Trigger SPI DMA transfer from Timer directly

Associate II

Hey there, 

at the moment I am stuck with the following problem: I need to trigger a SPI DMA Transfer precisely at each Timer overflow. NVIC Timer interrupts are not an option, because the jitter is way too high when I have to jump into code each time (I managed to trigger SPI-DMA transfer using the Timers NVIC global interrupt, but as I said, jitter is way too high). So now I am looking for a solution that involves the Cube MX, I want to configure the Timer in a way so that it directly triggers the DMA of the SPI? Or is there anything I can once declare in code that will do the job for me? In the end the solution should work without the CPU at all. I am using a NUCLEO-F446RE Board here, running at 180MHz. If someone has a quick solution (In Cube MX or Code, doesn’t matter as long as it works) I would be very thankful!

Greetings Julius


>> An often overlooked feature of the STM32 DMA controllers is that the peripheral address of a DMA transfer

>> can belong to a different peripheral, not just to the one which is sending the request."

> Can you show where in the reference manual can find this information


But there's also no mention that the peripheral address *must* belong to the peripheral sending the request.

There are secondary effects, though - almost no requests from the communication devices (SPI, UART, I2C) are registered/cleared by the transfer as it would be with traditional DMA controllers (think 8257); they come *directly* from the TXE/RXNE signals or their equivalents. In other words, if the peripheral is not served, the DMA will be triggered repeatedly/forever.

So, the transfer to other peripheral is mostly restricted to timer-triggered DMA.

> and how to set the registers?

Simply set the peripheral address register to/from whatever place you want to transfer.


I'm currently working with the STM32G474 which uses the DMAMUX.  I have a timer configured to trigger a DMA transfer from memory to the SPI2->DR and everything works as expected for a single 16-bit DMA transfer with TIM_DMA_CC1 set.  The timer, TIM5, is configured in PWM mode to pulse low and act as the slave select (needed for synchronous sampling of an ADC).  The trailing edge of the pulse is set via TIM5->CCR2.  When I set both TIM_DMA_CC1 and TIM_DMA_CC2 I expected this would generate two DMA transfers; however, logic analyzer traces of the SPI serial clock and the TIM5 PWM output only show a 16-bit transfer.  Monitoring the DMA1_Channel3->CNDTR register shows the counter decrementing once but not a second time.  Does this architecture behave differently or am I missing something.  

Here's the relative code:

uint16_t transmit_data[2] = {0x8102, 0x8304};

TIM5->CCR1 = 1; // Set the delay to turn on time for CH1 / PA0
TIM5->CCR2 = 80; // Set the delay to turn off time for CH1 / PA0
TIM5->CCER |= TIM_CCER_CC1E | TIM_CCER_CC2E; // Enable all compares 1 & 2
TIM5->CR1 |= TIM_CR1_CEN; // Start the timer counter

HAL_DMA_Start(&hdma_tim5_ch1,  transmit_data, &(SPI2->DR), 2);