Author Topic: PWM output on STM32  (Read 10986 times)

0 Members and 1 Guest are viewing this topic.

Offline Udayan SinhaTopic starter

  • Regular Contributor
  • *
  • Posts: 71
PWM output on STM32
« on: November 22, 2015, 09:23:16 pm »
I am new to ARM MCUs and I have been trying to find my way around the peripherals using STM's HAL library and STM32Cube. I am having trouble in getting the PWM output to work. Here, I'm trying dim an LED (connected to PA6) on the STM32L100 Discovery Board by using the channel-1 PWM output of timer-3 at 50% duty cycle.
However, the LED doesn't turn on at all. I tried using the in-circuit debugging feature and it appears that the timer is not getting configured at all (despite the fact that I initialized it using HAL_TIM_PWM_Init()).  :-// Any help would be appreciated. My main.c source code is attached below.

Line-96: main()
Line-148: Clock settings
Line-396: Timer Initialization routine
Line-463: GPIO Initialization routine

There are initialization functions for various other peripherals in the source file but I'm not using any of them right now. Jut timer and GPIO. I have used PWM features before on 8-bit MCUs like PICs, but the PICs that I used didn't have auto-reload features on their timer and hence, I had to use timer overflow interrupts to load back the timer register. However, timer-3 here has auto-reload and so I was unsure of whether I need interrupts. I tried looking up some example codes online and none of them seem to be using interrupts either.
 

Offline richardman

  • Frequent Contributor
  • **
  • Posts: 427
  • Country: us
Re: PWM output on STM32
« Reply #1 on: November 22, 2015, 09:40:44 pm »
I am new to ARM MCUs and I have been trying to find my way around the peripherals using STM's HAL library and STM32Cube. I am having trouble in getting the PWM output to work. Here, I'm trying dim an LED (connected to PA6) on the STM32L100 Discovery Board by using the channel-1 PWM output of timer-3 at 50% duty cycle.
However, the LED doesn't turn on at all. I tried using the in-circuit debugging feature and it appears that the timer is not getting configured at all (despite the fact that I initialized it using HAL_TIM_PWM_Init()).  :-// Any help would be appreciated. My main.c source code is attached below.

Line-96: main()
Line-148: Clock settings
Line-396: Timer Initialization routine
Line-463: GPIO Initialization routine

There are initialization functions for various other peripherals in the source file but I'm not using any of them right now. Jut timer and GPIO. I have used PWM features before on 8-bit MCUs like PICs, but the PICs that I used didn't have auto-reload features on their timer and hence, I had to use timer overflow interrupts to load back the timer register. However, timer-3 here has auto-reload and so I was unsure of whether I need interrupts. I tried looking up some example codes online and none of them seem to be using interrupts either.

I just got that working on JumpStart API. This is what you need to do using JumpStart API:

Code: [Select]
   timer1.SetPinsForPWM(&porta, 8, 2);
   timer1.MakePWM(1, 30);

Set up timer 1 to emit a 1 Hz PWM with 30% duty cycle on PA8. Simple eh?

Anyway, all the examples I found on the web is missing one crucial bit of set up: I do not know how they get their LED to blink at all, but on both the F030 and the F401 boards, I need to enable MOE to get the signal output. I'm allergic to look at HAL/STPeriphLib code, so I don't know what else may be missing in your code, but if you don't have MOE enable - no signal, from my experience.
// richard http://imagecraft.com/
JumpStart C++ for Cortex (compiler/IDE/debugger): the fastest easiest way to get productive on Cortex-M.
Smart.IO: phone App for embedded systems with no app or wireless coding
 

Offline MT

  • Super Contributor
  • ***
  • Posts: 1616
  • Country: aq
Re: PWM output on STM32
« Reply #2 on: November 23, 2015, 12:11:47 am »
Quote
I am new to ARM MCUs and I have been trying to find my way around the peripherals using STM's HAL library and STM32Cube.
What about direct register writing instead? You save RAM and increase execution speed .


Code: [Select]
   timer1.SetPinsForPWM(&porta, 8, 2);
   timer1.MakePWM(1, 30);
Set up timer 1 to emit a 1 Hz PWM with 30% duty cycle on PA8. Simple eh?
Yes its simple  neat and tidy just as it should be but how much code is behind those functions compared to ST SPL? just wondering.

Quote
Anyway, all the examples I found on the web is missing one crucial bit of set up: I do not know how they get their LED to blink at all, but on both the F030 and the F401 boards, I need to enable MOE to get the signal output. I'm allergic to look at HAL/STPeriphLib code, so I don't know what else may be missing in your code, but if you don't have MOE enable - no signal, from my experience.

TIM1->BDTR |= TIM_BDTR_MOE;       //Enable output stage, OBS! Only ADV timers have BDTR MOE
« Last Edit: November 23, 2015, 12:31:26 am by MT »
 

Offline richardman

  • Frequent Contributor
  • **
  • Posts: 427
  • Country: us
Re: PWM output on STM32
« Reply #3 on: November 23, 2015, 02:12:38 am »

Code: [Select]
   timer1.SetPinsForPWM(&porta, 8, 2);
   timer1.MakePWM(1, 30);


A LOT LESS than ST'lib. Here's the complete code:

Code: [Select]
void JSAPI_TIMER::MakePWM(unsigned Hz, unsigned duty_cycle_percent)
    {
    this->MakeTimer(Hz, 0, 0);
    this->Disable();

    TIM_TypeDef *TIMx = ((struct _timer *)(this->vp))->base;
    unsigned tmpccmrx = 0, tmpccer = 0;

    TIMx->CCER &= ~(TIM_CCER_CC1E|TIM_CCER_CC1P);

    tmpccmrx = TIMx->CCMR1;
    tmpccmrx &= ~(TIM_CCMR1_OC1M|TIM_CCMR1_CC1S);
    tmpccmrx |= TIM_OCMode_PWM1;
    tmpccmrx |= TIM_OCPreload_Enable;
    TIMx->CCMR1 = tmpccmrx;

    TIMx->CCR1 = ((TIMx->ARR+1) * duty_cycle_percent) / 100;
    TIMx->CCER |= TIM_CCER_CC1P;
    TIMx->CCER |= TIM_CCER_CC1E;
    TIMx->BDTR |= TIM_BDTR_MOE;
    this->Enable();
    }
« Last Edit: November 23, 2015, 02:16:25 am by richardman »
// richard http://imagecraft.com/
JumpStart C++ for Cortex (compiler/IDE/debugger): the fastest easiest way to get productive on Cortex-M.
Smart.IO: phone App for embedded systems with no app or wireless coding
 

Offline ralphd

  • Frequent Contributor
  • **
  • Posts: 445
  • Country: ca
    • Nerd Ralph
Re: PWM output on STM32
« Reply #4 on: November 23, 2015, 04:13:14 am »
Does the compiler optimize these into single writes?  If not, would doing it in a single statement help?
TIMx->CCER |= TIM_CCER_CC1P;
    TIMx->CCER |= TIM_CCER_CC1E;
Unthinking respect for authority is the greatest enemy of truth. Einstein
 

Offline richardman

  • Frequent Contributor
  • **
  • Posts: 427
  • Country: us
Re: PWM output on STM32
« Reply #5 on: November 23, 2015, 05:44:38 am »
Does the compiler optimize these into single writes?  If not, would doing it in a single statement help?
TIMx->CCER |= TIM_CCER_CC1P;
    TIMx->CCER |= TIM_CCER_CC1E;

It's not clear to me whether CC1P|CC1E can be written together. The STM32 manuals are sort of unclear. In any case, the way I work is to get it right, then iterate to remove dead wood. So that will happen later...
// richard http://imagecraft.com/
JumpStart C++ for Cortex (compiler/IDE/debugger): the fastest easiest way to get productive on Cortex-M.
Smart.IO: phone App for embedded systems with no app or wireless coding
 

Offline Udayan SinhaTopic starter

  • Regular Contributor
  • *
  • Posts: 71
Re: PWM output on STM32
« Reply #6 on: November 23, 2015, 09:58:39 am »
Appreciate the suggestions guys but I would prefer a HAL-Cube solution mainly because I have already done quite a bit of code on it. I know it just came out last year and is still not adopted widely, but I don't want to switch to some new API now as it would mean transferring my old code too (and I'm on a bit of a deadline right now).

Quote
I am new to ARM MCUs and I have been trying to find my way around the peripherals using STM's HAL library and STM32Cube.
What about direct register writing instead? You save RAM and increase execution speed .


Yes it would be more efficient, it would also be less portable and need me to go through all the documentation to see which registers to program. HAL APIs works on the entire STM32 line. Plus I don't need that efficiency just yet so I don't see the point in doing all the hard work of going through the peripheral documentation and would prefer sticking to HAL (that's the whole point of having an HAL layer; so you don't mess with the registers unless you really need to).
 

Offline AndreasF

  • Frequent Contributor
  • **
  • Posts: 251
  • Country: gb
    • mind-dump.net
Re: PWM output on STM32
« Reply #7 on: November 23, 2015, 04:51:08 pm »
I only had brief look at your code, but I don't see anywhere you're turning on the clock to the timer peripheral itself (similar to the way you do for the GPIOs in MX_GPIO_Init(), e.g.  __GPIOC_CLK_ENABLE(); ). This is different from the input clock sources for the timer! That might explain why your timer doesn't seem to get configured at all.
my random ramblings mind-dump.net
 

Offline MT

  • Super Contributor
  • ***
  • Posts: 1616
  • Country: aq
Re: PWM output on STM32
« Reply #8 on: November 23, 2015, 05:46:43 pm »

A LOT LESS than ST'lib. Here's the complete code:

Indeed, :-+ 
« Last Edit: November 23, 2015, 05:48:14 pm by MT »
 

Offline Udayan SinhaTopic starter

  • Regular Contributor
  • *
  • Posts: 71
Re: PWM output on STM32
« Reply #9 on: November 23, 2015, 05:49:10 pm »
I only had brief look at your code, but I don't see anywhere you're turning on the clock to the timer peripheral itself (similar to the way you do for the GPIOs in MX_GPIO_Init(), e.g.  __GPIOC_CLK_ENABLE(); ). This is different from the input clock sources for the timer! That might explain why your timer doesn't seem to get configured at all.

I did configure the clock (lines 409-410)). Beyond that I don't think there's anything else to do. I have used the timer as a simple time base in the same way and it worked just fine.
 

Offline richardman

  • Frequent Contributor
  • **
  • Posts: 427
  • Country: us
Re: PWM output on STM32
« Reply #10 on: November 23, 2015, 07:40:33 pm »
Did you enable MOE as I suggested?
// richard http://imagecraft.com/
JumpStart C++ for Cortex (compiler/IDE/debugger): the fastest easiest way to get productive on Cortex-M.
Smart.IO: phone App for embedded systems with no app or wireless coding
 

Offline Udayan SinhaTopic starter

  • Regular Contributor
  • *
  • Posts: 71
Re: PWM output on STM32
« Reply #11 on: November 23, 2015, 08:08:15 pm »
Did you enable MOE as I suggested?

MT posted earlier that it's only for advanced timers. I am using a general purpose timer.
 

Offline richardman

  • Frequent Contributor
  • **
  • Posts: 427
  • Country: us
Re: PWM output on STM32
« Reply #12 on: November 23, 2015, 08:27:51 pm »
Would it kill you to try a one-line change and see if it works?
// richard http://imagecraft.com/
JumpStart C++ for Cortex (compiler/IDE/debugger): the fastest easiest way to get productive on Cortex-M.
Smart.IO: phone App for embedded systems with no app or wireless coding
 

Offline MT

  • Super Contributor
  • ***
  • Posts: 1616
  • Country: aq
Re: PWM output on STM32
« Reply #13 on: November 23, 2015, 09:26:56 pm »
Would it kill you to try a one-line change and see if it works?
Dont you trust the hoard of coders at ST and their quality work? :D
But who knows whit ST stranger things have happened!
« Last Edit: November 23, 2015, 09:28:31 pm by MT »
 

Offline Udayan SinhaTopic starter

  • Regular Contributor
  • *
  • Posts: 71
Re: PWM output on STM32
« Reply #14 on: November 23, 2015, 09:32:21 pm »
Would it kill you to try a one-line change and see if it works?

It's a GENERAL PURPOSE TIMER. Doesn't have one. I checked.

I found an example code on PWM for the Nucleo board in the Cube Examples (attached below). They have just done everything that I did to configure the timers. I'm pretty lost now. Don't know what else I can do.  :-//
Think I'm gonna implement the error_handler() and see if any function returns an error. If not, then I have no other conclusion besides that there is a bug in the HAL PWM API  |O
 

Offline MT

  • Super Contributor
  • ***
  • Posts: 1616
  • Country: aq
Re: PWM output on STM32
« Reply #15 on: November 23, 2015, 09:36:01 pm »
Bug in HAL's is not uncommon, sooo it seams that you have to dig into the register definitions to fix this after all! :)
 

Offline Udayan SinhaTopic starter

  • Regular Contributor
  • *
  • Posts: 71
Re: PWM output on STM32
« Reply #16 on: November 23, 2015, 09:39:13 pm »
Bug in HAL's is not uncommon, sooo it seams that you have to dig into the register definitions to fix this after all! :)

You seem pretty happy at prospect of me doing extra work  :rant:
 

Offline MT

  • Super Contributor
  • ***
  • Posts: 1616
  • Country: aq
Re: PWM output on STM32
« Reply #17 on: November 23, 2015, 11:11:49 pm »
Yes! Welcome to the land of ST! :)
« Last Edit: November 23, 2015, 11:20:36 pm by MT »
 

Offline Udayan SinhaTopic starter

  • Regular Contributor
  • *
  • Posts: 71
Re: PWM output on STM32
« Reply #18 on: November 23, 2015, 11:18:25 pm »
Yes! Welcome to the land of ST! :)

Well they (the Discovery boards) can be cheaper than an Arduino   O0
I only need to learn how to use 3 more peripherals: SPI, I2C & DAC. Hopefully that shouldn't be problem. Actually timer is the only peripheral I have had issues with so far.
 

Offline kaadam

  • Contributor
  • Posts: 23
  • Country: hu
Re: PWM output on STM32
« Reply #19 on: November 24, 2015, 06:51:13 am »
Hello!

I bearly checked your code. As far as i noticed, you didn't initialize the PA6 pin at all.

And let me give you some advice. Use separate source files. I know it can be a pain in the ass, but your code will be less clean, and more readable. And yeah, the HAL driver contains bug, but not this ridiculous.
 

Offline crispus

  • Regular Contributor
  • *
  • Posts: 131
  • Country: ro
Re: PWM output on STM32
« Reply #20 on: November 24, 2015, 06:53:29 am »
Hi,

I use STM32 F0 Discovery board and tested PWM on the green LED: timer 3, channel 4.
I generated the code using STM32CubeMX (and I can see you did the same way), but in your code I don't see the PA6 GPIO initialization or __TIMx_CLK_ENABLE:
Code: [Select]
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(htim_base->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspInit 0 */

  /* USER CODE END TIM3_MspInit 0 */
    /* Peripheral clock enable */
    __TIM3_CLK_ENABLE();
 
   /**TIM3 GPIO Configuration   
    PC9     ------> TIM3_CH4
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /* USER CODE BEGIN TIM3_MspInit 1 */

  /* USER CODE END TIM3_MspInit 1 */
  }
}

L.E. I see that it was already answered. You may want to check ChibiOS HAL. It can be used independently, and is much, much cleaner.
« Last Edit: November 24, 2015, 06:56:46 am by crispus »
I know I'm numskull, but I look around me and I feel better.
 

Offline Udayan SinhaTopic starter

  • Regular Contributor
  • *
  • Posts: 71
Re: PWM output on STM32
« Reply #21 on: November 25, 2015, 11:25:12 pm »
Found the bloody problem  :palm:
It seems that depending on whether you configure the timer in Cube for time base, PWM, Capture or Compare, it produces a different start-up code during code generation for each configuration. I was using my PWM code in a project in which I had originally configured the timer to be used as a time base in Cube. So the PWM didn't run (coz the start-up code is different) despite the fact that the code was correct. Likewise, in a project which had the timer configured for PWM in Cube, it wouldn't run in time base mode even if we initialize the timer correctly and do everything right. I would infer that this is the same for the other modes.  :wtf:
Thanks a lot for all the help and suggestions guys!

Hi,

I use STM32 F0 Discovery board and tested PWM on the green LED: timer 3, channel 4.
I generated the code using STM32CubeMX (and I can see you did the same way), but in your code I don't see the PA6 GPIO initialization or __TIMx_CLK_ENABLE:
Code: [Select]
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(htim_base->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspInit 0 */

  /* USER CODE END TIM3_MspInit 0 */
    /* Peripheral clock enable */
    __TIM3_CLK_ENABLE();
 
   /**TIM3 GPIO Configuration   
    PC9     ------> TIM3_CH4
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /* USER CODE BEGIN TIM3_MspInit 1 */

  /* USER CODE END TIM3_MspInit 1 */
  }
}

L.E. I see that it was already answered. You may want to check ChibiOS HAL. It can be used independently, and is much, much cleaner.

GPIO initialization for PWM and __TIMx_CLK_ENABLE() is not needed. It runs fine without them.
 

Offline Matter45

  • Newbie
  • Posts: 5
  • Country: au
Re: PWM output on STM32
« Reply #22 on: March 08, 2017, 11:25:38 am »
just thought I add a solution to this problem:

https://www.youtube.com/watch?v=1BNlCkBN82A&feature=youtu.be

you need to add a line in the stm32f0xx_hal_msp.c file:

GPIO_InitStruct.Alternate = GPIO_AF1_TIM3;

then putting in HAL_TIM_PWM_Start in the main like usual will make it work.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf