PWM/DMA interrupts when using HAL_TIM_PWM_Start_DMA(...)
- October 4, 2019
- 3 replies
- 4224 views
Hi all,
(I am using a STM32L031) I'm trying to design a system that receives a UART string and uses this data to drive a WS2812 LED strip at different colors depending on the string. So far, I've done a lot of googling and found that a lot of people are using HAL_TIM_PWM_Start_DMA() to vary duty cycles of PWM for similar purposes. I've done all the peripheral setup required I think and am able to get a PWM signal going (see attached .png) I have a couple of issues though - The PWM never stops even though HAL_TIM_PWM_Start_DMA() requires a length to be passed in. Now, I've checked that the DMA transfer completes, by setting a breakpoint in the IRQ handler like so:
void TIMx_DMA_IRQHandler(void)
{
if (__HAL_DMA_GET_IT_SOURCE(TimHandle.hdma[TIM_DMA_ID_CC3],DMA_IT_TC)){
//
if (TimHandle.hdma[TIM_DMA_ID_CC3]->XferCpltCallback != NULL){
//other = other+1;
//this following callback does nothing...
TimHandle.hdma[TIM_DMA_ID_CC3]->XferCpltCallback(TimHandle.hdma[TIM_DMA_ID_CC3]);
HAL_TIM_PWM_Stop_DMA(&TimHandle, TIM_CHANNEL_3);
//HAL_Delay(1000);
}
}
HAL_DMA_IRQHandler(TimHandle.hdma[TIM_DMA_ID_CC3]);
}And if I uncomment 'other' then I can breakpoint and see that it increments after each transfer completes. However in the IRQ_Handler, my callback is never called. Question 1 is: is there any setup/configuration for callbacks required besides throwing this in my main
TimHandle.hdma[TIM_DMA_ID_CC3]->XferCpltCallback = TransferComplete;where the callback function is defined like this in main.c
static void TransferComplete(DMA_HandleTypeDef *DmaHandle){
other = other+1; //never reached
}because TransferComplete never gets called...
Question 2: Now that I know that PWM is "working", how do I get it to stop completely after a single transfer occurs? As you can see, I have tried adding a HAL_TIM_PWM_Stop_DMA(...) in the if a transfer completes, but it has seemingly no affect. Or maybe it does, but HAL_TIM_PWM_Start_DMA(...) is called so soon after there is no perceptible pause. To fix this, I added a HAL_Delay(1000) in the interrupt handler (you can see I commented it out for now). Now the HAL user manual for the STM32L031 states that you need to be careful about using HAL_Delay when PWM is running, or in an interrupt. So I added this to give priority:
NVIC_SetPriority(SysTick_IRQn, 0);
NVIC_EnableIRQ(SysTick_IRQn);which I assumed would stop the process from hanging if a delay is added in the interrupt. But it doesn't.
Here is the loop I'm using to try and delay so that I can load the next buffer:
while (1)
{
if (HAL_TIM_PWM_Start_DMA(&TimHandle, TIM_CHANNEL_3, buffer_1, 24*8) != HAL_OK)
{
Error_Handler();
}
TogglePixelBufferAddress();
HAL_Delay(5000);
if (HAL_TIM_PWM_Start_DMA(&TimHandle, TIM_CHANNEL_3, buffer_2, 24*8) != HAL_OK)
{
Error_Handler();
}
TogglePixelBufferAddress();
HAL_Delay(5000);
}
}and here is TogglePixelBufferAddress:
void TogglePixelBufferAddress(){
__HAL_DMA_DISABLE(TimHandle.hdma[TIM_DMA_ID_CC3]);
if (flag==0){
TimHandle.hdma[TIM_DMA_ID_CC3]->Instance->CMAR = (uint32_t)(buffer_1);
__HAL_DMA_ENABLE(TimHandle.hdma[TIM_DMA_ID_CC3]);
flag = 1;
}else{
TimHandle.hdma[TIM_DMA_ID_CC3]->Instance->CMAR = (uint32_t)(buffer_2);
__HAL_DMA_ENABLE(TimHandle.hdma[TIM_DMA_ID_CC3]);
flag = 0;
}
}Thanks for reading, and if anyone could provide any insight, with any of this, it would be very much appreciated
Best Regards,
Aaron
edit1: I was able to use HAL_Delay(...) within the interrupt by using
NVIC_SetPriority(DMA1_Channel1_IRQn, 1);which I should have done initially. This now means that there is a delay between stopping and starting the DMA, however, my oscilloscope still shows that the PWM never stops. I find this odd...
edit2: I've managed to stop the PWM after completing one transaction: actually the while(1) loop isn't required at all. Instead I started the TIM_PWM_Start_DMA(...) outside of a loop, and then stopped it in the transfer complete interrupt. Probably I throw all of the logic inside of the interrupt and configure it to be at the lowest priority, which means it won't block anything else important
