cancel
Showing results for 
Search instead for 
Did you mean: 

Understanding TIM DMA_Handle_index

Posted on June 27, 2017 at 15:02

Hi.

I'm trying to use DMA to  drive PWM output for led effects. MCU write seems to be OK, however there's few very weird consepts related to DMA configuration I don't seem to be able to wrap my head around.

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)

{

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

/* TIMx clock enable */

/* Enable DMA2 clock */

DMAx_CLK_ENABLE

/*♯♯-3- Configure the DMA stream ♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯*/

/* Set the parameters to be configured */

hdma_tim.Init.Channel = DMA_CHANNEL_CC3;

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_NORMAL;

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 = TIMx_CC3_DMA_STREAM;

/* Link hdma_tim to hdma[TIM_DMA_ID_UPDATE] update mode? */

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

/* Initialize TIMx DMA handle */

HAL_DMA_Init(htim->hdma[TIM_DMA_ID_UPDATE]);

/*♯♯-4- Configure the NVIC for DMA ♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯*/

/* NVIC configuration for DMA transfer complete interrupt */

HAL_NVIC_SetPriority(TIMx_DMA_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(TIMx_DMA_IRQn);

}

The link/initialize DMA uses the hdma array inside the TIM_HandleTypeDef. In the struct definition there's comment that array should be accessed via DMA_Handle_index. These are:

/** @defgroup DMA_Handle_index DMA Handle index

* @{

*/

&sharpdefine TIM_DMA_ID_UPDATE ((uint16_t) 0x0000U) /*!< Index of the DMA handle used for Update DMA requests */

&sharpdefine TIM_DMA_ID_CC1 ((uint16_t) 0x0001U) /*!< Index of the DMA handle used for Capture/Compare 1 DMA requests */

&sharpdefine TIM_DMA_ID_CC2 ((uint16_t) 0x0002U) /*!< Index of the DMA handle used for Capture/Compare 2 DMA requests */

&sharpdefine TIM_DMA_ID_CC3 ((uint16_t) 0x0003U) /*!< Index of the DMA handle used for Capture/Compare 3 DMA requests */

&sharpdefine TIM_DMA_ID_CC4 ((uint16_t) 0x0004U) /*!< Index of the DMA handle used for Capture/Compare 4 DMA requests */

&sharpdefine TIM_DMA_ID_COMMUTATION ((uint16_t) 0x0005U) /*!< Index of the DMA handle used for Commutation DMA requests */

&sharpdefine TIM_DMA_ID_TRIGGER ((uint16_t) 0x0006U) /*!< Index of the DMA handle used for Trigger DMA requests */

I've tried to link this info somehow to registers in reference manual for both DMA and TIM2, however I cannot make any sense to this. What should I use? What are these?

I'm using TIM2 channel 2 so it should be DMA1 stream 6. The used GPIO pin is PA1.

#dma #pwm #stm32f469
1 ACCEPTED SOLUTION

Accepted Solutions
Posted on June 28, 2017 at 15:07

As I've said I don't and won't Cube, but I'd expect TIM_CHANNEL_2 means 'use TIMx_CH2', implying TIMx_CCR2 as the target register.

A textual search for 'HAL_TIM_PWM_Start_DMA' in CubeF4 returned me 10 projects (one per board, presumably all very similar), e.g. [STM32Cube_FW_F4_V1.15.0]\Projects\STM32F413ZH-Nucleo\Examples\TIM\TIM_DMA. The readme.txt says,

This example provides a description of how to use DMA with TIMER Update request

to transfer Data from memory to TIMER Capture Compare Register 3 (TIMx_CCR3).

JW

View solution in original post

8 REPLIES 8
Posted on June 27, 2017 at 15:16

I've tried to link this info somehow to registers in reference manual for both DMA and TIM2, however I cannot make any sense to this. What should I use? What are these?

Bit indexes in TIMx_DIER, offset by -8.

JW

Posted on June 27, 2017 at 15:29

 ,

 ,

Wow, what a fast reply Batman!

Does this have any dependency to used OC mode (TIM_OCMODE_PWM1)? , My code is based on TIM_PWMOutput example.

void TIM_TIMER_Init(void) {

/* Enable clock for TIM2 */

 ,

__HAL_RCC_TIM2_CLK_ENABLE(),

 ,

/*

 ,

TIM2 is connected to APB1 bus, which has on F469 device 16MHz clock

Remember: Not each timer is connected to APB1, there are also timers connected

 ,

on APB2, which works at 16MHz by default, and internal PLL increase

 ,

this to up to 32MHz

PWM_frequency = timer_tick_frequency / (TIM_Period + 1)

TIM_Period = timer_tick_frequency / PWM_frequency - 1

In our case, for 10Khz PWM_frequency, set Period to

TIM_Period = 16000000 / 60 - 1 = 266665

*/

 ,

TimHandle.Instance = TIM2,

TimHandle.Init.Period = 266666 - 1, /*60hz*/

 ,

TimHandle.Init.Prescaler = (uint32_t)(SystemCoreClock / 16000000) - 1,

 ,

TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP,

 ,

TimHandle.Init.RepetitionCounter = 1,

 ,

TimHandle.Init.ClockDivision = 0,

uwPulse1 = (5 * TimHandle.Init.Period) / 10,

/* Initialize TIM2 */

 ,

if (HAL_TIM_Base_Init(&,TimHandle) != HAL_OK){

 ,

printf('TIM2 init failed \r\n'),

 ,

}

 ,

}

void TIM_PWM_Init(void) {

 ,

TIM_OC_InitTypeDef sPWMConfig,

 ,

/* ♯ ♯ -2- Configure the PWM channels ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ */

 ,

/* Common configuration for all channels */

 ,

sPWMConfig.OCMode = TIM_OCMODE_PWM1,

 ,

sPWMConfig.OCFastMode = TIM_OCFAST_DISABLE,

 ,

sPWMConfig.OCPolarity = TIM_OCPOLARITY_LOW,

 ,

sPWMConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH,

 ,

sPWMConfig.OCIdleState = TIM_OCIDLESTATE_RESET,

 ,

sPWMConfig.OCNIdleState= TIM_OCNIDLESTATE_RESET,

 ,

/* Set the pulse value for channel 1 */

 ,

sPWMConfig.Pulse = uwPulse1,

 ,

if (HAL_TIM_PWM_Init(&,TimHandle) != HAL_OK) {

 ,

/* Configuration Error */

 ,

printf('PWM init error \r\n'),

 ,

}

if(HAL_TIM_PWM_ConfigChannel(&,TimHandle, &,sPWMConfig, TIM_CHANNEL_2) != HAL_OK){

 ,

/* Configuration Error */

 ,

printf('PWM configchannel error \r\n'),

 ,

}

 ,

/* ♯ ♯ -3- Start PWM signals generation ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ ♯ */

 ,

/* Start channel 1 */

 ,

if(HAL_TIM_PWM_Start(&,TimHandle, TIM_CHANNEL_2) != HAL_OK)

 ,

{

 ,

/* Starting Error */

 ,

printf('PWM start error \r\n'),

 ,

}

 ,

TimHandle.Instance->,CCR1 = uwPulse1,

}

Posted on June 27, 2017 at 15:49

Does this have any dependency to used OC mode (TIM_OCMODE_PWM1)?

Should not. Sorry, I don't speak the Cube gibberish.

JW

Posted on June 28, 2017 at 09:25

Ok. Any ideas which DMA should if use from that array? I don't quite get the modes described. With non-DMA solution I just wrote the 32 bit value (fraction of TimHandle.Init.Period as defined in TIM_TIMER_Init above) to CCR1 register.

Posted on June 28, 2017 at 13:51

Use UPDATE as the DMA trigger, and then DMA upon every timer overflow transfers a new value from memory to CCR1.

JW

Posted on June 28, 2017 at 14:19

Is there any examples related to that?

The current configuration (as seen above) is pretty much as you described, however scope shows constant 50:50 duty cycle and I don't get any EoD callbacks. Or am I missing something here? When triggering the DMA I just call

HAL_TIM_PWM_Start_DMA(&TimHandle, TIM_CHANNEL_2, from, amount);

I mean there's no configuration for the target register anywhere (the CCR1 that I used to write directly).

Posted on June 28, 2017 at 15:07

As I've said I don't and won't Cube, but I'd expect TIM_CHANNEL_2 means 'use TIMx_CH2', implying TIMx_CCR2 as the target register.

A textual search for 'HAL_TIM_PWM_Start_DMA' in CubeF4 returned me 10 projects (one per board, presumably all very similar), e.g. [STM32Cube_FW_F4_V1.15.0]\Projects\STM32F413ZH-Nucleo\Examples\TIM\TIM_DMA. The readme.txt says,

This example provides a description of how to use DMA with TIMER Update request

to transfer Data from memory to TIMER Capture Compare Register 3 (TIMx_CCR3).

JW

Posted on June 29, 2017 at 08:12

Thanks again!

This was my bad. I searched my older fw yesterday, but apparently I made a typo as I didn't find then any references to _PWM_Start_DMA :/.

And man (and woman) definitely have to have principles!