cancel
Showing results for 
Search instead for 
Did you mean: 

Servo control using STM32VLDiscovery

choky_ndhie27
Associate II
Posted on October 13, 2011 at 14:18

Hi all,

want to run

 

a

 

servo

 

using the

 

STM32

 

Discovery

if

 

you

 

have a

 

suggestion

 

program to

run

 

the

 

servo

?

or

 

you have a

 

simple

 

code to

 

run the

 

servo

 

on the

 

STM32

 

Discovery

Thank you

Regards,

Endy
11 REPLIES 11
Posted on October 13, 2011 at 16:38

What kind of signal does the servo need? There have been several examples posted showing how to set up the timers to generate PWM signals, and to sweep the duty cycle.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
choky_ndhie27
Associate II
Posted on October 13, 2011 at 17:56

my servo need a square signals with 20ms, I have tried a timer with interrupt but does can run

this my program:

#include ''stm32f10x.h''

#include ''stm32f10x_tim.h''

#include ''STM32vldiscovery.h''

  u16 period;

  u16 scale;

  u16 width;

  u16 count;

  u16 angle;

void TIM3_IRQChannel(void)

{}

void TIM3_IRQHandler(void)

{

count=count+1;

if (count == 200)

{

count = 0x00;

}

if (count <= angle)

{

GPIO_SetBits(GPIOC,GPIO_Pin_7);

}

if (count >= angle)

{

GPIO_ResetBits(GPIOC,GPIO_Pin_7);

}

}

int main(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;

  NVIC_InitTypeDef NVIC_InitStructure;

  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

  TIM_OCInitTypeDef TIM_OCInitStructure;

  //RCC_Config();

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // Permit ReMap

  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_7; //7

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // clock to 50MHz

  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;  // alternate function pull

  GPIO_Init(GPIOC, &GPIO_InitStructure);// Configuration for GPIOB assume

  GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);

  scale = 101;

  period = 2501;

  width = period/2;

  TIM_TimeBaseStructure.TIM_Period = (period - 1);

  TIM_TimeBaseStructure.TIM_Prescaler = (scale - 1);

  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;

  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

  NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQHandler;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =2;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

  TIM_OCInitStructure.TIM_Pulse = width;

  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OC2Init(TIM3, &TIM_OCInitStructure);

  TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);

  TIM_ARRPreloadConfig(TIM3, ENABLE);

  TIM_ClearFlag(TIM3, TIM_FLAG_Update);

  TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);

  TIM_Cmd(TIM3,ENABLE);

 

  while (1)

  {

 angle = 20;

  }

}

void Delay(__IO uint32_t nCount)

{

  for(; nCount != 0; nCount--);

}

#ifdef  USE_FULL_ASSERT

void assert_failed(uint8_t* file, uint32_t line)

{

  while (1)

  {

  }

}

#endif

Posted on October 13, 2011 at 18:27

Presumably not truly square (50/50) because you need to pull the duty in/out to achieve the ''angle'' you want. What's the specification for that? ie min/max high time.

PC.7 is being driven by the TIM3_CH2 output, you don't control it by writing to the GPIO pin directly.

The values for scale and period are nonsensical, it will generate a ~95Hz signal (10.525 ms) on the pin, and call your update interrupt at that periodicity.

Whereas

scale = 48; // Assuming a 24 MHz TIMCLK, gives 500 KHz timebase

period = 10000;

Would give you 50 Hz (20 ms period), and provide a duty cycle sweepable from 0 to 100% in 0.01% increments (2 us tick units), which you could program in interrupt using the TIM3 CCR2 register (with 0 .. 10000). Your timer interrupt will also need to actually clear the source of the interrupt, otherwise it will continually tail chain.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
choky_ndhie27
Associate II
Posted on October 13, 2011 at 19:16

I

 

want to make a

 

signal

 

to drive the

 

servo

 

to the

 

control

 

signal

 

high

 

and signal

 

low

 

as

 

I included

 

this

 

picture

, how to make 

the signal

I

 

can control

 

with a

 

logic

 

high

Thanks clive1

choky_ndhie27
Associate II
Posted on October 13, 2011 at 19:25

0690X00000603E5QAI.jpg

Posted on October 13, 2011 at 19:49

Ok, I don't see a horizontal scale, but I'll assume you have a 20 ms period.

With PWM you control the ''width'' of the high portion with the CCR register for the channel. It's referred to as the duty cycle, 10/90 would spend 2 ms high, 18 ms low, using my suggested settings you'd be programming in 1000 into the CCR

Again, what is the minimum and maximum width of the high portion? I don't have the specifications for *your* servo.

With that information you could convert a fractional angle, 0-360 degrees, into a setting written into the CCR.

Some typical ones rotate 180 degrees and expect a 600 to 2400 us width to achieve that range, ie 1800 us or 900 tick units at 500 KHz (2 us)

TIM3->CCR2 = 300 + (u16)(angle * 10.0); // where angle is a float 0.0-180.0 degrees

So perhaps something like :

void TIM3_IRQHandler(void)

{

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

  {

    TIM_ClearITPendingBit(TIM3, TIM_IT_UP);

    // minimum high of 600 us, with 180 degrees at 2400 us

    TIM3->CCR2 = 300 + (u16)(angle * 5.0); // where angle is a float 0.0-180.0 degrees

  }

}

If I changed scale/period to something like 8/60000 I could achieve even better resolution/granularity.

If you have 4 servos, you could use the same TIM3, and all 4 PWM channels.

Edit: fixed scaling to 5.0

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
choky_ndhie27
Associate II
Posted on October 13, 2011 at 21:34

Sorry

 

clive

, I really 

do not

 

understand

 

with

 

this

 

program

if

 

you

 

can

 

give

 

me an example of

 

a simple

 

program

 

to

 

carry out

 

the servo

 

program

because

 

I am a

 

newbie

programmer

I

've 

tried

 

the program

 

to

 

run the

 

servo

 

on the

 

AVR

 

and the

 

servo

 

can run,

 

and I want to

 

make a

 

program

 

on

 

STM32_Discovery

 

as

 

logic

 

programs on the

AVR

Servo

 

that I use

 

is the

 

Hitec

 

HS

-325 

HB

Spesefikasi

 

what

 

you need

 

to

 

be

 

about providing

 

simple

 

program to

 

run

 

the

 

servo

or

 

you have

 

another way to run

 

the

 

servo

?

The following

 

is

 

my

 

AVR

 

program

:

#include <avr/io.h>

#include <avr/iom8535.h>

#include <avr/interrupt.h>

#include <util/delay.h> 

#define count _SFR_IO8 (0x60)

#define angle _SFR_IO8 (0x61)

void delay_ms(uint16_t ms)//program delay

{

while (ms)

{

_delay_ms(1);

ms--;//ms=ms-1

}

}

ISR(TIMER0_OVF_vect)

{

TCNT0 = 0xcd;

count = count+1;

if (count == 200)

{

count = 0x00;

}

if (count <= angle)

{

PORTB |= _BV(7);//servo

}

if (count >= angle)

{

PORTB &= ~_BV(7);

}

}

int main (void)

{

DDRB  = 0xff;

PORTB = 0x00;

TCCR0 = 0x02;//prescaller 8

TCNT0 = 0xcd;//0xff-0x9b=64(100)

//xtall=8MHz, 8M/(8x100)=10kHz

//t=1/10k=0.1ms

OCR0=0X00;

TIMSK = 0x01;

count = 0x00;

sei();

while (1)

{

angle=30;//min: 11 , max: 47; servo run 180 degree

}

}

From: clive1

Posted: Thursday, October 13, 2011 8:07 PM

Subject: Servo control using STM32VLDiscovery

Ok, I don't see a horizontal scale, but I'll assume you have a 20 ms period.

With PWM you control the ''width'' of the high portion with the CCR register for the channel. It's referred to as the duty cycle, 10/90 would spend 2 ms high, 18 ms low, using my suggested settings you'd be programming in 1000 into the CCR

Again, what is the minimum and maximum width of the high portion? I don't have the specifications for *your* servo.

With that information you could convert a fractional angle, 0-360 degrees, into a setting written into the CCR.

Some typical ones rotate 180 degrees and expect a 600 to 2400 us width to achieve that range, ie 1800 us or 900 tick units at 500 KHz (2 us)

TIM3->CCR2 = 300 + (u16)(angle * 10.0); // where angle is a float 0.0-180.0 degrees

So perhaps something like :

void TIM3_IRQHandler(void)

{

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

  {

    TIM_ClearITPendingBit(TIM3, TIM_IT_UP);

    // minimum high of 600 us, with 180 degrees at 2400 us

    TIM3->CCR2 = 300 + (u16)(angle * 10.0); // where angle is a float 0.0-180.0 degrees

  }

}

If I changed scale/period to something like 8/60000 I could achieve even better resolution/granularity.

If you have 4 servos, you could use the same TIM3, and all 4 PWM channels.

Posted on October 13, 2011 at 22:00

Sorry

 

clive

, I really 

do not

 

understand

 

with

 

this

 

program

if

 

you

 

can

 

give

 

me an example of

 

a simple

 

program

 

to

 

carry out

 

the servo

 

program

because

 

I am a

 

newbie

programmer

I

've 

tried

 

the program

 

to

 

run the

 

servo

 

on the

 

AVR

 

and the

 

servo

 

can run,

 

and I want to

 

make a

 

program

 

on

 

STM32_Discovery

 

as

 

logic

 

programs on the

AVR

 

Servo

 

that I use

 

is the

 

Hitec

 

HS

-325 

HB

Spesefikasi

 

what

 

you need

 

to

 

be

 

about providing

 

simple

 

program to

 

run

 

the

 

servo

or

 

you have

 

another way to run

 

the

 

servo

?

 

Your AVR code manually drives the pin, the STM32 timers are capable of generating the signal directly. You set up the timers, then you program a register with a value based on the angle you want the servo to attain.

Here's a specification for the signalling.

http://www.servocity.com/html/hs-325hb_bb_deluxe.html

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on October 13, 2011 at 22:50

// STM32 Servo Demo for 24 MHz VL Discovery - sourcer32@gmail.com

#include ''stm32F10x.h''

#include ''STM32vldiscovery.h''

void RCC_Configuration(void);

void GPIO_Configuration(void);

void NVIC_Configuration(void);

void TIM3_Configuration(void);

float servo_angle = 0.0; // +/- 90

float angle_delta = (1.0 / 50.0); // slew 1 degree per second

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->CCR2 = 600 + (u16)((servo_angle + 90.0) * 10.0); // where angle is a float -90.0 to +90.0 degrees

    // a quick hack to get the servo to stroke back and forth

    servo_angle += angle_delta;

    if ((servo_angle >= 90.0) || (servo_angle <= -90.0))

    {

      angle_delta = -angle_delta; // reverse

      servo_angle += angle_delta;

    }

  }

}

int main(void)

{

  RCC_Configuration();

  GPIO_Configuration();

  NVIC_Configuration();

  TIM3_Configuration();

  while(1);

}

void RCC_Configuration(void)

{

    // clock for GPIO and AFIO (Remap)

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);

    // clock for TIM3

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

}

void NVIC_Configuration(void)

{

   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);

}

void GPIO_Configuration(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;

  // PC.07 TIM3_CH2

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_Init(GPIOC, &GPIO_InitStructure);

  GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); // Remap to get signal on PC.07

}

void TIM3_Configuration(void)

{

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    TIM_OCInitTypeDef TIM_OCInitStructure;

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

    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);

    // Channel 2 configuration = PC.07 TIM3_CH2

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

    TIM_OCInitStructure.TIM_Pulse = 600 + 900; // 1500 us - Servo Top Centre

    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

    TIM_OC2Init(TIM3, &TIM_OCInitStructure);

    // turning on TIM3 and PWM outputs

    TIM_Cmd(TIM3, ENABLE);

    TIM_CtrlPWMOutputs(TIM3, ENABLE);

  // TIM IT enable

  TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);

}

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