STM32U575 timer DMA to update ARR
Hi folks,
I'm trying to use a timer to generate a PWM output on a single output channel, but vary the frequency each cycle by updating the ARR register with DMA updates. I think I set everything up correctly, but when I call HAL_TIM_Base_Start_DMA(), I don't see any ARR updates [it remains at the value configured in CubeMX]. I also registered interrupts to trigger when the DMA is half-complete and fully-complete, and have them toggle GPIO pins. I see no triggering of the interrupts either. No errors reported when calling any of the HAL functions, so it looks like the updates are not being triggered for some reason. The U5 GPDMA has a lot more to configure than the DMA on the L5 I used previously, so quite possible I've misunderstood or misconfigured something.
Timer configuration:

The counter period of 2000 is just a placeholder I expected to get overwritten by the DMA update.
The GPDMA1 CH0 configuration:

I'm not sure if the trigger configuration is correct or even necessary. I've tried with it disabled, and with rising and falling edge trigger, with none of them having any obversable difference. Does TRGO set up UPDATE in the TIM2 configuration trigger this here? If so, does TIM2 trigger an update on start, or only after the first cycle?
My code is fairly simple: DMA buffer and interrupt handlers to toggle pins to see activity:
uint32_t samples[256];
void tim_dma_half(TIM_HandleTypeDef *htim) {
HAL_GPIO_TogglePin(TIMER_DMA_GPIO_Port, TIMER_DMA_Pin);
}
void tim_dma_full(TIM_HandleTypeDef *htim) {
HAL_GPIO_TogglePin(TIMER_UPDATE_GPIO_Port, TIMER_UPDATE_Pin);
}
and in the "USER CODE BEGIN 2" section of the CubeMX-generated main():
/* Compute sine waveform for varying the timer period */
float previous = asin(0.0f) * 2.0f / M_PI;
for (int i = 0; i < 256; ++i) {
float current = asin(((float)i)/255.0) * 2.0f / M_PI;
float diff = current - previous;
previous = current;
samples[i] = (uint32_t)(diff * 100000.0f);
}
HAL_StatusTypeDef status = HAL_DCACHE_InvalidateByAddr(&hdcache1, &samples[0], sizeof(samples));
if (status != HAL_OK) {
_NOP();
}
status = HAL_TIM_RegisterCallback(&STEP_TIMER, HAL_TIM_PERIOD_ELAPSED_HALF_CB_ID, tim_dma_half);
if (status != HAL_OK) {
__NOP();
}
status = HAL_TIM_RegisterCallback(&STEP_TIMER, HAL_TIM_PERIOD_ELAPSED_CB_ID, tim_dma_full);
if (status != HAL_OK) {
__NOP();
}
/* Toggle pins to indicate start on trace */
HAL_GPIO_TogglePin(TIMER_DMA_GPIO_Port, TIMER_DMA_Pin);
HAL_GPIO_TogglePin(TIMER_DMA_GPIO_Port, TIMER_DMA_Pin);
HAL_GPIO_TogglePin(TIMER_UPDATE_GPIO_Port, TIMER_UPDATE_Pin);
HAL_GPIO_TogglePin(TIMER_UPDATE_GPIO_Port, TIMER_UPDATE_Pin);
/* Enable channel 1 */
TIM_CCxChannelCmd(STEP_TIMER.Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);
/* Start TIM2 with DMA reload of ARR */
status = HAL_TIM_Base_Start_DMA(&STEP_TIMER, &samples[1], (sizeof(samples)/sizeof(samples[0]))-1);
if (status != HAL_OK) {
__NOP();
}
With a logic analyser, I see a steady frequency matching the 2ms period from the CubeMX configuration, not the varying frequency I expected:

I didn't find any examples of how to do this for the U5. If anyone has any pointers or suggestions that would be greatly appreciated.
Many thanks,
Roger
