cancel
Showing results for 
Search instead for 
Did you mean: 

[STM32f4discovery]Some clarification about PWM

bifrost
Associate II
Posted on April 11, 2013 at 23:07

hello,

reading around the forum i comed up with the following code. my question are in the code comments, if someone can point me in the right direction i'll be glad.

This code will be used to move 4 ESC, so the generated pulse should be similar to analogic servo, PWM @50Hz, duty cicle high from 1 to 2ms with ~10us precision

{code}

volatile uint16_t position[] = { 1000, 1000, 1000, 1000 }; //from 1000 to 2000

void TIM3_IRQHandler(void)

{

  if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)

  {

    TIM_ClearITPendingBit(TIM3, TIM_IT_Update);

    // minimum high of 600 us for -90 degrees, with +90 degrees at 2400 us, 10 us per degree

    //  timer timebase set to us units to simplify the configuration/math

    TIM3->CCR1 = position[0]; //PB0

    TIM3->CCR2 = position[1]; //PB1

    TIM3->CCR3 = position[2]; //PB4

    TIM3->CCR4 = position[3]; //PB5

  }

}

void startPWM(){

/*

* BASED ON https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32VLDiscovery/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/STM32VLDiscovery/Servo%20control%20using%20STM32VLDiscovery&FolderCTID=0x01200200770978C69A1141439FE559EB459D758000491D59B8574F8049B5DFA3E8B21CBA51&TopicsView=https://my.st.co...

* THANKS to Clive1

* */

// clock for GPIO and AFIO (Remap) - WHY THIS?

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);

// clock for TIM3 - HERE DO WE ENABLE TIM3 HW?

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

// PIN SETUP

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_StructInit(&GPIO_InitStructure); //Reset init structure

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOB, &GPIO_InitStructure);

//THIS?

GPIO_PinRemapConfig( GPIO_FullRemap_TIM3, ENABLE );        // Map TIM3_CH3 to GPIOB.Pin0, GPIOB.Pin1, GPIOB.Pin4, GPIOB.Pin5

//OR THIS?

//GPIO_PinAFConfig(GPIOB, GPIO_PinSource0, GPIO_AF_TIM3);

//GPIO_PinAFConfig(GPIOB, GPIO_PinSource1, GPIO_AF_TIM3);

//GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_TIM3);

//GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_TIM3);

//TIMER INTERRUPT SETUP

NVIC_InitTypeDef NVIC_InitStructure;

// Configure the NVIC Preemption Priority Bits

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

// Enable the TIM3 Interrupt

NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

//TIMER SETUP

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

TIM_TimeBaseStructInit( &TIM_TimeBaseStructure ); // Reset init structure

// Simplify the math here so TIM_Pulse has 1 us units

// PWMFreq = SystemCoreClock / ((TIM_Prescaler + 1) * (TIM_Period + 1));

// NOT VERY SURE THE TIM3 RUN AT 24MHz....

TIM_TimeBaseStructure.TIM_Prescaler = 24 - 1;  // 24 MHz / 24 = 1 MHz

TIM_TimeBaseStructure.TIM_Period = 20000 - 1; // 1 MHz / 20000 = 50 Hz (20 ms)

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

TIM_OCInitTypeDef TIM_OCInitStructure;

TIM_OCStructInit( &TIM_OCInitStructure );

// PWM1: Channel1, PB0

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

TIM_OCInitStructure.TIM_Pulse = position[0];

TIM_OC1Init(TIM3, &TIM_OCInitStructure);

// PWM1: Channel2, PB1

TIM_OCInitStructure.TIM_Pulse = position[1];

TIM_OC2Init(TIM3, &TIM_OCInitStructure);

// PWM1: Channel3, PB4

TIM_OCInitStructure.TIM_Pulse = position[2];

TIM_OC3Init(TIM3, &TIM_OCInitStructure);

// PWM1: Channel4, PB5

TIM_OCInitStructure.TIM_Pulse = position[3];

TIM_OC4Init(TIM3, &TIM_OCInitStructure);

// ENABLE TIMER

TIM_Cmd( TIM3, ENABLE );

    TIM_CtrlPWMOutputs(TIM3, ENABLE);

    // TIM IT enable

    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);

}

{/code}

ps. this is my very first code for this chip family, please be kind

#stm32f4-discovery #pwm
6 REPLIES 6
Posted on April 11, 2013 at 23:29

Yeah, porting code from the F1 to F4 is fun, the GPIO set up is different, and you have to divide down the clock which won't be running at 24 MHz. The code is supposed to clock the time base at 1 MHz, which gives a 1 us granularity.

This is an STM32F4-Discovery Servo version, I pulled this from the work-in-progress directory, but think it's workable.

// STM32 4-channel Servo Demo for 168 MHz STM32F4 Discovery - sourcer32@gmail.com
#include ''stm32f4_discovery.h''
/**************************************************************************************/
// Integers, or scaled integers (*10) will be more efficient here
volatile float servo_angle[4] = { 0.0, 0.0, 0.0, 0.0 }; // +/- 0 degrees
void TIM4_IRQHandler(void)
{
if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
// minimum high of 600 us for -90 degrees, with +90 degrees at 2400 us, 10 us per degree
// timer timebase set to us units to simplify the configuration/math
TIM_SetCompare1(TIM4, 1500 + (int)(servo_angle[0] * 0f) ); // PD.12
TIM_SetCompare2(TIM4, 1500 + (int)(servo_angle[1] * 0f) ); // PD.13
TIM_SetCompare3(TIM4, 1500 + (int)(servo_angle[2] * 0f) ); // PD.14
TIM_SetCompare4(TIM4, 1500 + (int)(servo_angle[3] * 0f) ); // PD.15
}
}
/**************************************************************************************/
void RCC_Configuration(void)
{
/* --------------------------- System Clocks Configuration -----------------*/
/* TIM4 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
/* GPIOD clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
}
/**************************************************************************************/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the TIM4 gloabal Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**************************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*-------------------------- GPIO Configuration ----------------------------*/
/* GPIOD Configuration: Pins 12, 13, 14 and 15 in output push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
/* Connect TIM4 pins to AF2 */
GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_TIM4);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_TIM4);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_TIM4);
}
/**************************************************************************************/
void TIM4_Configuration(void)
{
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* Time base configuration - SystemCoreClock = 168000000 for 168 MHz board */
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) (((SystemCoreClock / 1000000) / 2) - 1); // Shooting for 1 MHz, (1us)
TIM_TimeBaseStructure.TIM_Period = 20000 - 1; // 1 MHz / 20000 = 50 Hz (20ms)
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
/* Enable TIM4 Preload register on ARR */
TIM_ARRPreloadConfig(TIM4, ENABLE);
/* TIM PWM1 Mode configuration: Channel */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 1500; // Servo Top-Center
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
/* Output Compare PWM1 Mode configuration: Channel1 PD.12 */
TIM_OC1Init(TIM4, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);
/* Output Compare PWM1 Mode configuration: Channel2 PD.13 */
TIM_OC2Init(TIM4, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);
/* Output Compare PWM1 Mode configuration: Channel3 PD.14 */
TIM_OC3Init(TIM4, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);
/* Output Compare PWM1 Mode configuration: Channel4 PD.15 */
TIM_OC4Init(TIM4, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable);
/* TIM Interrupts enable */
TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
/* TIM4 enable counter */
TIM_Cmd(TIM4, ENABLE);
}
/**************************************************************************************/
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
NVIC_Configuration();
TIM4_Configuration();
while(1)
{
// Add code to stroke servos here
}
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
bifrost
Associate II
Posted on April 12, 2013 at 00:20

Thank you very much!

ok, so what is the difference between

//THIS?

GPIO_PinRemapConfig( GPIO_FullRemap_TIM3, ENABLE );        // Map TIM3_CH3 to GPIOB.Pin0, GPIOB.Pin1, GPIOB.Pin4, GPIOB.Pin5

//OR THIS?

//GPIO_PinAFConfig(GPIOB, GPIO_PinSource0, GPIO_AF_TIM3);

//GPIO_PinAFConfig(GPIOB, GPIO_PinSource1, GPIO_AF_TIM3);

//GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_TIM3);

//GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_TIM3);

There is no remap in stm32f4? (uhhm i was sure the code was compiling)

if i understand the difference between the GPIO initialization, simply are the init struct different?

the XXX

PreloadConfig 

is because STM32f4 use to buffer into shoadow register the real register value (i've rad the DataS, but i'm a bit confused about this)

sorry if some question are stupid, i'm tired and i'm going to sleep.

Posted on April 12, 2013 at 00:55

The F2, F4, L1 have a better multiplexing fabric for the alternate function mapping. It's been moved to the GPIO unit, and can now permit pin level reconfiguration, instead of blocks of pins (peripheral remap) that the F1 provided. This makes it easier to escape the functions you require.

The ARR normally changes at the current update value, whatever that happens to be, I set it immediately for consistency, and the fact whatever it was before is irrelevant.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
bifrost
Associate II
Posted on April 23, 2013 at 13:32

Thank you very much, yesterday i've corrected the code and now it is working.

I don't have here the code, but basically it is yours with some correction (just some define are different, and systemClock appear to be 72MHz in my system).

I just can't understand your prescaler calculation: you divide clock by 2.. this give you a ''pwm clock'' of 0.5MHz, not 1MHz as expected 

Posted on April 23, 2013 at 13:48

The code makes presumptions about the APB1 clock divider.

For a APB1 Prescaler of 4 (the usual default), the TIMCLK is DIV2
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
teobanhtrai
Associate
Posted on January 28, 2014 at 07:31

Hi,

I have modified your code of Servo Example STM32F4-Discovery to generate PWM to control my Blue Bird servo

BMS-621DMG+HS

, but I still cannot make it move.

The attached picture summaries the characteristics of PWM output. The period is 34ms, duty cycle changes 2.8% ~ 1% slowly up and down. The speed at which the duty cycle changes from the min value to the max one is about 8s, long enough for the response of the servo.

STM32F4-Discovery board provides the real output voltage at about 4.5V, not enough for the servo requirement 4.8~6.0V. So I use an external voltage 4.9~5.9V.

Could you please give me some hints.

________________

Attachments :

scope_3.bmp : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I05r&d=%2Fa%2F0X0000000bTN%2FKiORAjwqXxeVhTnlWpnJsnbJQEtmJ8Z28A4P7VOExxA&asPdf=false