Library for using the TLC5940 as a servo controller.

Dependencies:   FastPWM

Dependents:   TLC5940ServoTest

Files at this revision

API Documentation at this revision

Comitter:
dudanian
Date:
Tue Oct 21 06:04:24 2014 +0000
Parent:
1:ba4e0390f72e
Child:
3:3b04a122e508
Commit message:
Big changes to the code. Removed Servo files and made an inner class inside TLC5940Servo.

Changed in this revision

Servo.cpp Show diff for this revision Revisions of this file
Servo.h Show diff for this revision Revisions of this file
TLC5940Servo.cpp Show annotated file Show diff for this revision Revisions of this file
TLC5940Servo.h Show annotated file Show diff for this revision Revisions of this file
--- a/Servo.cpp	Tue Oct 21 02:32:57 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/* mbed R/C Servo Library
- *  
- * Copyright (c) 2007-2010 sford, cstyles
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- 
-#include "Servo.h"
-#include "mbed.h"
-
-static float clamp(float value, float min, float max) {
-    if(value < min) {
-        return min;
-    } else if(value > max) {
-        return max;
-    } else {
-        return value;
-    }
-}
-
-Servo::Servo() {
-    calibrate();
-    write(0.5);
-}
-
-// used source code, but converted pwm pulse to 12 bit value
-// assuming 20ms period, divide to get percentage and multiply to get value
-void Servo::write(float percent) {
-    float offset = _range * 2.0 * (percent - 0.5);
-    _pw = (int)((0.0015 + clamp(offset, -_range, _range))/0.02 * 4096.0);
-    _p = clamp(percent, 0.0, 1.0);
-}
-
-/*void Servo::position(float degrees) {
-    /* not used for now
-    float offset = _range * (degrees / _degrees);
-    _pw = 0.0015 + clamp(offset, -_range, _range); // need to change
-    
-}*/
-
-void Servo::calibrate(float range, float degrees) {
-    _range = range;
-    _degrees = degrees;
-}
-
-float Servo::read() {
-    return _p;
-}
-
-int Servo::pulsewidth() {
-    return _pw;
-}
-
-float& Servo::operator= (float percent) { 
-    write(percent);
-    return _p;
-}
--- a/Servo.h	Tue Oct 21 02:32:57 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/* mbed R/C Servo Library
- * Copyright (c) 2007-2010 sford, cstyles
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-  
-#ifndef SERVO_H
-#define SERVO_H
-
-#include "mbed.h"
-
-/** 
- * Servo control class, modified to be used with the TLC5940 PWM IC
- *
- */
-class Servo {
-
-public:
-    /** Create a servo object NOT connected to a specified PwmOut pin
-     */
-    Servo();
-    
-    /** Set the servo position, normalised to it's full range
-     *
-     * @param percent A normalised number 0.0-1.0 to represent the full range.
-     */
-    void write(float percent);
-    
-    /**  Read the servo motors current position
-     *
-     * @param returns A normalised number 0.0-1.0  representing the full range.
-     */
-    float read();
-
-    /**  Read the servo motors current pulse width converted to TLC5940 PWM value
-     *
-     * @param returns A number between 0 and 4096 representing a pulse width.
-     */
-    int pulsewidth();
-    
-    /**  Allows calibration of the range and angles for a particular servo
-     *
-     * @param range Pulsewidth range from center (1.5ms) to maximum/minimum position in seconds
-     * @param degrees Angle from centre to maximum/minimum position in degrees
-     */
-    void calibrate(float range = 0.0005, float degrees = 45.0); 
-        
-    /**  Shorthand for the write and read functions */
-    float& operator= (float percent);
-
-protected:
-    int _pw;
-    float _range;
-    float _degrees;
-    float _p;
-};
-
-#endif
--- a/TLC5940Servo.cpp	Tue Oct 21 02:32:57 2014 +0000
+++ b/TLC5940Servo.cpp	Tue Oct 21 06:04:24 2014 +0000
@@ -1,71 +1,118 @@
 #include "TLC5940Servo.h"
 
-TLC5940Servo::TLC5940Servo(PinName MOSI, PinName SCLK, PinName XLAT, PinName BLANK, 
-        PinName GSCLK, const int number) : number(number), spi(MOSI, NC, SCLK), gsclk(GSCLK),
-                                           blank(BLANK), xlat(XLAT), newData(false), need_xlat(false)
-{   
-    // Configure SPI to 12 bits and SPI_SPEED
+TLC5940Servo::TLC5940Servo(PinName MOSI, PinName SCLK, PinName XLAT, PinName BLANK,
+                           PinName GSCLK, const int number) : number(number), spi(MOSI, NC, SCLK), gsclk(GSCLK),
+    blank(BLANK), xlat(XLAT), newData(false), need_xlat(false) {
     spi.format(12, 0);
     spi.frequency(SPI_SPEED);
-    
-    // Set output pin states
+
     xlat = 0;
     blank = 1;
-    
-    // Call the reset function every 4096 PWM outputs
+
     reset_ticker.attach_us(this, &TLC5940Servo::reset, (1000000.0/GSCLK_SPEED) * 4096.0);
-    
-    // Configure FastPWM output for GSCLK frequency at 50% duty cycle
+
     gsclk.period_us(1000000.0/GSCLK_SPEED);
     gsclk.write(.5);
 
-    // Create a data buffer to store the current Servo states
-    dataBuffer = new int[16 * number]();
+    servos = new Servo[16 * number];
 }
 
-TLC5940Servo::~TLC5940Servo()
-{
-    // Delete the buffer
-    delete[] dataBuffer;
+TLC5940Servo::~TLC5940Servo() {
+    delete[] servos;
+}
+
+void TLC5940Servo::calibrate(int index, float range, float degrees) {
+    servos[index].calibrate(range, degrees);
 }
 
-
-int& TLC5940Servo::operator[](int index)
-{
-    // Return the start of the correct data chunk
-    newData = true;
-    return dataBuffer[index];
+void TLC5940Servo::calibrate(float range, float degrees) {
+    for (int i = 0; i < 16 * number; i++)
+        servos[i].calibrate(range, degrees);
 }
 
-void TLC5940Servo::reset()
-{
+TLC5940Servo::Servo& TLC5940Servo::operator[](int index) {
+    newData = true;
+    return servos[index];
+}
+
+// most complicated method, heavily commented
+void TLC5940Servo::reset() {
     gsclk.write(0); // turn off gsclk
     blank = 1; // start reset
-    
+
     // latch data if new data was written
     if (need_xlat) {
         xlat = 1;
         xlat = 0;
-        
+
         need_xlat = false;
     }
-    
+
     blank = 0; // turn off reset
     gsclk.write(.5); // restart gsclk
 
     if (newData) {
-        
-        // Send GS data backwards - this makes the GS_buffer[0] index correspond to OUT0 
-        for (int i = (16 * number) - 1; i >= 0; i--)
-        {
+
+        // Send data backwards - this makes servos[0] index correspond to OUT0
+        for (int i = (16 * number) - 1; i >= 0; i--) {
             // Get the lower 12 bits of the buffer and send
-            spi.write(dataBuffer[i] & 0xFFF);
+            spi.write(servos[i].pulsewidth() & 0xFFF);
         }
-        
+
         // Latch after current GS data is done being displayed
         need_xlat = true;
-        
+
         // No new data to send (we just sent it!)
         newData = false;
     }
-}
\ No newline at end of file
+}
+
+/**
+ * TLC5940 Inner Servo class
+ * 
+ * Helps to abstract some of the details away
+ */
+static float clamp(float value, float min, float max) {
+    if(value < min) {
+        return min;
+    } else if(value > max) {
+        return max;
+    } else {
+        return value;
+    }
+}
+
+TLC5940Servo::Servo::Servo() {
+    calibrate();
+    write(0.5);
+}
+
+// used source code, but converted pwm pulse to 12 bit value
+// assuming 20ms period, divide to get percentage and multiply to get value
+void TLC5940Servo::Servo::write(float percent) {
+    float offset = _range * 2.0 * (percent - 0.5);
+    _pw = (int)(4095 - ((0.0015 + clamp(offset, -_range, _range))/0.02 * 4096.0));
+    _p = clamp(percent, 0.0, 1.0);
+}
+
+void TLC5940Servo::Servo::calibrate(float range, float degrees) {
+    _range = range;
+    _degrees = degrees;
+}
+
+float TLC5940Servo::Servo::read() {
+    return _p;
+}
+
+int TLC5940Servo::Servo::pulsewidth() {
+    return _pw;
+}
+
+TLC5940Servo::Servo& TLC5940Servo::Servo::operator= (float percent) { 
+    write(percent);
+    return *this;
+}
+
+TLC5940Servo::Servo::operator float() {
+    return read();
+}
--- a/TLC5940Servo.h	Tue Oct 21 02:32:57 2014 +0000
+++ b/TLC5940Servo.h	Tue Oct 21 06:04:24 2014 +0000
@@ -2,7 +2,7 @@
 #define TLC5940Servo_H
 
 #include "FastPWM.h"
- 
+
 /**
   * SPI speed used by the mbed to communicate with the TLC5940
   * The TLC5940 supports up to 30Mhz. This should be kept as high
@@ -14,65 +14,81 @@
   * The rate at which the GSCLK pin is pulsed
   * This also controls how often the reset function is called
   * The rate at which the reset function is called can be calculated by: (1/GSCLK_SPEED) * 4096
-  * 
-  * Since the Servo period is 20ms (50Hz), we set this clock to 50*4096 = 204,800Hz according to the eqn above
-  * Also, since this clock is so slow, there is no real limit to the number of TLC5940s you can chain
+  *
+  * Since the Servo period is 20ms (50Hz), we set this clock to 50*4096 = 204,800Hz according to the equation above
+  * Also, since this clock is so slow, there is almost no limit to the number of TLC5940s you can chain
   */
 #define GSCLK_SPEED 204800
 
 /**
-  *  This class controls a TLC5940 PWM driver to control Servo motors.
-  *  It supports sending grayscale PWM data calibrated for Servos, but it does not support error checking or writing the EEPROM.
-  *  This class uses the FastPWM library by Erik Olieman to continuously pulse the GSLCK pin without CPU intervention. After
-  *  4096 pulses, the private member funciton reset is called by the ticker. It resets the display by pulsing the BLANK pin. If new
-  *  data has been set to be sent by the function setNewData, it is sent here.
+  *  This class controls a TLC5940 PWM driver to control Servo motors. It supports sending grayscale PWM data calibrated for Servos,
+  *  but it does not support error checking or writing the EEPROM. After 4096 pulses, the private member funciton reset is called by
+  *  the ticker. It resets the driver by pulsing the BLANK pin. If new data has been set to be sent by the function setNewData, it
+  *  is sent here.
+  *  
+  *  This class is a heavily modified versoin of the TLC5940 library created by Spencer Davis. This class also uses the FastPWM
+  *  library by Erik Olieman to continuously pulse the GSLCK pin without CPU intervention. 
   */
-class TLC5940Servo
-{
+class TLC5940Servo {
 public:
+    /* 
+     * Servo inner class to abstract some of the details. Based off of the mbed official Servo class
+     */
+    class Servo {
+    public:
+        Servo();
+        void write(float percent);
+        void calibrate(float range=0.0005, float degrees=45.0);
+        float read();
+        int pulsewidth();
+        Servo& operator= (float percent);
+        operator float();
+    private:
+        float _p;
+        float _range;
+        float _degrees;
+        int _pw;
+    };
     /**
-      *  Set up the TLC5940
-      * 
-      *  @param MOSI - The MOSI pin of the SPI bus
-      *  @param SCLK - The SCK pin of the SPI bus
-      *  @param XLAT - The XLAT pin of the TLC5940(s)
-      *  @param BLANK - The BLANK pin of the TLC5940(s)
-      *  @param GSCLK - The GSCLK pin of the TLC5940(s)
-      *  @param number - The number of TLC5940s (optional)
+      * Set up the TLC5940
+      *
+      * @param MOSI - The MOSI pin of the SPI bus
+      * @param SCLK - The SCK pin of the SPI bus
+      * @param XLAT - The XLAT pin of the TLC5940(s)
+      * @param BLANK - The BLANK pin of the TLC5940(s)
+      * @param GSCLK - The GSCLK pin of the TLC5940(s)
+      * @param number - The number of TLC5940s (optional)
       */
     TLC5940Servo(PinName MOSI, PinName SCLK, PinName XLAT, PinName BLANK,
-            PinName GSCLK, const int number = 1);
-    
-    // Destructor used to delete memory
+                 PinName GSCLK, const int number = 1);
+
+    /**
+     * Destructor used to delete memory
+     */
     ~TLC5940Servo();
 
-    /**  Allows calibration of the range and angles for all servos
-     *
-     * @param range Pulsewidth range from center (1.5ms) to maximum/minimum position in seconds
-     * @param degrees Angle from centre to maximum/minimum position in degrees
-     */
-    void calibrate(float range, float degrees); 
-    
-    /**  Allows calibration of the range and angles for a particular servo
+    /**
+     * Allows calibration of the range and angles for a particular servo
      *
      * @param range Pulsewidth range from center (1.5ms) to maximum/minimum position in seconds
      * @param degrees Angle from centre to maximum/minimum position in degrees
      */
     void calibrate(int index, float range, float degrees);
-    
-    /**  Allows calibration of the range and angles for a particular servo
+
+    /**
+     * Allows calibration of the range and angles for all servos
      *
      * @param range Pulsewidth range from center (1.5ms) to maximum/minimum position in seconds
      * @param degrees Angle from centre to maximum/minimum position in degrees
      */
-    void calibrate(float *range, float *degrees);  
-    
+    void calibrate(float range, float degrees);
+
     /**
-      *  Set the next chunk of grayscale data to be sent
-      *  @param data - Array of 16 bit shorts containing 16 12 bit grayscale data chunks per TLC5940
-      *  @note These must be in intervals of at least (1/GSCLK_SPEED) * 4096 to be sent
+      * Array index operator for reading and writing from servos
+      *
+      * @param index Index of Servo in array
       */
-    int& operator[](int index);
+    Servo& operator[](int index);
 
 private:
     // SPI port - only MOSI and SCK are used
@@ -98,7 +114,7 @@
     volatile bool need_xlat;
 
     // Buffers to store data until it is sent
-    int* dataBuffer;
+    Servo* dataBuffer;
 
     // Function to reset the display and send the next chunks of data
     void reset();