cancel
Showing results for 
Search instead for 
Did you mean: 

Timer PWM DMA Pulse generation STM32F303

pedahl
Associate II

Hi,

My aim is to generate a pulse sequence using the PWM timer and DMA analogue to Stm32 custom signal generation using pwm and dma with a STM32F303 on RTX5 RTOS.

I need Pulsefrequency with max. 500khz, i use the STM32F303RCTx with PA2 as output

Here are my Config:

 

static void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 60;
  htim2.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1;
  htim2.Init.Period = 600;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 1;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
  {
    Error_Handler();
  }
  __HAL_TIM_DISABLE_OCxPRELOAD(&htim2, TIM_CHANNEL_3);
  /* USER CODE BEGIN TIM2_Init 2 */

  /* USER CODE END TIM2_Init 2 */
  HAL_TIM_MspPostInit(&htim2);

}
static void MX_DMA_Init(void)
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Channel1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);

}
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV5;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL12;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC12;
  PeriphClkInit.Adc12ClockSelection = RCC_ADC12PLLCLK_DIV1;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

 

I use the following Code to start my sequence:

 

#define CCRValue_BufferSize 6
 __attribute__((aligned(32)))  uint32_t CCRValue_Buffer[CCRValue_BufferSize] = 
{
	500, 500, 500, 500, 500, 500
};
HAL_TIM_PWM_Start_DMA(&htim2,TIM_CHANNEL_3, CCRValue_Buffer, CCRValue_BufferSize);

 

and when the sequence is finished i need to stop the PWM DMA Timer:

 

void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==htim2.Instance)
	{
		HAL_TIM_PWM_Stop_DMA(&htim2,TIM_CHANNEL_3);
	}
};

 

 

with my oscilloscope i receive the following sequence:

scope_1.bmp

What is wrong here, can someone help me?

 

4 REPLIES 4
Sarra.S
ST Employee

Hello @pedahl,

Are you asking about the first pulse that is not identical to the rest of the pulses? 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

I expected 6 Pulses and i ask also about the deformed first pulse

Sarra.S
ST Employee

Hello again @pedahl

Regarding the pulse number, this is mostly related to stopping the DMA since the buffer size is correct, to be sure, you might need to manually clear the DMA request manually

Regarding the first different pulse, it is related to the HAL_TIM_PWM_Start function, in this function, the output channel is enabled prior to enabling the timer's counter, that's why a timing difference might be observed on the first generated PWM. This difference corresponds to the delay - in term of number of CPU cycles - between the channel enable and the counter enable in the HAL_TIM_PWM_Start function. This issue is tracked internally and a note in readme.txt files will be added. 

 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

While it's relatively simple to do in registers, others fail too using Cube/CubeMX for this. Maybe Cube/CubeMX is just not ready to generate this simply by clicking.

For example, if HAL_TIM_PWM_Stop_DMA() disables given PWM channel (it probably does, why would you use it otherwise - I don't use Cube but you can look up if it does, Cube is open source), then calling it in HAL_TIM_PWM_PulseFinishedCallback() is probably too early, as that is called inside one or two cycles before cycle intended to be the last, depending on whether you have TIMx_CCRx preload set or not. One way to be sure this does not happen is to append one zero to your array, to generate zero-length pulse, and leave the timer running (or disable it later, when the zero-lenght pulse happens). There are also other ways, depending on what exactly do you intend to do next.

@Sarra.Salso told you about the importance to sequence events at the beginning properly; again, this depends on what exactly the individual Cube/HAL incantations do, and it's way easier to do yourself by directly programming registers, as then you know what are you doing and everything is under your control.

JW