cancel
Showing results for 
Search instead for 
Did you mean: 

NucleoF103, CubeMX HAL, PWM Out Tim3CH1

aal1
Associate II
Posted on May 04, 2016 at 22:50

hi

im working on a project to drive a WS2812B led string.

i use TIM1 as time source and TIM3 for the PWM generation.

im so far able to achieve a PWM signal @ 800kHz.

For testing, i tried (see stm32f1xx_it.c) to drive the first 3 leds in the led string (24bit per led), therefore, send 3x 0x555555 (3x24bit). i get a 0-1-0-1... data out by using the 

HAL_TIM_PWM_PulseFinishedCallback function. but unfortunately, after 3x24 times calling the callback, the output sent way more than these 3x24 pulses, since way more than 3 leds are turned on.

is it possible that it is not possible, after each pulse to stop the timer and pwm, set the CCR register and then start it again?

#no-hablo-hal #no-hablo-hal
9 REPLIES 9
aal1
Associate II
Posted on May 05, 2016 at 00:49

The device is not going to be able to sustain an 800KHz interrupt rate. You will need to create a pulse width table, and use DMA to update the timer at the end of each interval. A table with 100 values would reduce the interrupt rate to 8KHz

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Walid FTITI_O
Senior II
Posted on May 05, 2016 at 19:16

Hi am.lu,

Yes you can do that either by Timer's DMA burst r by synchronizing two timers. I think Timer chaning is easier:

As I understand your need to output periodic N pulses (N =3).

To do that,

you Interconnect two timer peripherals peripheral TIM1 and TIM2. TIM1 timer peripheral will generate a PWM signal by a T1_on duty cycle programmed in TIM1_CCR1 and T1 period programmed in TIM1_ARR. TIM2 timer peripheral will ensure that the period of each generation cycle is equal to T2 which is programmed in its TIM2_ARR register.

The TIM2 peripheral timer is configured as master trigger mode to trig the TIM1 peripheral timer input ITR1 via its internal TRGO signal, each update event. The time between two Update Events is the T2 of the waveform targeted.

The TIM1 peripheral timer is configured as slave one pulse (OPM) mode, to generate one pulse when triggered by TIM2 timer peripheral.

In fact, when a rising edge occurs on the trigger input (ITR1) the counter starts up-counting for only one time until it matches the configure period (TIM1_CCR1) equal to 1/F1 and then an UEV occurs. To repeat the pulse generated (the up-counting), we use the repetition counter of TIM1 timer peripheral which we configure to the number of of pulses per the on-going signal waveform portion minus one (i.e. TIM1_RCR = Number_of_pluses_per_portion – 1 = 3-1 ). So, the UEV is only generated after up-counting is repeated for a number of time configured TIM1_RCR +1.

D’ont forget to enable the UEV (by setting UG bit) before ena bling TIM1 to avoid any delay on the generating the first pulse.

Try to apply my recommendation and come back if you face any problems in coding.

-Hannibal-

aal1
Associate II
Posted on May 06, 2016 at 13:13

@clive

what i still dont get, if you say a 800kHz interrupt on the timer callback is way to high and i use DMA instead, how do you start the dma transfer after each period? the timer IT still needs to start the DMA transfer at 800kHz??
aal1
Associate II
Posted on May 06, 2016 at 13:16

hello hannibal, thanks for the suggestions as an alternative for the DMA solution.

I really would like to learn to use the DMAs correctly anyway. so im going first to get to this solution. but as soon as i will use your solution, i hope you can help me then to set up the project using the CubeMX software.

aal1
Associate II
Posted on May 06, 2016 at 13:35

@clive: here my idea:

 

1.) i set up the timer @ 800khz, pulse 0

/* TIM3 init function */

void MX_TIM3_Init(void)

{

  TIM_MasterConfigTypeDef sMasterConfig;

  TIM_OC_InitTypeDef sConfigOC;

  htim3.Instance = TIM3;

  htim3.Init.Prescaler = 0;

  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;

  htim3.Init.Period = 89;

  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

  HAL_TIM_PWM_Init(&htim3);

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;

  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

  HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig);

  sConfigOC.OCMode = TIM_OCMODE_PWM1;

  sConfigOC.Pulse = 0;

  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;

  sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;

  HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);

  HAL_TIM_MspPostInit(&htim3);

}

2.) cubeMX implements the DMA end of transfer callback routine

/**

  * Enable DMA controller clock

  */

void MX_DMA_Init(void)

{

  /* DMA controller clock enable */

  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */

  /* DMA1_Channel3_IRQn interrupt configuration */

  HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 2, 0);

  HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);

}

3.) initialization

  /* Initialize all configured peripherals */

  MX_GPIO_Init();

  MX_DMA_Init();

  MX_RTC_Init();

  MX_TIM3_Init();

4.) start the services as follows:

HAL_TIM_Base_Start

HAL_TIM_PWM_Start

HAL_TIM_PWM_Start_IT

HAL_DMA_Start

HAL_DMA_Start_IT

5.) application

im now able to start the first DMA transfer with the function:

HAL_TIM_DMABurst_WriteStart??

then, im going to ignore the DMA end of transfer callback:

DMA1_Channel3_IRQHandler

and with the Timer callback:

TIM3_IRQHandler

im going to start the DMA transfer all over again with the next pulse with??

HAL_TIM_DMABurst_WriteStart??

is this what i need to do?
Posted on May 06, 2016 at 15:11

what i still dont get, if you say a 800kHz interrupt on the timer callback is way to high and i use DMA instead, how do you start the dma transfer after each period? the timer IT still needs to start the DMA transfer at 800kHz??

The point of using DMA is that is serves the next 10 or 100 update events from a list of parameters, and in so doing decimates the interrupt loading to a point the CPU can actually function.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
aal1
Associate II
Posted on May 07, 2016 at 13:40

so, could you correct me when im wrong:

1.) i start the timer timebase:

HAL_TIM_Base_Start()

2.) i start the PWM via DMA:

HAL_TIM_PWM_Start_DMA()

3.) when the DMA callback is reached, this means, i already had 100 periods on the output:

HAL_DMA_IRQHandler()

thats all im going to do?

what about HAL_TIM_PWM_Start()? is this automatically started when i start the HAL_TIM_PWM_Start_DMA()?

what about HAL_DMA_Start_IT?? is this not even necessary to start up?

Posted on May 07, 2016 at 16:45

so, could you correct me when im wrong:

I'm not a HAL coder, so I'm not wading into coding issues with it, I have in the past posted several SPL based examples for different STM32 to output to this LED driver, and also ones where I modulate the TIM/PWM using a DMA driving table.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..