Skip to main content
LZure.1
Associate
February 8, 2022
Question

How to use HAL DMA to generate PWM on P-NUCLEO-WB?

  • February 8, 2022
  • 7 replies
  • 5770 views

I am trying to generate PWM by using DMA with HAL library:

uint16_t buffer[1] = {1500};
... 
Status = HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1, (uint32_t *)buffer, 1);

however nothing happens. I am able to generate PWM without DMA:

 TIM2->CCR1 = 500;
 HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);

Is there any example of DMA PWM usage?

7 replies

Remy ISSALYS
Technical Moderator
March 8, 2022

Hello,

Maybe you have a wrong configuration for your DMA, according to your code you need to set DMA for TIM2 channel 1 and to configure Memory to Peripheral direction if you need to send data to the peripheral.

Best Regards

LZure.1
LZure.1Author
Associate
May 4, 2022

I have followed this tutorial without success:

https://controllerstech.com/pwm-with-dma-in-stm32/

Please take a look at my code:

TIM init:

/**
 * @brief TIM2 Initialization Function
 * @param None
 * @retval None
 */
static void MX_TIM2_Init(void)
{
 
 /* USER CODE BEGIN TIM2_Init 0 */
 
 /* USER CODE END TIM2_Init 0 */
 
 TIM_ClockConfigTypeDef sClockSourceConfig = {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 = 64-1;
 htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
 htim2.Init.Period = 10000-1;
 htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
 htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
 if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
 {
 Error_Handler();
 }
 sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
 if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
 {
 Error_Handler();
 }
 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 = 0;
 sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
 sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
 if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN TIM2_Init 2 */
 
 /* USER CODE END TIM2_Init 2 */
 HAL_TIM_MspPostInit(&htim2);
 
}

TIM_Base_MspInit:

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
 if(htim_base->Instance==TIM2)
 {
 /* USER CODE BEGIN TIM2_MspInit 0 */
 
 /* USER CODE END TIM2_MspInit 0 */
 /* Peripheral clock enable */
 __HAL_RCC_TIM2_CLK_ENABLE();
 
 /* TIM2 DMA Init */
 /* TIM2_CH1 Init */
 hdma_tim2_ch1.Instance = DMA1_Channel1;
 hdma_tim2_ch1.Init.Request = DMA_REQUEST_TIM2_CH1;
 hdma_tim2_ch1.Init.Direction = DMA_MEMORY_TO_PERIPH;
 hdma_tim2_ch1.Init.PeriphInc = DMA_PINC_DISABLE;
 hdma_tim2_ch1.Init.MemInc = DMA_MINC_ENABLE;
 hdma_tim2_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
 hdma_tim2_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
 hdma_tim2_ch1.Init.Mode = DMA_NORMAL;
 hdma_tim2_ch1.Init.Priority = DMA_PRIORITY_LOW;
 if (HAL_DMA_Init(&hdma_tim2_ch1) != HAL_OK)
 {
 Error_Handler();
 }
 
 __HAL_LINKDMA(htim_base,hdma[TIM_DMA_ID_CC1],hdma_tim2_ch1);
 
 /* USER CODE BEGIN TIM2_MspInit 1 */
 
 /* USER CODE END TIM2_MspInit 1 */
 }
 
}

TIM MspPostInit:

void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{
 GPIO_InitTypeDef GPIO_InitStruct = {0};
 if(htim->Instance==TIM2)
 {
 /* USER CODE BEGIN TIM2_MspPostInit 0 */
 
 /* USER CODE END TIM2_MspPostInit 0 */
 
 __HAL_RCC_GPIOA_CLK_ENABLE();
 /**TIM2 GPIO Configuration
 PA0 ------> TIM2_CH1
 */
 GPIO_InitStruct.Pin = GPIO_PIN_0;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
 GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
 /* USER CODE BEGIN TIM2_MspPostInit 1 */
 
 /* USER CODE END TIM2_MspPostInit 1 */
 }
 
}

DMA init:

static void MX_DMA_Init(void)
{
 
 /* DMA controller clock enable */
 __HAL_RCC_DMAMUX1_CLK_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);
 
}

Code to generate PWM:

int datasentflag=0;
 
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
 HAL_TIM_PWM_Stop_DMA(htim, TIM_CHANNEL_1);
 datasentflag = 1;
}
 
uint16_t pwmData[24];
 
void WS2812_Send (uint32_t color)
{
 for (int i=23; i>=0; i--)
 {
 if (color&(1<<i))
 {
 pwmData[i] = 6600;
 }
 else pwmData[i] = 3300;
 }
 
 HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1, (uint32_t *)pwmData, 24);
 while (!datasentflag){};
 datasentflag = 0;
}

Main:

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();
 
/* Configure the peripherals common clocks */
 PeriphCommonClock_Config();
 
 /* USER CODE BEGIN SysInit */
 
 /* USER CODE END SysInit */
 
 /* Initialize all configured peripherals */
 MX_GPIO_Init();
 MX_DMA_Init();
 MX_TIM2_Init();
 /* USER CODE BEGIN 2 */
 uint32_t colour = 0x347235; // colour code for some color
 WS2812_Send(colour);
 
 
 while (1)
 {
 
 }
 
 /* USER CODE END 2 */
 
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 
 /* USER CODE END 3 */
}

and this is result on pin PA0 (TIM2_Ch1):

0693W00000NpCnxQAF.pngIs there anythin I am missing or is this FW issue?

Remy ISSALYS
Technical Moderator
May 11, 2022
LZure.1
LZure.1Author
Associate
May 25, 2022

Hello Remy,

I have check this link and it would be great example however its based on LL not HAL. My problem is more related to HAL library.

Best regards

LZure.1
LZure.1Author
Associate
May 30, 2022

Do you have any other examples I could base on? I can debug it but I need example using HAL driver.

Remy ISSALYS
Technical Moderator
June 3, 2022

Hello,

Maybe this code or this video can help you.

Best Regards

Senior
March 21, 2024

you can use my packet. 

https://github.com/nimaltd/ws28xx