cancel
Showing results for 
Search instead for 
Did you mean: 

Example: PWM on STM32-Discovery Blue LED

Posted on February 12, 2011 at 21:39

Hey,

I just spent a bunch of time sorting out how to get the darn PWM output on the blue LED on the STM32-Discovery board.  After a lot of time pouring over the datasheets and forum posts I was finally able to work out the following code.  Seems to work very well.

    RCC_APB2PeriphClockCmd(    RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |

            RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE |

            RCC_APB2Periph_AFIO, ENABLE );

 

    RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3, ENABLE );

 

    // Set the Vector Table base address at 0x08000000.

    NVIC_SetVectorTable( NVIC_VectTab_FLASH, 0x0 );

 

    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );

 

    // Configure HCLK clock as SysTick clock source.

    SysTick_CLKSourceConfig( SysTick_CLKSource_HCLK );

    // Setup Blue LED on STM32-Discovery Board to use PWM.

    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;            // Alt Function - Push Pull

    GPIO_Init( GPIOC, &GPIO_InitStructure );

    GPIO_PinRemapConfig( GPIO_FullRemap_TIM3, ENABLE );        // Map TIM3_CH3 to GPIOC.Pin8

 

    // Let PWM frequency equal 100Hz.

    // Let period equal 1000. Therefore, timer runs from zero to 1000. Gives 0.1Hz resolution.

    // Solving for prescaler gives 240.

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;

    TIM_TimeBaseStructInit( &TIM_TimeBaseInitStruct );

    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV4;

    TIM_TimeBaseInitStruct.TIM_Period = 1000;

    TIM_TimeBaseInitStruct.TIM_Prescaler = 240;

    TIM_TimeBaseInit( TIM3, &TIM_TimeBaseInitStruct );

 

    TIM_OCInitTypeDef TIM_OCInitStruct;

    TIM_OCStructInit( &TIM_OCInitStruct );

    TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;

    TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;

    // Initial duty cycle equals 0%. Value can range from zero to 1000.

    TIM_OCInitStruct.TIM_Pulse = 0;

    TIM_OC3Init( TIM3, &TIM_OCInitStruct );

    TIM_Cmd( TIM3, ENABLE );

Also, below is a useful macro that sets the PWM duty cycle once the output is running.

// Set duty cycle when using TIM3 as a PWM output.

&sharpdefine SetTIM3Duty( val )    TIM3->CCR3 = val

It's neat to see the blue LED ramping and fading smoothly.

#stm32 #pwm #pwm #discovery #stm32f100rb #output
49 REPLIES 49
Posted on April 02, 2012 at 16:04

You're going to need to lose the TimingDelay_Decrement() function call in stm32f10x_it.c, since you aren't implementing it, or using SysTick.

And you're going to need to ADD the Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_tim.c to your project.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
fcini9
Associate II
Posted on April 03, 2012 at 11:29

Ok, now it compiles, thanks.

I still have this line

..\src\main.c(83): warning:  #111-D: statement is unreachable

the statement is:   return(0); // System will implode

Posted on April 03, 2012 at 15:13

Well, that's because it's preceded by a while(1) loop that doesn't exit.

Leaving main() is a very bad plan, and will most likely result in the system crashing. Remember there is no where for it to exit too, or pass a return value, you're not running a command line application.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
bjoern2
Associate II
Posted on April 12, 2012 at 13:10

Hello,

took me some time, but now it works on stm32f4 discovery board:

int main(void)

{

    RCC_AHB1PeriphClockCmd(  RCC_AHB1Periph_GPIOD , ENABLE );

 

    RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM4, ENABLE );

  GPIO_InitTypeDef GPIO_InitStructure;

  TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;

  TIM_OCInitTypeDef TIM_OCInitStruct;

 

    volatile int i;

    int n = 1;

    int brightness = 0;

     

 

    GPIO_StructInit(&GPIO_InitStructure); // Reset init structure

 

    GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4);

    GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_TIM4);

    // Setup Blue & Green LED on STM32-Discovery Board to use PWM.

    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_12 | GPIO_Pin_13;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;            // Alt Function - Push Pull

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

    GPIO_Init( GPIOD, &GPIO_InitStructure );

       

 

    // Let PWM frequency equal 100Hz.

    // Let period equal 1000. Therefore, timer runs from zero to 1000. Gives 0.1Hz resolution.

    // Solving for prescaler gives 240.

    TIM_TimeBaseStructInit( &TIM_TimeBaseInitStruct );

    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV4;

    TIM_TimeBaseInitStruct.TIM_Period = 1000 - 1;   // 0..999

    TIM_TimeBaseInitStruct.TIM_Prescaler = 240 - 1; // Div 240

    TIM_TimeBaseInit( TIM4, &TIM_TimeBaseInitStruct );

 

    TIM_OCStructInit( &TIM_OCInitStruct );

    TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;

    TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;

    // Initial duty cycle equals 0%. Value can range from zero to 1000.

    TIM_OCInitStruct.TIM_Pulse = 500; // 0 .. 1000 (0=Always Off, 1000=Always On)

 

    TIM_OC1Init( TIM4, &TIM_OCInitStruct ); // Channel 3 Blue LED

    TIM_OC2Init( TIM4, &TIM_OCInitStruct ); // Channel 4 Green LED

 

    TIM_Cmd( TIM4, ENABLE );

 

  while(1)  // Do not exit

  {

    if (((brightness + n) >= 1000) || ((brightness + n) <= 0))

      n = -n; // if  brightness maximum/maximum change direction

 

        brightness += n;

 

    TIM4->CCR1 = brightness; // set brightness

    TIM4->CCR2 = 1000 - brightness; // set brightness

 

    for(i=0;i<10000;i++);  // delay

  }

 

  return(0); // System will implode

}

Greetings Bjoern

bjoern2
Associate II
Posted on April 12, 2012 at 14:46

Hello again,

just a short question, I think the TIM3 is APB1 and therefore should be clocked with 42MHz clk. But if I set:

    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;

    TIM_TimeBaseInitStruct.TIM_Period = 10000 - 1;   // 0..9999

    TIM_TimeBaseInitStruct.TIM_Prescaler = 42000 - 1; // Div 42000

Then I measure 5s for one cycle PWM, means 42000 x 10000 clks are 5 s long.

84 000 000 clocks for one second mean 84MHz, where am I wrong???

Greetings Bjoern

mikemayer
Associate
Posted on October 15, 2012 at 23:24

Clive,

I'm trying to drive the blue LED on my STM32L Discovery board using this example, but a lot of the defines do not existin the STM32l1xx libraries. Is the STM32L microcontrollera lot different from the STM32F1xx.?

Also, did I post this reply properly? What is the following box for?

Posted on October 16, 2012 at 02:32

This is a bit of a blind build as I don't have the board, but should work with the Green and Blue LED on the STM32L-Discovery. Might need to tweak it.

// PMW4 PB.6 Green LED, PB.7 Blue LED STM32L-Discovery - sourcer32@gmail.com
#include ''stm32l1xx.h''
#include ''stm32l1xx_conf.h''
int main(void)
{ 
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
volatile int i;
int n = 1;
int brightness = 0;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
// Setup Green and Blue LED on STM32L-Discovery Board to use PWM.
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_TIM4); // PB.6 Green LED TIM4_CH1
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_TIM4); // PB.7 Blue LED TIM4_CH2
// Let PWM frequency equal 100Hz.
// Let period equal 1000. Therefore, timer runs from zero to 1000. Gives 10 us resolution.
// Solving for prescaler gives 320 for 32 MHz device
TIM_TimeBaseInitStruct.TIM_Prescaler = (SystemCoreClock / 100000) - 1; // 100 KHz 
TIM_TimeBaseInitStruct.TIM_Period = 1000 - 1; // 0..999, 100 Hz
TIM_TimeBaseInitStruct.TIM_ClockDivision = 0;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStruct);
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
// Initial duty cycle equals 0%. Value can range from zero to 1000.
TIM_OCInitStruct.TIM_Pulse = 0; // 0 .. 1000 (0=Always Off, 1000=Always On)
TIM_OC1Init(TIM4, &TIM_OCInitStruct);
TIM_OC2Init(TIM4, &TIM_OCInitStruct);
TIM_Cmd(TIM4, ENABLE);
while(1) // Do not exit
{
if (((brightness + n) >= 1000) || ((brightness + n) <= 0))
n = -n; // if brightness maximum/maximum change direction
brightness += n;
TIM4->CCR1 = brightness; // set brightness
TIM4->CCR2 = 1000 - brightness; // set brightness
for(i=0;i<10000;i++); // delay
}
return(0); // System will implode
} 

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
mikemayer
Associate
Posted on October 16, 2012 at 21:24

Clive,

The code worked great.  The green and blud LEDs alternately get bright/dim about once every 14 seconds.  Now, I am trying to merge it with the temperature sensor demo.  There are some conflicts, but at least I am making some progress.  Thanks again.

Mike

jurriaan
Associate II
Posted on October 18, 2012 at 16:06

The code works for me but very slowly. I can actually see the PWM(on,off,on,off...) what configuration am I missing?

Posted on October 18, 2012 at 17:33

The code works for me but very slowly. I can actually see the PWM(on,off,on,off...) what configuration am I missing?

 

It will depend on how fast you run the core, and the optimization level of the compiler.

The LED demo should phase the LED with respect to each other as it swipes the pulse width in/out (0-100-0 %). Want to observe the waveform, get a scope.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..