cancel
Showing results for 
Search instead for 
Did you mean: 

When to stop TIM_DMABurst and how to first start TIM_DMABurst

dming.4
Associate II

I try to use TIM_DMABurst to generate exact number of pwm pulses.

But I found after call HAL_TIM_DMABurst_WriteStart and HAL_TIM_PWM_Start, it enter HAL_TIM_PeriodElapsedCallback. And then if I call HAL_TIM_PWM_Stop it will stop and generate no pwm. If I call HAL_TIM_DMABurst_WriteStop and HAL_TIM_DMABurst_WriteStart it will continue generate PWM but the wave is wrong

5 REPLIES 5
dming.4
Associate II
TIM_HandleTypeDef htim1;
DMA_HandleTypeDef hdma_tim1_up;
 
static uint32_t g_irq_cnt = 0;
static uint32_t aSRC_Buffer[3];
 
int main(void)
{
  /* USER CODE BEGIN 1 */
 
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_TIM1_Init();
  /* USER CODE BEGIN 2 */
  aSRC_Buffer[0] = 7200 - 1;                     /* ARR */
  aSRC_Buffer[1] = 7 - 1;                        /* RCR */
  aSRC_Buffer[2] = (aSRC_Buffer[0] + 1) * 0.2;   /* CCR1 */
  HAL_TIM_DMABurst_WriteStart(&htim1, TIM_DMABASE_ARR, TIM_DMA_UPDATE, aSRC_Buffer, TIM_DMABURSTLENGTH_3TRANSFERS);
  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
  // HAL_TIM_GenerateEvent(&htim1, TIM_EVENTSOURCE_UPDATE);
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
    HAL_Delay(500);
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
 
 
/**
  * @brief  Period elapsed callback in non blocking mode
  * @note   This function is called  when TIM7 interrupt took place, inside
  * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
  * a global variable "uwTick" used as application time base.
  * @param  htim : TIM handle
  * @retval None
  */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */
  if (htim->Instance == TIM1) {
	  ++g_irq_cnt;
 
	  if (g_irq_cnt == 1) {
		  aSRC_Buffer[0] = 3600 - 1;                     /* ARR */
		  aSRC_Buffer[1] = 7 - 1;                        /* RCR */
		  aSRC_Buffer[2] = (aSRC_Buffer[0] + 1) * 0.2;   /* CCR1 */
	  } else if (g_irq_cnt == 2) {
		  aSRC_Buffer[0] = 1800 - 1;                     /* ARR */
		  aSRC_Buffer[1] = 7 - 1;                        /* RCR */
		  aSRC_Buffer[2] = (aSRC_Buffer[0] + 1) * 0.4;   /* CCR1 */
	  } else if (g_irq_cnt == 3) {
	  		  aSRC_Buffer[0] = 900 - 1;                     /* ARR */
	  		  aSRC_Buffer[1] = 7 - 1;                        /* RCR */
	  		  aSRC_Buffer[2] = (aSRC_Buffer[0] + 1) * 0.6;   /* CCR1 */
	  	  }
 
	  HAL_TIM_DMABurst_WriteStop(&htim1, TIM_DMA_UPDATE);
	  // htim->DMABurstState = HAL_DMA_BURST_STATE_READY;
	  HAL_TIM_DMABurst_WriteStart(&htim1, TIM_DMABASE_ARR, TIM_DMA_UPDATE, aSRC_Buffer, TIM_DMABURSTLENGTH_3TRANSFERS);
 
	if (g_irq_cnt >= 6) {
		HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
	}
  }
  /* USER CODE END Callback 0 */
  if (htim->Instance == TIM7) {
    HAL_IncTick();
  }
  /* USER CODE BEGIN Callback 1 */
 
  /* USER CODE END Callback 1 */
}
 
static void MX_TIM1_Init(void)
{
 
  /* USER CODE BEGIN TIM1_Init 0 */
 
  /* USER CODE END TIM1_Init 0 */
 
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
 
  /* USER CODE BEGIN TIM1_Init 1 */
 
  /* USER CODE END TIM1_Init 1 */
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 100 - 1;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 65535;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
  sBreakDeadTimeConfig.DeadTime = 0;
  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
  if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM1_Init 2 */
 
  /* USER CODE END TIM1_Init 2 */
  HAL_TIM_MspPostInit(&htim1);
 
}
 
static void MX_DMA_Init(void)
{
 
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();
 
  /* DMA interrupt init */
  /* DMA1_Channel5_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
 
}
 
 
/**
* @brief TIM_Base MSP Initialization
* This function configures the hardware resources used in this example
* @param htim_base: TIM_Base handle pointer
* @retval None
*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
  if(htim_base->Instance==TIM1)
  {
  /* USER CODE BEGIN TIM1_MspInit 0 */
 
  /* USER CODE END TIM1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_TIM1_CLK_ENABLE();
 
    /* TIM1 DMA Init */
    /* TIM1_UP Init */
    hdma_tim1_up.Instance = DMA1_Channel5;
    hdma_tim1_up.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_tim1_up.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_tim1_up.Init.MemInc = DMA_MINC_ENABLE;
    hdma_tim1_up.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_tim1_up.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_tim1_up.Init.Mode = DMA_NORMAL;
    hdma_tim1_up.Init.Priority = DMA_PRIORITY_HIGH;
    if (HAL_DMA_Init(&hdma_tim1_up) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_LINKDMA(htim_base,hdma[TIM_DMA_ID_UPDATE],hdma_tim1_up);
 
    /* TIM1 interrupt Init */
    HAL_NVIC_SetPriority(TIM1_UP_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
  /* USER CODE BEGIN TIM1_MspInit 1 */
 
  /* USER CODE END TIM1_MspInit 1 */
  }
 
}
 
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(htim->Instance==TIM1)
  {
  /* USER CODE BEGIN TIM1_MspPostInit 0 */
 
  /* USER CODE END TIM1_MspPostInit 0 */
 
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**TIM1 GPIO Configuration
    PA8     ------> TIM1_CH1
    */
    GPIO_InitStruct.Pin = GPIO_PIN_8;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /* USER CODE BEGIN TIM1_MspPostInit 1 */
 
  /* USER CODE END TIM1_MspPostInit 1 */
  }
 
}

dming.4
Associate II

The core like this

First start TIM_DMABrust with

  aSRC_Buffer[0] = 7200 - 1;                     /* ARR */
  aSRC_Buffer[1] = 7 - 1;                        /* RCR */
  aSRC_Buffer[2] = (aSRC_Buffer[0] + 1) * 0.2;   /* CCR1 */

and then in the HAL_TIM_PeriodElapsedCallback change aSRC_Buffer

	  if (g_irq_cnt == 1) {
		  aSRC_Buffer[0] = 3600 - 1;                     /* ARR */
		  aSRC_Buffer[1] = 7 - 1;                        /* RCR */
		  aSRC_Buffer[2] = (aSRC_Buffer[0] + 1) * 0.2;   /* CCR1 */
	  } else if (g_irq_cnt == 2) {
		  aSRC_Buffer[0] = 1800 - 1;                     /* ARR */
		  aSRC_Buffer[1] = 7 - 1;                        /* RCR */
		  aSRC_Buffer[2] = (aSRC_Buffer[0] + 1) * 0.4;   /* CCR1 */
	  } else if (g_irq_cnt == 3) {
	          aSRC_Buffer[0] = 900 - 1;                     /* ARR */
                  aSRC_Buffer[1] = 7 - 1;                        /* RCR */
	          aSRC_Buffer[2] = (aSRC_Buffer[0] + 1) * 0.6;   /* CCR1 */
          }

but i get pluss like that

0693W00000QLrR1QAL.png0693W00000QLrS4QAL.png0693W00000QLrSYQA1.png0693W00000QLrSxQAL.png0693W00000QLrT7QAL.pngand in the end it will generate a very small pluse

0693W00000QLrTbQAL.png

Which STM32?

> and then in the HAL_TIM_PeriodElapsedCallback change aSRC_Buffer

But why?

The point of DMA is, that it works without your intervention. So just define a long enough buffer to hold all the changes, and run the DMA and you're done. A nice trick to stop is to add one more set at the end, where ARR=0.

JW

stm32f103

I use this timer to driver a step motor ​ so it must be stop at the target point. Amd the problem is the wave generate by mcu is wrong. Use dmamultiwrite do not fix.

Once you call 'dma write start' you will find the pwm will not stop and you can ' dma write​ start' again before use 'dma write stop'.