Skip to main content
Wleon.1
Associate III
June 22, 2020
Question

STM32 PWM to stop after n pluses

  • June 22, 2020
  • 8 replies
  • 2779 views

Is there a way to stop STM32 PWM after 10 pluses ?

I know one solution is using the system time and issue a stop via the code, however my issue is the stm CPU might be very busy to handle the stop signal.

This topic has been closed for replies.

8 replies

waclawek.jan
Super User
June 22, 2020

Which STM32?

Use a timer which has the repetition counter (TIM_RTR), see TIM1/TIM8.

If there's no timer with TIM_RTR available, you can use another timer as master, in master-slave configuration, this timer in gated mode. Another option is to use DMA to load 0 into ARR or into CR1. Both these options are more complex than using the repetition counter.

JW

Wleon.1
Wleon.1Author
Associate III
June 23, 2020

Thanks for your reply, but how do you load 0 into ARR using DMA ? Is there any example ?

waclawek.jan
Super User
June 23, 2020

In the same way as you'd write to any other TIM register using DMA. Read the TIM, DMA chapters in the Reference Manual, and the Timer Cookbook application note AN4776.

JW

Wleon.1
Wleon.1Author
Associate III
June 24, 2020

Thanks for the reply, I tried the TIM DMA, and got the DMA and TIM register to the following settings, however it seems that no interrupt is happening, I don't see the ARR change. Can you help me check if my settings are correct ?0693W000001rMPsQAM.png

Tesla DeLorean
Guru
June 23, 2020

Which STM32?

What frequency, and how busy?

The STM32 could get an update interrupt at each pulse. Or at multiples with the repetition count. At 8-bit provides for 1 thru 256 as I recall.

Posted examples to forum before doing N pulse PWM using One-Shot Mode + Repetition Count

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
waclawek.jan
Super User
June 24, 2020

Okay, from the screenshots we can guess it's 'F723. You should've told us.

DMA1 Stream 0 (set to Channel 2) is triggered by TIM4_CH1, you should've set TIM4_DIER.CC1DE for that.

Then that should work, but IMO it's better to leave the trigger from update (DIER.UDE=1 as it is now), and use the respective DMA1 Stream 6 (at channel 2).

JW

Wleon.1
Wleon.1Author
Associate III
June 25, 2020

Hi thanks for the reply ! I have got the interrupt now and the DMA is running, however I encounter something very strange.

so I have set an data array

#define n 9
#define transfer 6
uint32_t buffer[n] = {500, 251, 252, 253, 504, 255, 506, 257, 258}; 
uint32_t DCR = 0x20B;

and I call the following function to kick start:

HAL_StatusTypeDef HAL_TIM_PWM_Start_DMA_MODIFIED(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData, uint16_t Length)
{
 uint32_t tmpsmcr;
 
 /* Check the parameters */
 assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));
 
 if (htim->State == HAL_TIM_STATE_BUSY)
 {
 return HAL_BUSY;
 }
 else if (htim->State == HAL_TIM_STATE_READY)
 {
 if ((pData == NULL) && (Length > 0U))
 {
 return HAL_ERROR;
 }
 else
 {
 htim->State = HAL_TIM_STATE_BUSY;
 }
 }
 else
 {
 /* nothing to do */
 }
 
 switch (Channel)
 {
 case TIM_CHANNEL_1:
 {
 /* Set the DMA compare callbacks */
 htim->hdma[TIM_DMA_ID_CC1]->XferCpltCallback = TIM_DMADelayPulseCplt;
 htim->hdma[TIM_DMA_ID_CC1]->XferHalfCpltCallback = TIM_DMADelayPulseHalfCplt;
 
 /* Set the DMA error callback */
 htim->hdma[TIM_DMA_ID_CC1]->XferErrorCallback = TIM_DMAError ;
 
 /* Enable the DMA stream */
 if (HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC1], (uint32_t)pData, (uint32_t)&htim->Instance->DMAR, Length) != HAL_OK) <----- i Change this from CCR1 to DMAR
 {
 return HAL_ERROR;
 }
 
 /* Enable the TIM Capture/Compare 1 DMA request */
 __HAL_TIM_ENABLE_DMA(htim, TIM_DMA_CC1);
 break;
 }
 
 default:
 break;
 }
 
int main(void)
{
...
 
 htim4.Instance->ARR = 1000;
 htim4.Instance->CCR1 = 100;
 HAL_TIM_PWM_Start_DMA_MODIFIED(&htim4, TIM_CHANNEL_1, buffer, transfer);
...
}
 

I wired a interrupt pin to the TIM output, and each interrupt i will save ARR and CCR1 to an array:

int arr[100] = {0};
int ccr1[100] = {0};
 
...
 
/**
 * @brief This function handles EXTI line[9:5] interrupts.
 */
void EXTI9_5_IRQHandler(void)
{
 /* USER CODE BEGIN EXTI9_5_IRQn 0 */
 
 if(i<100)
 {
 arr[i] = htim4.Instance->ARR;
 ccr1[i] = htim4.Instance->CCR1;
 }else{
 //i++;
 }
 i++;
 
 /* USER CODE END EXTI9_5_IRQn 0 */
 HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_5);
 /* USER CODE BEGIN EXTI9_5_IRQn 1 */
 
 /* USER CODE END EXTI9_5_IRQn 1 */
}

I was expecting:

arr[] = 1000, 500, 253 ...

ccr1[]=100, 251, 253 ...

what I actually got is:

arr[] = 1000, 1000, 252 ...

ccr1[]=100, 251, 504 ...

why is this so strange ? It says in the document if I set DCR to 0x20B, it should DMA 3 element in the array each time the DMA is triggered, why the pattern seems so "random".

here is my register set:0693W000001rRn0QAE.png

waclawek.jan
Super User
June 25, 2020

I don't understand what are you trying to do, but don't use both the CC1DE and UDE - use only UDE and change the DMA stream as I wrote above.

JW

Wleon.1
Wleon.1Author
Associate III
June 25, 2020

I am trying to change ARR and CCR1 for each and every pulses.

waclawek.jan
Super User
June 25, 2020

It depends on the very details of how your program is written, but if you still use Cube, maybe you are confused by the extra Update generated by the Cube init code setting TIM_EGR.UG.

JW

Wleon.1
Wleon.1Author
Associate III
June 26, 2020

Is there a way to check the current DMA count and address ?

waclawek.jan
Super User
June 26, 2020

Observe the DMA NDTR register.

JW

Wleon.1
Wleon.1Author
Associate III
June 29, 2020

Hi thanks for the reply, another question, in which document is it written TIM4 UDE is bound to DMA1 stream 6 ?, If I were to change to TIM2_CH3 and TIM8_CH1, what are the respective DMA stream ?

waclawek.jan
Super User
June 30, 2020

0693W000001rmBvQAI.png

JW

Wleon.1
Wleon.1Author
Associate III
July 1, 2020

Thanks for the reply, I notice that when I connect a debugger (using the "Build and debug" option, and it is giving a FIFO error (LISR->FWIF1 is set) ) the DMA seems to have a offset, but when I use the "Build and run" option everything seems fine, is this behavior expected ? Thanks in advance