Skip to main content
VMoca.1
Associate II
February 5, 2020
Solved

STM32F769 PWM using DMA on two channels PA2 and PA3 issue

  • February 5, 2020
  • 9 replies
  • 5191 views

Hello,

I have an issue with using two channels of DMA to generate the PWM on PA2 and PA3 pins.

I configured using CubeMX TIM2 PWM Generation CH3 and CH4.

I have added the DMA memory to peripheral for PA2 DMA1Stream1 and for PA3 DMA1Stream6.

The issue I have is that only the DMA1_Stream1_IRQHandler is called and only the PA2 PWM generation is done. DMA1_Stream6_IRQHandler is never called.

This is what I use to test PA3 pin.

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)

{

 GPIO_InitTypeDef  GPIO_InitStruct1;

 GPIO_InitTypeDef  GPIO_InitStruct2;

 static DMA_HandleTypeDef hdma_tim1;

 static DMA_HandleTypeDef hdma_tim2;

 /*##-1- Enable peripherals and GPIO Clocks #################################*/

 /* TIMx clock enable */

 TIMx_CLK_ENABLE();

 /* Enable GPIO Channel3/3N Clocks */

 TIMx_CHANNEL3_GPIO_CLK_ENABLE(); /* PA2 and PA3 */

 /* Enable DMA clock */

 DMAx_CLK_ENABLE();

   /* Configure TIM2_Channel3 in output, push-pull & alternate function mode */

   GPIO_InitStruct1.Pin = GPIO_PIN_CHANNEL4; /*  PA3 */

   GPIO_InitStruct1.Mode = GPIO_MODE_AF_PP;

   GPIO_InitStruct1.Pull = GPIO_PULLUP;

   GPIO_InitStruct1.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

   GPIO_InitStruct1.Alternate = GPIO_AF1_TIM2;

   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct1);

   /* Set the parameters to be configured */

   hdma_tim1.Init.Channel = DMA_CHANNEL_4; /* PA3 TIM2_CH4 */

   hdma_tim1.Init.Direction = DMA_MEMORY_TO_PERIPH;

   hdma_tim1.Init.PeriphInc = DMA_PINC_DISABLE;

   hdma_tim1.Init.MemInc = DMA_MINC_ENABLE;

   hdma_tim1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD ;

   hdma_tim1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD ;

   hdma_tim1.Init.Mode = DMA_CIRCULAR;

   hdma_tim1.Init.Priority = DMA_PRIORITY_HIGH;

   hdma_tim1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;

   hdma_tim1.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;

   hdma_tim1.Init.MemBurst = DMA_MBURST_SINGLE;

   hdma_tim1.Init.PeriphBurst = DMA_PBURST_SINGLE;

   /* Set hdma_tim instance */

   hdma_tim1.Instance = DMA1_Stream6;

   /* Link hdma_tim to hdma[TIM_DMA_ID_CC4] (channel4) */

   __HAL_LINKDMA(htim, hdma[TIM_DMA_ID_CC4], hdma_tim1);

   /* Initialize TIMx DMA handle */

   HAL_DMA_Init(htim->hdma[TIM_DMA_ID_CC4]);

   /* ##-2- Configure the NVIC for DMA ######################################### */

   /* NVIC configuration for DMA transfer complete interrupt */

   HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 0, 0);

   HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);

}

This is the function to set-up the values to send on PWM in the main() with parameter 20000u corresponding to 20KHz.

void DMA_Config2(uint32_t DmaFreq)

{

   uint8_t idx = 0U;

    /* Load buffer for DMA */

    for (idx = 0; idx < DMA_PWM_MAX_BUF; idx++)

    {

       /* Compute CCR1 value to generate a duty cycle [%] */

       aCCValue_Buffer_right[idx] = (uint32_t)(((uint32_t) (100-idx) * (uwTimerPeriod - 1)) / 100);

    }

   /*##-1- Initialise Timer settings ##########################################*/

   TimHandle2.Instance = TIM2;

   TimHandle2.Init.Period           = uwTimerPeriod;

   TimHandle2.Init.RepetitionCounter = 1;

   TimHandle2.Init.Prescaler        = 0;

   TimHandle2.Init.ClockDivision    = 0;

   TimHandle2.Init.CounterMode      = TIM_COUNTERMODE_UP;

   TimHandle2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

   if (HAL_TIM_PWM_Init(&TimHandle2) != HAL_OK)

   {

    /* Initialization Error */

    Error_Handler();

   }

   /*##-2- Configure the PWM channel 3 ########################################*/

   sConfig2.OCMode      = TIM_OCMODE_PWM1;

   sConfig2.OCPolarity  = TIM_OCPOLARITY_HIGH;

   sConfig2.Pulse       = aCCValue_Buffer_right[0];

   sConfig2.OCNPolarity = TIM_OCNPOLARITY_HIGH;

   sConfig2.OCFastMode  = TIM_OCFAST_DISABLE;

   sConfig2.OCIdleState = TIM_OCIDLESTATE_RESET;

   sConfig2.OCNIdleState = TIM_OCNIDLESTATE_RESET;

   if (HAL_TIM_PWM_ConfigChannel(&TimHandle2, &sConfig2, TIM_CHANNEL_4) != HAL_OK) /* PA3 */

   {

    /* Configuration Error */

    Error_Handler();

   }

   /*##-3- Start PWM signal generation in DMA mode ##############################*/

   if (HAL_TIM_PWM_Start_DMA(&TimHandle2, TIM_CHANNEL_4, aCCValue_Buffer_right, DMA_PWM_MAX_BUF) != HAL_OK) /* PA3 */

   {

    /* Starting Error */

    Error_Handler();

   }

}

This topic has been closed for replies.
Best answer by Imen GH

​Hello,

You will find attached my file STM32f7xx_hal_msp.c

The contents of this file was automatically generated ( I didn't add or change anything )

Regards

9 replies

waclawek.jan
Super User
February 5, 2020

I don't speak the Cube/HAL gobbledygook, but

   /* Set the parameters to be configured */

   hdma_tim1.Init.Channel = DMA_CHANNEL_4; /* PA3 TIM2_CH4 */

is IMO incorrect, I believe you want to set the channel in given stream in DMA, corresponding to given trigger from TIM, ie.

0690X00000Bycj8QAB.png

Reading out and checking the DMA registers is always the ultimate way to find out what the mcu is actually doing.

JW

VMoca.1
VMoca.1Author
Associate II
February 6, 2020

I have changed like suggested and the IRQ is still not called.

waclawek.jan
Super User
February 6, 2020

Read out and check/post the TIM and DMA registers content.

JW

VMoca.1
VMoca.1Author
Associate II
February 6, 2020

TIM2

VMoca.1
VMoca.1Author
Associate II
February 6, 2020

As I see in HAL_TIM_Base_MspInit() i get a warning

/* Several peripheral DMA handle pointers point to the same DMA handle.

    Be aware that there is only one stream to perform all the requested DMAs. */

I am trying to set-up two DMAs on PA2 and 3 which are both on DMA1 Channel 3 and only the stream is different (Stream1 for PA2 and Stream6 on PA3).

See code below

if(tim_baseHandle->Instance==TIM2)

 {

 /* USER CODE BEGIN TIM2_MspInit 0 */

 /* USER CODE END TIM2_MspInit 0 */

   /* TIM2 clock enable */

   __HAL_RCC_TIM2_CLK_ENABLE();

   /* TIM2 DMA Init */

   /* TIM2_UP_CH3 Init */

   hdma_tim2_up_ch3.Instance = DMA1_Stream1;

   hdma_tim2_up_ch3.Init.Channel = DMA_CHANNEL_3;

   hdma_tim2_up_ch3.Init.Direction = DMA_MEMORY_TO_PERIPH;

   hdma_tim2_up_ch3.Init.PeriphInc = DMA_PINC_DISABLE;

   hdma_tim2_up_ch3.Init.MemInc = DMA_MINC_ENABLE;

   hdma_tim2_up_ch3.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;

   hdma_tim2_up_ch3.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;

   hdma_tim2_up_ch3.Init.Mode = DMA_NORMAL;

   hdma_tim2_up_ch3.Init.Priority = DMA_PRIORITY_LOW;

   hdma_tim2_up_ch3.Init.FIFOMode = DMA_FIFOMODE_ENABLE;

   hdma_tim2_up_ch3.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;

   hdma_tim2_up_ch3.Init.MemBurst = DMA_MBURST_SINGLE;

   hdma_tim2_up_ch3.Init.PeriphBurst = DMA_PBURST_SINGLE;

   if (HAL_DMA_Init(&hdma_tim2_up_ch3) != HAL_OK)

   {

     Error_Handler();

   }

   /* Several peripheral DMA handle pointers point to the same DMA handle.

    Be aware that there is only one stream to perform all the requested DMAs. */

   __HAL_LINKDMA(tim_baseHandle,hdma[TIM_DMA_ID_UPDATE],hdma_tim2_up_ch3);

   __HAL_LINKDMA(tim_baseHandle,hdma[TIM_DMA_ID_CC3],hdma_tim2_up_ch3);

   /* TIM2_CH2_CH4 Init */

   hdma_tim2_ch2_ch4.Instance = DMA1_Stream6;

   hdma_tim2_ch2_ch4.Init.Channel = DMA_CHANNEL_3;

   hdma_tim2_ch2_ch4.Init.Direction = DMA_MEMORY_TO_PERIPH;

   hdma_tim2_ch2_ch4.Init.PeriphInc = DMA_PINC_DISABLE;

   hdma_tim2_ch2_ch4.Init.MemInc = DMA_MINC_ENABLE;

   hdma_tim2_ch2_ch4.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;

   hdma_tim2_ch2_ch4.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;

   hdma_tim2_ch2_ch4.Init.Mode = DMA_NORMAL;

   hdma_tim2_ch2_ch4.Init.Priority = DMA_PRIORITY_LOW;

   hdma_tim2_ch2_ch4.Init.FIFOMode = DMA_FIFOMODE_ENABLE;

   hdma_tim2_ch2_ch4.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;

   hdma_tim2_ch2_ch4.Init.MemBurst = DMA_MBURST_SINGLE;

   hdma_tim2_ch2_ch4.Init.PeriphBurst = DMA_PBURST_SINGLE;

   if (HAL_DMA_Init(&hdma_tim2_ch2_ch4) != HAL_OK)

   {

     Error_Handler();

   }

   /* Several peripheral DMA handle pointers point to the same DMA handle.

    Be aware that there is only one stream to perform all the requested DMAs. */

   __HAL_LINKDMA(tim_baseHandle,hdma[TIM_DMA_ID_CC2],hdma_tim2_ch2_ch4);

   __HAL_LINKDMA(tim_baseHandle,hdma[TIM_DMA_ID_CC3],hdma_tim2_ch2_ch4);

}

}

waclawek.jan
Super User
February 6, 2020

/* Several peripheral DMA handle pointers point to the same DMA handle.

    Be aware that there is only one stream to perform all the requested DMAs. */

Okay, so this may be a Cube/HAL limitation.

Ditch Cube, go for the registers.

JW

VMoca.1
VMoca.1Author
Associate II
February 7, 2020

​Hello,

I have managed to set-up the desired PA3 to use DMA but only with Steam7.

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)

{

GPIO_InitTypeDef GPIO_InitStruct;

static DMA_HandleTypeDef hdma_tim; 

/* Configure TIM2_Channel3 in output, push-pull & alternate function mode */

GPIO_InitStruct.Pin = GPIO_PIN_3; /* PA3 */

GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

GPIO_InitStruct.Pull = GPIO_PULLUP;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;

HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

/* Set the parameters to be configured on DMA */

hdma_tim.Init.Channel = DMA_CHANNEL_3; /*PA2 and PA3 have the same channel*/

hdma_tim.Init.Direction = DMA_MEMORY_TO_PERIPH;

hdma_tim.Init.PeriphInc = DMA_PINC_DISABLE;

hdma_tim.Init.MemInc = DMA_MINC_ENABLE;

hdma_tim.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD ;

hdma_tim.Init.MemDataAlignment = DMA_MDATAALIGN_WORD ;

hdma_tim.Init.Mode = DMA_CIRCULAR;

hdma_tim.Init.Priority = DMA_PRIORITY_HIGH;

hdma_tim.Init.FIFOMode = DMA_FIFOMODE_DISABLE;

hdma_tim.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;

hdma_tim.Init.MemBurst = DMA_MBURST_SINGLE;

hdma_tim.Init.PeriphBurst = DMA_PBURST_SINGLE;

/* Set hdma_tim instance */

hdma_tim.Instance = DMA1_Stream7; 

/* Link hdma_tim to hdma[TIM_DMA_ID_CC4] (channel3) */

__HAL_LINKDMA(htim, hdma[TIM_DMA_ID_CC4], hdma_tim);

/* Initialize TIMx DMA handle */

HAL_DMA_Init(htim->hdma[TIM_DMA_ID_CC4]); 

/*##-2- Configure the NVIC for DMA #########################################*/

/* NVIC configuration for DMA transfer complete interrupt */

HAL_NVIC_SetPriority(DMA1_Stream7_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(DMA1_Stream7_IRQn);

}

and

void DMA_Config(uint32_t DmaFreq)

{

uint8_t idx = 0U;

/* Compute the value of ARR regiter to generate signal frequency at 20.00 Khz */

uwTimerPeriod = (uint32_t)(((SystemCoreClock/2) / DmaFreq) - 1);

/* Load buffer for DMA */

for (idx=0; idx < DMA_PWM_MAX_BUF; idx++)

{

/* Compute CCR1 value to generate a duty cycle [%] */

aCCValue_Buffer_left[idx] = (uint32_t)(((uint32_t) idx * (uwTimerPeriod - 1)) / 100);

}

/*##-1- Initialise Timer settings ##########################################*/

TimHandle.Instance = TIM2;

TimHandle.Init.Period = uwTimerPeriod;

TimHandle.Init.RepetitionCounter = 1;

TimHandle.Init.Prescaler = 0;

TimHandle.Init.ClockDivision = 0;

TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;

TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)

{

/* Initialization Error */

Error_Handler();

}

/*##-2- Configure the PWM channel 3 ########################################*/

sConfig.OCMode = TIM_OCMODE_PWM1;

sConfig.OCPolarity = TIM_OCPOLARITY_HIGH;

sConfig.Pulse = aCCValue_Buffer_left[0];

sConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH;

sConfig.OCFastMode = TIM_OCFAST_DISABLE;

sConfig.OCIdleState = TIM_OCIDLESTATE_RESET;

sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;

if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_4) != HAL_OK) /* PA3 */

{

/* Configuration Error */

Error_Handler();

}

/*##-3- Start PWM signal generation in DMA mode ##############################*/

if (HAL_TIM_PWM_Start_DMA(&TimHandle, TIM_CHANNEL_4, aCCValue_Buffer_left, DMA_PWM_MAX_BUF) != HAL_OK) /* PA2 */

{

/* Starting Error */

Error_Handler();

}

}

VMoca.1
VMoca.1Author
Associate II
February 7, 2020

​I will try to merge the PA2 and PA3 implementation next.

Thank you for your support

VMoca.1
VMoca.1Author
Associate II
February 7, 2020

The CubeMX is blocking selecting both CH3 TIM2_CH3 (Stream1) and CH​4 TIM2_CH3(Stream7)...

waclawek.jan
Super User
February 7, 2020

> I have managed to set-up the desired PA3 to use DMA but only with Steam7.

Oh, that's an unexpected twist.

Do you use also CH2 on that timer for DMA?

JW

Imen GH
ST Employee
February 14, 2020

Hello,

I succeeded to generate PWM using DMA for both TIM2 channels on PA2 and PA3.

You find attached the compiled code I used.

0690X00000DAe2JQAT.png

VMoca.1
VMoca.1Author
Associate II
February 17, 2020

Hello,

I cannot find the HAL_TIM_PWM_Init() and HAL_TIM_MspPostInit() functions content from your configuration.

Is it possible to send me this file two?

Thank you.

Imen GH
Imen GHBest answer
ST Employee
February 21, 2020

​Hello,

You will find attached my file STM32f7xx_hal_msp.c

The contents of this file was automatically generated ( I didn't add or change anything )

Regards

VMoca.1
VMoca.1Author
Associate II
February 21, 2020

​Ok, thank you. It works now. I have used different variables in the code (initiated in tim.c with a name and used it in DMA_Config, another variable) and it was not the same addresses :D

Now it is working.