cancel
Showing results for 
Search instead for 
Did you mean: 

Is there a HAL example of a memory to memory, or memory to peripheral DMA operation triggered directly by a TIMER event (not via a timer ISR) on the STM32H7?

CMorg.1
Associate II

I've read a ton of app notes, the STM32H7 reference manual, posts here, and I can't figure out how to have the timer UP event trigger a DMA operation. I'm sure this is obvious to someone with more understanding and could be gleaned from other STM32 model examples but I haven't been able to put things together and was hoping to find an example using the HAL for the H7.

7 REPLIES 7
TDK
Guru

This one transfers from memory to the DAC peripheral on the TIM6 update event:

https://github.com/STMicroelectronics/STM32CubeH7/blob/master/Projects/NUCLEO-H743ZI/Examples/DAC/DAC_SignalsGeneration/Src/main.c

If you feel a post has answered your question, please click "Accept as Solution".
CMorg.1
Associate II

@TDK​ thank you for the reference. Looking at that code it appears that the DMA hardware has the ability to have an external trigger and that's what is being used to initiate the DAC. I was hoping to use the TIM UP event to capture a value from gpio by reading the ODR register at a frequency determined by the timer.

TDK
Guru

It's the exact same concept, but you would be transferring to GPIO->ODR (or GPIO->BSRR) instead of the DAC. Everything else would be the same.

I don't think you're going to find a HAL example that does this. You may need to write your own function here. Use HAL_DAC_Start_DMA as a starting point.

> reading the ODR register

Do you want to read or write? The OP says you want to transfer to GPIO, but if you want to read, you would read from IDR.

If you feel a post has answered your question, please click "Accept as Solution".
CMorg.1
Associate II

@TDK​ no you are right, I've not been particularly clear. I was thinking that to test it I could set up the timer and write to the GPIO and look on the scope to see the expected output signal (a DMA writing say 0x0000FFFF and then 0xFFFF0000 should produce a high and then low on the gpio output). That way I could confirm that the timer was set at the correct frequency etc and dma was working. Then turn around and swap the direction reading data in.

I did notice that the block diagram for the DAC hardware shows external trigger inputs, figure 207 in the ref manual, that looked like were being connected to the timer exto signal.

Looking at the GPIO section of the manual its a register read that triggers the operation (either the read or write). I'm not following how the timer event would cause the DMA operation to execute without doing so via the timer isr (which at my 6MHz sampling rate means a lot of time spent entering and exiting ISRs).

I'll look at HAL_DAC_Start_DMA(). Thank you again for your replies, I appreciate it as I've been banging my head on this one on and off for a week now, unable to determine if its possible and if so, how.

Wouldn't you just pick a trigger source in the DMAMUX? Like the TIM1 Update? As a DMA request # 15. Not tried this with the GPIO, but that's the sense of how the plumbing/connectivity gets done. On a phase of the TIM, then via a CHx / CCRx == CNT match.

0693W000006HdiAQAS.jpgYou might need to be sensitive to which bus the GPIO hardware is on, picking a DMA unit that deals with that properly, per the bus matrix diagram.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
TDK
Guru

> I did notice that the block diagram for the DAC hardware shows external trigger inputs, figure 207 in the ref manual, that looked like were being connected to the timer exto signal.

This is true, but not relevant for what is happening. The timer update event is the one initiating the DMA transfer, not the DAC. The DAC is just a bystander and the external DAC trigger isn't doing anything. The only way the DAC comes into play here is that it's the destination address, which is why you can easily set GPIO->BSRR as the destination address to get the same effect.

>  I'm not following how the timer event would cause the DMA operation to execute without doing so via the timer isr

That's the whole point of the DMA--to do stuff without needing the CPU. It's hardwired to be able trigger on certain events, in this case the timer update event.

To be clear, the timer ISR is also triggered from the update event, but only if you have the ISR enabled, which is unnecessary here.

If you feel a post has answered your question, please click "Accept as Solution".
TDK
Guru

This does what you want on the STM32F4 series. To adapt it to the STM32H7, you would need to add in the DMAMUX part. It doesn't use HAL, but maybe it would help your understanding.

  // set up the timer
  __HAL_RCC_TIM1_CLK_ENABLE();
  __HAL_RCC_TIM1_FORCE_RESET();
  __HAL_RCC_TIM1_RELEASE_RESET();
  TIM1->PSC = 0;
  TIM1->ARR = 4;
  TIM1->CNT = 0;
  TIM1->DIER |= TIM_DIER_UDE;
 
  uint32_t gpio_data[] = {
      (1 << 10) | (1 << 11),
      1 << 26,
      (1 << 10) | (1 << 27),
      1 << 26};
 
  // set up the DMA channel
  __HAL_RCC_DMA2_CLK_ENABLE();
  __HAL_RCC_DMA2_FORCE_RESET();
  __HAL_RCC_DMA2_RELEASE_RESET();
 
  DMA_Stream_TypeDef * stream = DMA2_Stream5;
  stream->M0AR = (uint32_t) gpio_data;
  stream->NDTR = sizeof(gpio_data) / (sizeof(*gpio_data));
 
  // disable direct mode
  stream->FCR |= DMA_SxFCR_DMDIS;
  //stream->FCR |= 0b11 << DMA_SxFCR_FTH_Pos;
 
  // TIM1_UP is channel 6 on DMA2 stream 5
  stream->CR |= 6 << DMA_SxCR_CHSEL_Pos;
  stream->CR |= 0b10 << DMA_SxCR_MSIZE_Pos;
  stream->CR |= 0b10 << DMA_SxCR_PSIZE_Pos;
  stream->CR |= DMA_SxCR_MINC;
  stream->CR |= DMA_SxCR_CIRC;
  stream->CR |= 0b01 << DMA_SxCR_DIR_Pos;
  stream->PAR = (uint32_t) &GPIOC->BSRR;
  stream->CR |= 0b1 << DMA_SxCR_PL_Pos;
 
  stream->CR |= DMA_SxCR_EN;
 
  // start timer
  TIM1->CR1 |= TIM_CR1_CEN;

If you feel a post has answered your question, please click "Accept as Solution".