K40: Turning A Servo Tutorial

Document created by GUO XIAOLI Employee on Jul 12, 2012Last modified by GUO XIAOLI Employee on Jul 25, 2012
Version 13Show Document
  • View in full screen mode

This tutorial covers the details of Turning A Servo on the Kinetis K40 using TWR-K40x256-KIT evaluation board.

 

 

Overview

 

In this exercise you will build a “bare metal” (no RTOS) application which turns a servo, targeting a Freescale K40 board.

 

You will:

  • Create the Servo code in CodeWarrior
  • Build the Servo project
  • Download and run the code on a Kinetis K40 Tower System board
  • Learn how to utilize the FlexTimer module to control a Servo

 

  To successfully complete this exercise you need the following board and development environment.

  • The K40 Tower card, TWR-K40x256
  • Tower Elevator Panels
  • Servo
  • Prototyping Board
  • Power to your servo - either utilize the 7.2v Nicad Battery or a DC power supply
  • CodeWarrior for Microcontrollers

1. Hardware

 

  The first step of this tutorial requires you read the Turn A Servo article for background information on servo's, timer modules, PWM signals and counters.

You will need to connect your servo to the microcontroller and also to a separate power source.

2. Create a New CodeWarrior Project

 

The next step is to create a new project (or add this code to an existing project).

3. Build the Code

 

If you have more than one project in your project view, make sure the proper project is the focus. The most reliable way to do this is to right click the project and choose Build Project as shown below. You can also go to the Project menu and choose the same command.

If you encounter errors, look in the Problems view and resolve them. You can ignore any warnings.

4. Download/Debug/Run

 

This link shows a video of the servo turning the wheels from left to right in small increments
http://www.youtube.com/watch?v=QgwASk9DHvU&feature=relmfu

5. Learning Step: Servo Code Description

 

Your code will sweep your servo from max to minimum angular position, and then back again continuously.

Example Code

 

This code sets up the Pulse Width Modulation Timer Module for use by a servo. It is set to utilize Edge-Aligned PWM, and this file properly configures the period, and pulse width for use by the other modules

 

Several important functions are contained in this file:
1. Init_PWM_Servo () - initializes the timer module
2. PWM_Servo (double duty_Cycle) - enter the desired duty cycle setting for the servo
3. PWM_Servo_Angle (int Angle) - enter the desired angle for the servo

  • Straight forward - PWM_Servo_Angle (45)
  • Full left - PWM_Servo_Angle (90)Full right - PWM_Servo_Angle (0)

  4. Servo_Tick - interrupt routine which executes once/servo period

 

PWM_Servo (double duty_Cycle)
Init_PWM_Servo ()
PWM_Servo_Angle (float Angle)
void ServoTick()

Variables

  • FTM0_CLK_PRESCALE
  • TM0_OVERFLOW_FREQUENCY
  • Pulse_Width_Low
  • Pulse_Width_High
  • Total_Count
  • Low_Count
  • Scale_Factor
  • Angle

Init_PWM_Servo

 

Void Init_PWM_Servo ()

{

 

//Enable the Clock to the FTM0 Module
SIM_SCGC6 |= SIM_SCGC6_FTM0_MASK

//Pin control Register (MUX allowing user to route the desired signal to the pin. 
PORTC_PCR4  = PORT_PCR_MUX(4)  | PORT_PCR_DSE_MASK;

//FTM0_MODE[WPDIS] = 1; //Disable Write Protection - enables changes to QUADEN, DECAPEN, etc. 
FTM0_MODE |= FTM_MODE_WPDIS_MASK;

//FTMEN is bit 0, need to set to zero so DECAPEN can be set to 0
FTM0_MODE &= ~1;

 

 

//Set Edge Aligned PWM
FTM0_QDCTRL &=~FTM_QDCTRL_QUADEN_MASK
//QUADEN is Bit 1, Set Quadrature Decoder Mode (QUADEN) Enable to 0,   (disabled)

// Also need to setup the FTM0C0SC channel control register
FTM0_CNT = 0x0; //FTM Counter Value - reset counter to zero
FTM0_MOD = (PERIPHERAL_BUS_CLOCK/(1<<FTM0_CLK_PRESCALE))/FTM0_OVERFLOW_FREQUENCY// Count value of full duty cycle
FTM0_CNTIN = 0; //Set the Counter Initial Value to 0

// FTMx_CnSC - contains the channel-interrupt status flag control bits
FTM0_C3SC |= FTM_CnSC_ELSB_MASK; //Edge or level select
FTM0_C3SC &= ~FTM_CnSC_ELSA_MASK; //Edge or level Select
FTM0_C3SC |= FTM_CnSC_MSB_MASK; //Channel Mode select

//Edit registers when no clock is fed to timer so the MOD value, gets pushed in immediately
FTM0_SC = 0; //Make sure its Off!

//FTMx_CnV contains the captured FTM counter value, this value determines the pulse width
FTM0_C3V = FTM0_MOD;

//Status and Control bits
FTM0_SCFTM_SC_CLKS(1); // Selects Clock source to be "system clock" or (01)

//sets pre-scale value see details below
FTM0_SC |= FTM_SC_PS(FTM0_CLK_PRESCALE);

/******begin FTM_SC_PS details ****************************
* Sets the Prescale value for the Flex Timer Module which divides the
* Peripheral bus clock -> 48Mhz by the set amount
* Peripheral bus clock set up in clock.h

* The value of the prescaler is selected by the PS[2:0] bits. 
* (FTMx_SC field bits 0-2 are Prescale bits -  set above in FTM_SC Setting)

*  000 - 0 - No divide
*  001 - 1 - Divide by 2
*  010 - 2 - Divide by 4
*  011 - 3 - Divide by 8
*  100 - 4 - Divide by 16
*  101 - 5 - Divide by 32
*  110 - 6 - Divide by 64 -
*  111 - 7 - Divide by 128
*  ******end FTM_SC_PS details*****************************/


// Interrupts
FTM0_SC |= FTM_SC_TOIE_MASK; //Enable the interrupt mask.  timer overflow interrupt.. enables interrupt signal to come out of the module itself...  (have to enable 2x, one in the peripheral and once in the NVIC
enable_irq(62)// Set NVIC location, but you still have to change/check NVIC file sysinit.c under Project Settings Folder

}

 

PWM_Servo

Void PWM_Servo (double duty_Cycle)

{    

     FTM0_C3V =  FTM0_MOD*(duty_Cycle*.01);

}

PWM_Servo_Angle

 

 

 

 

//PWM_Servo_Angle is an integer value between 0 and 90
//where 0 sets servo to full right, 45 sets servo to middle, 90 sets servo to full left
void PWM_Servo_Angle (float Angle)
{
   High_Count = FTM0_MOD*(Pulse_Width_High)*FTM0_OVERFLOW_FREQUENCY;
   Low_Count = FTM0_MOD*(Pulse_Width_Low)*FTM0_OVERFLOW_FREQUENCY;
   Total_Count = High_Count - Low_Count;
   Scale_Factor = High_Count -Total_Count*(Angle/90);  
   FTM0_C3V = Scale_Factor; //sets count to scaled value based on above calculations
}









Set Up a Look-Up Table for Servo Angles

int main(void)
{
  //Servo angles can be stored in a look-up table for steering the car.
  float table[n] = { steering_angle_0;
   steering_angle_1;
   steering_angle_2;
  ……
   steering_angle_n-1
   };
 
  Steering_Angle = table[x];
  PWM_Servo_Angle (Steering_Angle); // Call PWM_Servo_Angle function.
 
}









Other K40 Tutorials:

 

  1. K40 Blink LED Tutorial
  2. K40 DC Motor Tutorial
  3. Kinetis K40: Turning A Servo
  4. K40 Line Scan Camera Tutorial

Links

 

Kinetis K40


TWR-K40X256-KIT

Attachments

    Outcomes