basic pca9685

Fork of ic2_test_bus by Martin Simpson

Files at this revision

API Documentation at this revision

Comitter:
richnash
Date:
Mon Oct 29 14:56:07 2018 +0000
Parent:
0:2db41a0c2f17
Commit message:
basic pca9685

Changed in this revision

PCA9685.cpp Show annotated file Show diff for this revision Revisions of this file
PCA9685.h Show annotated file Show diff for this revision Revisions of this file
TextLCD.lib Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-os.lib Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show diff for this revision Revisions of this file
diff -r 2db41a0c2f17 -r dbe78e80d722 PCA9685.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PCA9685.cpp	Mon Oct 29 14:56:07 2018 +0000
@@ -0,0 +1,79 @@
+#include "PCA9685.h"
+#include "mbed.h"
+PCA9685::PCA9685(PinName sda, PinName scl, int addr) : i2c(sda, scl), _i2caddr(addr) {}
+
+void PCA9685::begin(void)
+{
+    reset();
+}
+
+void PCA9685::frequencyI2C(int freq)
+{
+    i2c.frequency(freq);
+}
+void PCA9685::write8(uint8_t address, uint8_t data)
+{
+    char cmd[2];
+    cmd[0] = address;
+    cmd[1] = data;
+    i2c.write(_i2caddr, cmd, 2);
+}
+
+char PCA9685::read8(char address)
+{
+    i2c.write(_i2caddr, &address, 1);
+    char rtn;
+    i2c.read(_i2caddr, &rtn, 1);
+    return rtn;
+}
+
+void PCA9685::reset(void)
+{
+    write8(PCA9685_MODE1, 0x0);
+}
+void PCA9685::setPrescale(uint8_t prescale) {
+    uint8_t oldmode = read8(PCA9685_MODE1);
+    uint8_t newmode = (oldmode&0x7F) | 0x10; // sleep
+    write8(PCA9685_MODE1, newmode); // go to sleep
+    wait_ms(5);
+    write8(PCA9685_PRESCALE, prescale); // set the prescaler
+    write8(PCA9685_MODE1, oldmode);
+    wait_ms(5);
+    write8(PCA9685_MODE1, oldmode | 0xa1);
+}
+void PCA9685::setPWMFreq(float freq)
+{
+    float prescaleval = 25000000;
+    prescaleval /= 4096;
+    prescaleval /= freq;
+    uint8_t prescale = floor(prescaleval  + 0.5) - 1;
+    setPrescale(prescale);
+}
+
+void PCA9685::setPWM(uint8_t num, uint16_t on, uint16_t off)
+{
+    char cmd[5];
+    cmd[0] = LED0_ON_L + 4 * num;
+    cmd[1] = on;
+    cmd[2] = on >> 8;
+    cmd[3] = off;
+    cmd[4] = off >> 8;
+    i2c.write(_i2caddr, cmd, 5);
+}
+
+void PCA9685::setPWM_ALL(uint16_t on, uint16_t off)
+{
+    char cmd[5];
+    
+    for (uint8_t num = 0; num < 16; num++)
+        {
+        cmd[0] = LED0_ON_L + 4 * num;
+        cmd[1] = on;
+        cmd[2] = on >> 8;
+        cmd[3] = off;
+        cmd[4] = off >> 8;
+        i2c.write(_i2caddr, cmd, 5);
+        wait(0.0005);
+        }
+    
+}
\ No newline at end of file
diff -r 2db41a0c2f17 -r dbe78e80d722 PCA9685.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PCA9685.h	Mon Oct 29 14:56:07 2018 +0000
@@ -0,0 +1,114 @@
+/**Library for PCA9685 16-channel, 12-bit PWM Fm+ I²C-bus LED controller
+* Example code
+* @code
+*
+*#include"PCA9685.h"
+*#include"mbed.h"
+*
+*
+*
+*PCA9685 pwm(D14,D15);
+* 
+*void setServoPulse(uint8_t n, float pulse) {
+*    float pulselength = 10000;   // 10,000 units per seconds
+*    pulse = 4094 * pulse / pulselength;
+*    pwm.setPWM(n, 0, pulse);
+*}
+* 
+*void initServoDriver() {
+*    pwm.begin();
+*    pwm.setPrescale(64);    //This value is decided for 10ms interval.
+*    pwm.frequencyI2C(400000); //400kHz
+*}
+* 
+* int main() {
+*
+*    while(1){
+*    initServoDriver();
+*    wait(0.2);
+*    setServoPulse(0, 2300);
+*    setServoPulse(1, 500);    
+*    wait(0.5);//delay necessary to perform the action
+*    setServoPulse(0, 1350);
+*    setServoPulse(1, 1350);
+*    wait(0.5);
+*    setServoPulse(0,550);
+*    setServoPulse(1, 2250);
+*    wait(0.5);
+*    setServoPulse(0, 2300);
+*    wait(2);
+*    for (int mov = 550; mov < 2300; mov++){
+*    setServoPulse(0, mov);
+*    wait(0.001); 
+*    }  
+*    for (int mov = 500; mov < 2200; mov++){
+*    setServoPulse(1, mov);
+*    wait(0.001); 
+*    }     
+*   }
+*}
+*@endcode
+*
+*/
+#ifndef PCA9685_H
+#define PCA9685_H
+
+#include "mbed.h"
+#include <cmath>
+//register definitions
+#define PCA9685_SUBADR1 0x2
+#define PCA9685_SUBADR2 0x3
+#define PCA9685_SUBADR3 0x4
+
+#define PCA9685_MODE1 0x0
+#define PCA9685_PRESCALE 0xFE
+
+#define LED0_ON_L 0x6
+#define LED0_ON_H 0x7
+#define LED0_OFF_L 0x8
+#define LED0_OFF_H 0x9
+
+#define ALLLED_ON_L 0xFA
+#define ALLLED_ON_H 0xFB
+#define ALLLED_OFF_L 0xFC
+#define ALLLED_OFF_H 0xFD
+
+
+class PCA9685
+{
+public:
+    PCA9685(PinName sda, PinName scl, int addr = 0x80);
+    
+    void frequencyI2C(int freq);
+    
+    void begin(void); //Initialize the controller
+    void reset(void); //Reset the controller
+    void setPrescale(uint8_t prescale);//setPrescale(prescale)
+    /** Set prescale
+     *
+     *  @param prescale: set scale for the PWM frequency
+     *
+     */
+    void setPWMFreq(float freq);//Set the pwm frequency
+    /** Set frequency
+      *
+      * @param frequency in Hz
+      *
+      */
+    void setPWM(uint8_t num, uint16_t on, uint16_t off);//SetPWM(channel, on, off)
+    /** Set the start (on) and the end (off) of the part of the PWM pulse of the channel
+     *  @param channel : from 0 to 15 the channel the should be update
+     *  @param  on: from 0 to 4095 the tick when the signal should pass from low to high
+     *  @param off: from 0 to 4095 the tick when the signal should pass from high to low
+     */
+     
+     void setPWM_ALL(uint16_t on, uint16_t off); //SetPWM(on, off)
+     
+private:
+    void write8(uint8_t address, uint8_t data);
+    char read8(char address);
+    int _i2caddr;
+    I2C i2c;
+};
+
+#endif
\ No newline at end of file
diff -r 2db41a0c2f17 -r dbe78e80d722 TextLCD.lib
--- a/TextLCD.lib	Tue Jan 13 15:48:33 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/simon/code/TextLCD/#308d188a2d3a
diff -r 2db41a0c2f17 -r dbe78e80d722 main.cpp
--- a/main.cpp	Tue Jan 13 15:48:33 2015 +0000
+++ b/main.cpp	Mon Oct 29 14:56:07 2018 +0000
@@ -1,60 +1,126 @@
 #include "mbed.h"
-#include "TextLCD.h"
+#include"PCA9685.h"
  
-#define Device_Name_ADDR   (0xEE) // Device You Wish to Use Address - using i2c Address
+#define I2C_ADDR_PCA9685   (0xEE) // Device You Wish to Use Address - using i2c Address
+
 #define WRITE              (0x00) // i2c Write bit
 #define READ               (0x01) // i2c Read bit
 
-/* This is a program to demonstrate the ease of use of the i2c bus
-   and Detecting any Devices connected and returning their addresses
-   Do not forget that Pull Up resistors are required on the SDA and SCL lines
-   (Typically 2K ohms for 400KHz bus speeds) NB these could be provided on the PCB Modules.
-   These are required since devices connected with the i2c will have 'open drain' (or open collector)
-   circuitry to allow wire 'ORing' of their respective connections. Used with a stm32-Nucleo-F401RE.
-   Used both Serial Port to USB and LCD Module to display results can use either or both just comment out if you wish.
-   Martin Simpson January 2015 */
+// ----- NOTES -----
+// 4.7k resistor pull up to 3.3v on SDA and SDL lines
+// SCL is green on our boards
+// 
 
-I2C i2c(I2C_SDA, I2C_SCL);       //I2C Class Pin Assignments see I2C.h
- 
 Serial pc(SERIAL_TX, SERIAL_RX); //Serial Class Pin Assignments see Serial.h
 
-TextLCD lcd(D2,D3,D4,D5,D6,D7);  //Text LCD Class assignments RS, E, D4 to D7 see TextLCD.h
+
+PCA9685 pwm( I2C_SDA, I2C_SCL );
+
+
+bool I2CScan( I2C *i2c, int Device_Adress )
+{
+    char ucdata_write[2];
+    
+    ucdata_write[0]=0;
+    ucdata_write[1]=0;
+    
+    // try writing to the device
+    if (!i2c->write((Device_Adress|WRITE), ucdata_write, 1, 0))// Check for ACK from i2c Device NB I am 'ORing' the Write Bit
+        {
+        // all good
+        return true;
+        }
+    // no device found
+    return false;
+}
+
 
-char ucdata_write[2];
-short count=0;
+int I2CScan( I2C *i2c )
+{
+    short count=0;
+    
+    // scan all channels
+    pc.printf("====================================================\n\r");
+    pc.printf("I2CScan (ALL Channels)\n\r");
+    for (int Device_Adress=0; Device_Adress<=0xFE; Device_Adress+=2)//Stepping in 2 Because Read/Write use LSB
+        {
+        if( I2CScan(i2c, Device_Adress) )
+            {
+            pc.printf("I2CScan: %#4x\n\r", Device_Adress );
+            count++;
+            }
+        }
+    pc.printf("%d Devices detected!\n\r",count);
+    pc.printf("====================================================\n\r\n\r");
+    
+    return count;
+}
+
+
+
+void PCA9685_initDriver() {
+    pwm.begin();
+    pwm.setPWMFreq(1600);     // max frequency
+    pwm.frequencyI2C(400000); //400kHz fast I2C comunication
+}
+
 
 int main()
 {
-    unsigned int uibaudrate=115200;
-    pc.baud(uibaudrate);
+    I2C i2c(I2C_SDA, I2C_SCL);       //I2C Class Pin Assignments see I2C.h
     
     unsigned int uifrequency=400000; //400KHz for i2c Max
-    i2c.frequency (uifrequency);
+    unsigned int uibaudrate=115200;
     
-    pc.printf("\n\rHello World ");
-    pc.printf("at %u BAUD and %uKHz i2c Frequency\n\r",uibaudrate,uifrequency/1000);
-    pc.printf("Using mbed.org Martin\n\r");
+    // debug
+    pc.baud(uibaudrate);
+    pc.printf("\n\r ---- I2C Scanner ---- \n\r");
     
-    lcd.cls();lcd.locate(0,0); //Tidy up LCD Display
-
-    ucdata_write[0]=0;ucdata_write[1]=0;
-
-    for (int Device_Adress=0;Device_Adress<=0xFE;Device_Adress+=2)//Stepping in 2 Because Read/Write use LSB
-    {
-    if (!i2c.write((Device_Adress|WRITE), ucdata_write, 1, 0))// Check for ACK from i2c Device NB I am 'ORing' the Write Bit
+    // setup i2c
+    i2c.frequency(uifrequency);
+    pc.printf("I2C: %uKHz\n\r", uifrequency/1000);
+    
+    // scan
+    I2CScan(&i2c);
+    
+    // Init the PCA9685 on the default addr
+    PCA9685_initDriver();
+    
+    // loop led's on channel 0 and 1
+    while(1)
         {
-            pc.printf("ACK from the Device at Address %#4x\n\r",Device_Adress);
-            lcd.printf("ACK at:%#4x\n",Device_Adress);
-            count=count+1;
-            wait(2);
+        for (int i = 0; i < 4095; i=i+24)
+            {
+            pwm.setPWM_ALL(4095-i,0);
+            wait(0.0005);
+            }
+        for (int i = 4094; i > 0; i=i-24)
+            {
+            pwm.setPWM_ALL(4095-i,0);
+            wait(0.0005);
+            }
+/*
+        pc.printf("1.");
+        for (int i = 0; i < 4095; i=i+8)
+            {
+            pwm.setPWM(1,4095-i,0);
+            wait(0.0005);
+            
+            pwm.setPWM(2,i,0);
+            wait(0.0005);            
+            }
+        
+        pc.printf("2.");
+        for (int i = 4094; i > 0; i=i-8)
+            {
+            pwm.setPWM(1,4095-i,0);
+            wait(0.0005);
+            
+            pwm.setPWM(2,i,0);
+            wait(0.0005); 
+            }
+        pc.printf("\n\r");
+*/
         }
-        else
-        {
-            //Left the following in for development/Future coding
-            //pc.printf("\n\rCannot get an ACK from the Device check connections!\n\r");
-            //lcd.printf("No ACK from\nDevice!");
-        }
-    }
-    pc.printf("\n\r %d Devices have been detected!\n\r",count);
-    lcd.printf("%d Dev Found!",count);
 }
+
diff -r 2db41a0c2f17 -r dbe78e80d722 mbed-os.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-os.lib	Mon Oct 29 14:56:07 2018 +0000
@@ -0,0 +1,1 @@
+https://github.com/ARMmbed/mbed-os/#ed7fe215002a9c50452acfecda633ce47e00c614
diff -r 2db41a0c2f17 -r dbe78e80d722 mbed.bld
--- a/mbed.bld	Tue Jan 13 15:48:33 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/mbed_official/code/mbed/builds/4fc01daae5a5
\ No newline at end of file