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 23, 2011 at 13:41

Which board? Which pin?

I'm afraid I can't provide any specific help with the information provided.

The example uses a specific timer, and knowledge about which pin(s) that timer is connected to externally. For it to work with different pins/timers, you'd need to review the reference manual to see if the pin you want to use is in fact connected to a timer output channel capable of PWM, and then enable/configure the timer (timebase/channel), gpio, clocks, etc.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
grox
Associate
Posted on December 23, 2011 at 12:50

Just replace

 

while(1);

with

int i;

int n = 1;

 

int brightness = 0;

while(1){ // Do not exit

if (brightness >= 1000)

n =

-1; // if

brightness maximum change direction

if (brightness <= 0) n = 1;

// if brightness minimum change direction

brightness += n; // increment or decrement brightness refer by direction

TIM3->CCR3 = brightness; // set brightness

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

 

};

JimK, thank you very much. This is the first thing that I wanted to do after simple led blinking.

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

Playing with stm32vldiscovery for second evening. Now it is time to understand the right way to add PWM to second LED.

stryczniewicz
Associate
Posted on December 29, 2011 at 16:06

And that's what i wanted to ask - why is pin 8 automatically remapped to channel 3? Can i remap it to some other channel and how? And btw how to connect both leds on stm32-discovery to pwm?

Posted on December 29, 2011 at 16:26

And that's what i wanted to ask - why is pin 8 automatically remapped to channel 3?

The default pin mapping, and remapped options, are clearly defined in the Data Sheet. The timer, channel, and remapping were chosen explicitly because they got the job done, and not picked randomly. See pg 27

http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD002517pdf

http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/REFERENCE_MANUAL/CD00246pdf

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on January 09, 2012 at 17:15

Hi,

Thank you for your useful example. I try to do the same thing on green led (PC9) that should be also mapped to TIM3, but it's not working. Do you have a suggestion?

Thank you very much

and congratulations

for the excellent job

on the forum

Posted on January 09, 2012 at 19:07

#include ''stm32F10x.h''
#include ''STM32vldiscovery.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_APB2PeriphClockCmd(
RCC_APB2Periph_GPIOC |
RCC_APB2Periph_AFIO, ENABLE );
RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3, ENABLE );
GPIO_StructInit(&GPIO_InitStructure); // Reset init structure
// Setup Blue & Green LED on STM32-Discovery Board to use PWM.
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
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, TIM3_CH4 to GPIOC.Pin9
// Let PWM frequency equal 100Hz.
// Let period equal 1000. Therefore, timer runs from zero to 1000. Gives 0.1Hz resolution.
// Solving for prescaler gives 
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( TIM3, &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_OC3Init( TIM3, &TIM_OCInitStruct ); // Channel 3 Blue LED
TIM_OC4Init( TIM3, &TIM_OCInitStruct ); // Channel 4 Green LED
TIM_Cmd( TIM3, ENABLE );
while(1) // Do not exit
{
if (((brightness + n) >= 1000) || ((brightness + n) <= 0))
n = -n; // if brightness maximum/maximum change direction
brightness += n;
TIM3->CCR3 = brightness; // set brightness
TIM3->CCR4 = 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..
Posted on January 09, 2012 at 22:47

I studied the code and data sheet, but i had not looked at the 

TIM_OC3Init function. Now everything is clear! Thanks!!

fcini9
Associate II
Posted on March 23, 2012 at 16:45

I've the same problem, even if I use the complete code of Clive1.

I 've some others errors....I list them:

..\src\main.c(28): error:  #20: identifier ''TIM_TimeBaseInitTypeDef'' is undefined

..\src\main.c(29): error:  #20: identifier ''TIM_OCInitTypeDef'' is undefined

..\src\main.c(53): warning:  #223-D: function ''TIM_TimeBaseStructInit'' declared implicitly

..\src\main.c(54): error:  #20: identifier ''TIM_CKD_DIV4'' is undefined

..\src\main.c(57): warning:  #223-D: function ''TIM_TimeBaseInit'' declared implicitly

..\src\main.c(59): warning:  #223-D: function ''TIM_OCStructInit'' declared implicitly

..\src\main.c(60): error:  #20: identifier ''TIM_OutputState_Enable'' is undefined

..\src\main.c(61): error:  #20: identifier ''TIM_OCMode_PWM1'' is undefined

..\src\main.c(65): warning:  #223-D: function ''TIM_OC3Init'' declared implicitly

..\src\main.c(66): warning:  #223-D: function ''TIM_OC4Init'' declared implicitly

..\src\main.c(68): warning:  #223-D: function ''TIM_Cmd'' declared implicitly

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

a lot of problems are just warning.

The software I'm using is the Keil one.

I'm new with the programming with this micro (and micro in general), so forgive me if it is a stupid question 😉

Posted on March 23, 2012 at 20:42

This would seem to be a basic problem with pulling in the appropriate include files.

Try looking at stm32f10x_conf.h, and make sure it's pulling in stm32f10x_tim.h, etc.

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 02, 2012 at 13:06

Thanks for the reply.

I try to check the stm32f10_conf.h file and the file stm32f10x_tim.h is commented.

In the stm32f10x_tim.h file the only included file is stm32f10x.h

I try to remove the comment on stm32f10_conf.h but I have new errors:

Following the errors.

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

linking...

.\Debug\DISCOVER.axf: Error: L6218E: Undefined symbol TimingDelay_Decrement (referred from stm32f10x_it.o).

.\Debug\DISCOVER.axf: Error: L6218E: Undefined symbol TIM_Cmd (referred from main.o).

.\Debug\DISCOVER.axf: Error: L6218E: Undefined symbol TIM_OC3Init (referred from main.o).

.\Debug\DISCOVER.axf: Error: L6218E: Undefined symbol TIM_OC4Init (referred from main.o).

.\Debug\DISCOVER.axf: Error: L6218E: Undefined symbol TIM_OCStructInit (referred from main.o).

.\Debug\DISCOVER.axf: Error: L6218E: Undefined symbol TIM_TimeBaseInit (referred from main.o).

.\Debug\DISCOVER.axf: Error: L6218E: Undefined symbol TIM_TimeBaseStructInit (referred from main.o).