Stellaris/Tiva Drivers
Miscellaneous drivers for Stellaris/Tiva microcontrollers
Servo Driver for Wide Timers

This is a servo driver for TI Stellaris microcontrollers. More...

Macros

#define SERVO_TIMER_A
 Specifies the A "half" of the timer to use for the servo.
 
#define SERVO_TIMER_B
 Specifies the B "half" of the timer to use for the servo.
 

Functions

int Servo_Init (uint32_t sysClock, uint32_t timerPeriodUsecs)
 Initialize the servo driver. More...
 
ServoHandle_t Servo_Config (uint32_t timerIdx, uint32_t timerHalf)
 Configure a servo instance. More...
 
int Servo_Enable (ServoHandle_t hServo)
 Enable servo operation. More...
 
int Servo_Disable (ServoHandle_t hServo)
 Disable servo operation. More...
 
int Servo_Calibrate (ServoHandle_t hServo, int32_t usecsPer90, int32_t usecsAtZero, bool reverseAngle)
 Set the calibration parameters for the servo. More...
 
int Servo_SetLimits (ServoHandle_t hServo, int32_t usecsMin, int32_t usecsMax)
 Set the limits for the servo. More...
 
int Servo_SetMotionParameters (ServoHandle_t hServo, int32_t rateDegPerSec)
 Set servo motion parameters. More...
 
int Servo_SetPositionUsecs (ServoHandle_t hServo, int32_t usecs)
 Set the servo position using the pulse width in microseconds. More...
 
int Servo_SetPosition (ServoHandle_t hServo, int32_t centiDegrees)
 Set the servo position using the pulse width in centi-degrees. More...
 
int32_t Servo_GetPositionUsecs (ServoHandle_t hServo)
 Get the position of the servo in microseconds of pulse width. More...
 
int32_t Servo_GetPosition (ServoHandle_t hServo)
 Get the position of the servo in centi-degrees. More...
 
int Servo_MoveUsecs (ServoHandle_t hServo, int32_t usecs, void(*pfnMotionObserver)(void *pObserverData), void *pObserverData)
 Move to position in microseconds pulse width, with motion control. More...
 
int Servo_Move (ServoHandle_t hServo, int32_t centiDegrees, void(*pfnMotionObserver)(void *pObserverData), void *pObserverData)
 Move to position in centi-degrees, with motion control. More...
 
int Servo_SetTickObserver (ServoHandle_t hServo, void(*pfnServoTickObserver)(void *pObserverData), void *pObserverData)
 Set a callback function on the PWM timer tick. More...
 
uint32_t Servo_ReadBatteryRaw (void)
 Read the battery level in raw ADC counts. More...
 
uint32_t Servo_ReadBatteryMv (void)
 Read the battery level in millivolts. More...
 
void Servo_BatteryInit (uint32_t gain, uint32_t offset)
 Initialize the servo battery monitor. More...
 

Detailed Description

This is a servo driver for TI Stellaris microcontrollers.

Specifically it is for the LM4F parts (such as LM4F120 or LM4F232) because this driver depends on the wide timers. The wide timers are not available on older LM3S devices.

Although it is not required, this driver was written to be used with a Servo BoosterPack. See https://github.com/kroesche/lp-servo12 and http://tronics.kroesche.org/servo-boosterpack.html

This driver provides a set of functions for configuring and using timers for servo motion control. It uses the PWM mode of the timers to generate the appropriate pulse-width control for typical hobby servos.

Two unit systems are provided for dealing with servo position: microseconds and centi-degrees. Because the servo position is controlled by the pulse width of the timer output signal, the position can be represented as a pulse width. Therefore microseconds is used as the units to represent the pulse width and thus the servo position. The other option for units is centi-degrees, which is degrees * 10. This allows resolution of 0.1 degrees which should be sufficient for hobby applications. Using centi-degrees allows fractional degree resolution without requiring floating point.

Servos can be moved two ways: direct position and motion control. When direct position is used, the servo is just immediately commanded to the new position and the rate of motion is whatever the servo provides. When motion control is used, the rate of motion is controlled. This allows for smoother and less jerky control.

The servo enable/disable can be used to apply/remove the pulse signal to the servos. It may be useful to disable a servo once it has reached the desired position so that the servo stops hunting around or jittering at the target position.

Two forms of callback are provided: tick and motion. The tick callback allows a client function to be called at each pulse period (timer tick). This allows for varying the pulse width at the pulse frequency. This could be used for some advanced control method where the position is varied over time according to some algorithm. The motion control makes use of this, so if you install a tick callback and then use a Move() function, your tick callback will be deleted. The motion callback is used with the Move() functions. Since Move() is asynchronous and returns before the motion is done, this allows a client to be notified when the motion is finished.

Todo:

add acceleration feature to motion control

extend driver to work without wide timer

EXAMPLE: Here is code showing how you might use this driver in an example:

// init the driver
err = Servo_Init(SysControlClockGet(), 20000); // 50 Hz

// get a servo instance using wide timer 4A
handle = Servo_Config(4, SERVO_TIMER_A)

// enable the servo (this establishes a known position)
err = Servo_Enable(handle);

// set motion rate for 90 deg per sec
err = Servo_SetMotionParameters(handle, 90);

// command the servo to move to +45 deg
err = Servo_Move(handle, 450, NULL, NULL);

Function Documentation

int Servo_Init ( uint32_t  sysClock,
uint32_t  timerPeriodUsecs 
)

Initialize the servo driver.

Parameters
[in]sysClockis the system clock rate used to run the timers.
[in]timerPeriodUsecsis the timer period in microseconds, to used for servo pulse width generation.

This function must be called to initialize the servo driver and before any of the other servo functions are called. The parameter timerPeriodUsecs is used to set the timer that is used for teh servo pulse period. The same value will be used for all the servos managed by this driver. The parameter sysClock is the value of the system clock or time base used for the timers. Internally this value is used to compute the number of timer ticks per microsecond so it shoud always be a whole MHz value. If fractional MHz is used for the system clock, then pulse width calculations will not be correct.

Returns
Zero is returned for success, non-zero for the following reasons: driver is already initialized (-1)
ServoHandle_t Servo_Config ( uint32_t  timerIdx,
uint32_t  timerHalf 
)

Configure a servo instance.

Parameters
[in]timerIdxis the wide timer number to use for the servo
[in]timerHalfis the half of the timer for this servo, A (0) or B(1). Macros SERVO_TIMER_A and SERVO_TIMER_B can be used.

This function allocates and configures a servo instance. The caller specifies which wide timer is to be used for the servo. That timer will then be initialized to be used for servo PWM generation and the servo instance data will be populated. Default values will be used for all the calibration data.

Returns
A servo handle is returned if the function is successful. The servo handle should be used for all other servo driver function calls. If there is any error, then a NULL handle is returned. Possible errors are: the timer has already been allocated for the servo; there are no available servo instances.
int Servo_Enable ( ServoHandle_t  hServo)

Enable servo operation.

Parameters
[in]hServois the servo handle

This function will begin generating the PWM pulse to the servo at the present position. If the servo is not already at that position it will move there (without rate control).

Returns
Zero is returned for success, non-zero for the following reasons: input parameter is bad (-1)
int Servo_Disable ( ServoHandle_t  hServo)

Disable servo operation.

Parameters
[in]hServois the servo handle

This function will disable the servo. All callbacks will be deleted and interrupts disabled, and the PWM output will be turned off.

Returns
Zero is returned for success, non-zero for the following reasons: input parameter is bad (-1); timer not initialized (-2)
int Servo_Calibrate ( ServoHandle_t  hServo,
int32_t  usecsPer90,
int32_t  usecsAtZero,
bool  reverseAngle 
)

Set the calibration parameters for the servo.

Parameters
[in]hServois the servo handle
[in]usecsPer90is the number of microseconds of pulse witdth change that represents 90 degrees of motion
[in]usecsAtZerois the pulse width in microseconds when the servo is at the position designated as zero
[in]reverseAngleis a flag that means that angle calculations should be reversed (reverses the sign of motion)

This function sets the parameters that are used for calibration of the servo movement. The values are dependent on the specific servos and the physical arrangement.

Returns
Zero is returned if successful, non-zero if there is an error. Reasons for error are: bad input parameter (-1).
int Servo_SetLimits ( ServoHandle_t  hServo,
int32_t  usecsMin,
int32_t  usecsMax 
)

Set the limits for the servo.

Parameters
[in]hServois the servo handle
[in]usecsMinis the minimum pulse width in microseconds
[in]usecsMaxis the maximum pulse width in microseconds

This function sets the limits that are used for determining the lower and upper bound for the pulse width that can be applied to the servo and represents the limits of range of motion. The values are dependent on the specific servos and the physical arrangement.

Returns
Zero is returned if successful, non-zero if there is an error. Reasons for error are: bad input parameter (-1).
int Servo_SetMotionParameters ( ServoHandle_t  hServo,
int32_t  rateDegPerSec 
)

Set servo motion parameters.

Parameters
[in]hServois the servo handle
[in]rateDegPerSecis the motion rate in degrees per second

This function will set the motion rate as specified in degrees per second. Internally this will be silently constrained to a minimum of 9 degrees per second. This is the rate that the servo will move when commanded using a Move() function.

Returns
Zero if successful, non-zero for the following reasons: bad input parameter (-1)
int Servo_SetPositionUsecs ( ServoHandle_t  hServo,
int32_t  usecs 
)

Set the servo position using the pulse width in microseconds.

Parameters
[in]hServois the servo handle
[in]usecsis the pulse width in microseconds

This function will set the servo PWM pulse width which represents a position. If the usecs value is outside the min and max defined for the servo, then the value will be constrained to the min or max with no error indicated.

Returns
Zero is returned upon success, non-zero for the following reasons: input parameter is bad (-1); timer not initialized (-2)
int Servo_SetPosition ( ServoHandle_t  hServo,
int32_t  centiDegrees 
)

Set the servo position using the pulse width in centi-degrees.

Parameters
[in]hServois the servo handle
[in]centiDegreesis the angle in centi-degrees

This function will set the servo position as specified in centi-degrees. The position will be constrained per the default or prior set limits.

Returns
Zero is returned upon success, non-zero for the following reasons: input parameter is bad (-1); timer not initialized (-2)
int32_t Servo_GetPositionUsecs ( ServoHandle_t  hServo)

Get the position of the servo in microseconds of pulse width.

Parameters
[in]hServois the servo handle

This function returns the current, absolute position of the servo in units of microseconds of pulse width.

Returns
The pulse with in microseconds or 0 if there is an error.
int32_t Servo_GetPosition ( ServoHandle_t  hServo)

Get the position of the servo in centi-degrees.

Parameters
[in]hServois the servo handle

This function returns the current, absolute position of the servo in units of centi-degrees.

Returns
The angle in centi-degrees or 0 if there is an error. Zero does not necessarily indicate an error because it is also a legitimate value for the angle.
int Servo_MoveUsecs ( ServoHandle_t  hServo,
int32_t  usecs,
void(*)(void *pObserverData)  pfnMotionObserver,
void *  pObserverData 
)

Move to position in microseconds pulse width, with motion control.

Parameters
[in]hServois the servo handle
[in]usecsis the position in microseconds of pulse width
[in]pfnMotionObserveris a callback function, called when motion is complete
[in]pObserverDatais caller supplied data pointer to be passed to the callback function

This function will move the servo to a new position. The position is specified as pulse width in microseconds. The servo is moved with motion control, which means that the servo is not immediately commanded to the new position but is moved gradually according to the motion parameters. This allows for smoother, more controlled motion. This starts the motion and returns right away, before the motion is complete. If the called supplied a callback function, then it will be called when the motion is complete.

Note
The callback function (pfnMotionObserver) will be called in interrupt context, so it must be short and non-blocking.
Returns
Zero is returned if successful, non-zero for the following reasons: servo handle is bad (-1); or any error returned by Servo_SetTickObserver().
int Servo_Move ( ServoHandle_t  hServo,
int32_t  centiDegrees,
void(*)(void *pObserverData)  pfnMotionObserver,
void *  pObserverData 
)

Move to position in centi-degrees, with motion control.

Parameters
[in]hServois the servo handle
[in]centiDegreesis the position in centi-degrees
[in]pfnMotionObserveris a callback function, called when motion is complete
[in]pObserverDatais caller supplied data pointer to be passed to the callback function

This function will move the servo to a new position. The position is specified as centi-degrees. The servo is moved with motion control, which means that the servo is not immediately commanded to the new position but is moved gradually according to the motion parameters. This allows for smoother, more controlled motion. This starts the motion and returns right away, before the motion is complete. If the called supplied a callback function, then it will be called when the motion is complete.

Note
The callback function (pfnMotionObserver) will be called in interrupt context, so it must be short and non-blocking.
Returns
Zero is returned if successful, non-zero for the following reasons: servo handle is bad (-1); or any error returned by Servo_SetTickObserver().
int Servo_SetTickObserver ( ServoHandle_t  hServo,
void(*)(void *pObserverData)  pfnServoTickObserver,
void *  pObserverData 
)

Set a callback function on the PWM timer tick.

Parameters
[in]hServois the servo handle
[in]pfnServoTickObserveris the callback function for timer ticks
[in]pObserverDatais the data to pass to the callback

This function will install a callback function that will be called once for each timer PWM period. Then the timer interrupts will be enabled so the callback should start getting called immediately. If NULL is passed as the callback function, then the callback is removed and interrupts disabled.

Note
The callback will be called in interrupt context, so it must be short and non-blocking.
Returns
Zero if successful, non-zero for the following reasons: bad handle (-1); timer not initialized (-2)
uint32_t Servo_ReadBatteryRaw ( void  )

Read the battery level in raw ADC counts.

This function returns the battery voltage as raw ADC counts (0-4095). It uses a moving average to smooth the voltage reading so the reading should be fairly smooth but will not respond to quick changes in battery voltage. This function should be called periodically in order to keep the moving average accurate. It should be used for the purpose of monitoring the battery state of charge and not for reading instantaneous voltage.

Note
  1. This function will start an ADC conversion and then poll-wait until the conversion is complete. This should only take a microsecond or two.
  2. This function assumes it is being used on a 12-servo BoosterPack board which has the battery voltage input on AIN2. If you are not using the Servo BoosterPack board, then you probably should not use this function.
  3. The ADC input will read bogus non-saturated values if the input goes above the reference voltage. The battery measuring circuit is designed for a battery voltage range of 6-9V. If you battery is above 9V you may read a non-saturated value on the ADC that is incorrect.
Returns
The raw ADC counts of the battery voltage.
uint32_t Servo_ReadBatteryMv ( void  )

Read the battery level in millivolts.

This function returns the battery voltage in millivolts. It uses Servo_ReadBatteryRaw to get the smoothed ADC counts and then applies a conversion to obtain millivolts.

See Also
Servo_ReadBatteryRaw
Returns
The battery voltage in millivolts.
void Servo_BatteryInit ( uint32_t  gain,
uint32_t  offset 
)

Initialize the servo battery monitor.

Parameters
[in]gainis the range of measurement, in millivolts
[in]offsetis the lowest measured voltage, in millivolts

This function will initialize the ADC peripheral to prepare for measuring the battery voltage using Servo_BatteryReadMv. The parameters gain and offset can be used to calibrate the measurement. If these values are zero, then nominal calibration values are used so they can be left at 0 if calibration data is not available. The calibration values are not arbitrary - they must match the tuning of the battery measuring circuit.

  • gain - this is the voltage range that is measurable by the monitor circuit, in millivolts. The circuit is designed for a nominal range of 6-9.3V so the range is 3300 mV.
  • offset - this is the offset point of the lowest measurable voltage. The circuit is designed for 6V so the nominal setting is 6000 mV.
    Note
    The servo battery monitoring functions are meant to be used with the Servo BoosterPack board which has a battery monitor circuit and uses AIN2 for the battery voltage.
    See Also
    Servo_ReadBatteryMv