2021-01-04 08:09 AM
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.
2021-01-04 09:09 AM
This one transfers from memory to the DAC peripheral on the TIM6 update event:
2021-01-04 07:40 PM
@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.
2021-01-04 08:17 PM
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.
2021-01-05 05:20 PM
@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.
2021-01-05 05:40 PM
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.
You 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.
2021-01-05 05:53 PM
> 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.
2021-01-05 05:56 PM
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;