Why enabling a timer via DMA write to the CR1 register fails
I have many timers working on out H743VIT6 board, so only have Tim2, 5, 12 and above available.
I have many forms of of timer triggered DMA working, but in this case as the system is near to max capacity, I need a DMA event scheduled for 52uS in the future WITHOUT using IRQs which are not time-stable enough for the purpose.
So I found that timer 16 in table 98 of the RM0433 manual is show connecting to timer 2, but in CubeMX timer 15 shows no trigger source!
So I though I would set up timer 5 to count down 52uS and trigger its DMA stream to write a half word to CR1 of Timer 15, that was setup to pace its own DMA stream. Now I can get tier 15 triggering and DMA transfering it I enable it via the end of event cllback for timer 5, but DMAing to CR1 of an diabled timer doesn’t seem to work.
It’s a very complicated problem!
// Arm one amplitude bank, started by a TIM5 countdown delay to trigger DMA write to enable a target timer with DMA stream
HAL_StatusTypeDef ArmOneBank(uint32_t *pwm_values, uint32_t DataLength, uint32_t delay_ticks)
{
HAL_StatusTypeDef status; // Free timers 2, 5 and 12-up: Timer 15 does not map to Tim5 or Tim2 in Table 98 RM0433 manual inteconnect matrix
// Timers 16 and 17 are interconnected in table 98 to timer 15, but timers 1-17 do not have trigger sources
// TIM15 in normal up-counter mode, NOT waiting for an ITR trigger
__HAL_TIM_DISABLE(&htim15);
__HAL_TIM_DISABLE_DMA(&htim15, TIM_DMA_UPDATE);
__HAL_TIM_SET_COUNTER(&htim15, 0);
__HAL_TIM_CLEAR_FLAG(&htim15, TIM_FLAG_UPDATE);
// Arm amplitude DMA while TIM15 is stopped
status = HAL_DMA_Start_IT(&hdma_tim15_up,
(uint32_t)pwm_values,
(uint32_t)&TIM8->CCR3,
DataLength);
if (status != HAL_OK)
return status;
// Prepare target timer CR1 value to enable it, preserving existing bits
tim15_cr1_start_word = (uint16_t)(TIM15->CR1 | TIM_CR1_CEN); // 0x81 Check correct!!
// Enable amplitude requests before starting TIM15
__HAL_TIM_ENABLE_DMA(&htim15, TIM_DMA_UPDATE);
///__HAL_TIM_ENABLE(&htim15); // <---- THIS LINE ENABLED THE DMA TRANSFER IMMEDIATELY - NOT DESIRED!
// Prepare TIM5 one-shot delay
__HAL_TIM_DISABLE(&htim5);
__HAL_TIM_DISABLE_DMA(&htim5, TIM_DMA_UPDATE);
__HAL_TIM_SET_COUNTER(&htim5, 0);
__HAL_TIM_SET_AUTORELOAD(&htim5, delay_ticks);
__HAL_TIM_CLEAR_FLAG(&htim5, TIM_FLAG_UPDATE);
// Arm one DMA transfer: TIM5 update -> write TIM15 CR1
status = HAL_DMA_Start_IT(&hdma_tim5_up,
(uint32_t)&tim15_cr1_start_word,
(uint32_t)&TIM15->CR1,
1);
if (status != HAL_OK)
{
__HAL_TIM_DISABLE_DMA(&htim15, TIM_DMA_UPDATE);
HAL_DMA_Abort(&hdma_tim15_up);
return status;
}
// Enable TIM5 update DMA requests only after its stream is armed
__HAL_TIM_ENABLE_DMA(&htim5, TIM_DMA_UPDATE);
// Start the one-shot countdown - when tim5 expires it will trigger its DMA
// to write the tim15_cr1_start_word to enable timer 15 but timer 15 does not pave its DMA stream for some reason
__HAL_TIM_ENABLE(&htim5);
return HAL_OK;
}
