Richard Nash
/
i2c_pca9685_test1
basic pca9685
Fork of ic2_test_bus by
Revision 1:dbe78e80d722, committed 2018-10-29
- Comitter:
- richnash
- Date:
- Mon Oct 29 14:56:07 2018 +0000
- Parent:
- 0:2db41a0c2f17
- Commit message:
- basic pca9685
Changed in this revision
--- /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
--- /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
--- 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
--- 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); } +
--- /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
--- 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