A feature complete driver for the PCA9952/55 LED driver from NXP.

Dependents:   PCA9955_HelloWorld

Revision:
1:016f916c5579
Parent:
0:7b3cbb5a53b8
Child:
4:6ca7ab31c5fb
--- a/PCA9955.cpp	Tue Nov 05 21:16:25 2013 +0000
+++ b/PCA9955.cpp	Thu Nov 07 21:16:07 2013 +0000
@@ -16,17 +16,27 @@
 
 #include "PCA9955.h"
 
-PCA9955::PCA9955(PinName sda, PinName scl, Address addr) : m_I2C(sda, scl)
+PCA9955::PCA9955(PinName sda, PinName scl, Address addr) : m_I2C(sda, scl), m_ADDR((int)addr)
 {
-    //Set the internal device address
-    m_Addr = (int)addr;
+    //Set the I2C bus frequency to 400kHz
+    m_I2C.frequency(400000);
 }
 
-bool PCA9955::open(void)
+bool PCA9955::open()
 {
     //Probe for the PCA9952/55 using a Zero Length Transfer
-    if (!m_I2C.write(m_Addr, NULL, 0)) {
-        //NOTE: We don't reset here as SWRST may reset other I2C devices as well
+    if (!m_I2C.write(m_ADDR, NULL, 0)) {
+        //NOTE: We don't issue a SWRST here since it might reset other I2C devices as well
+
+        //Read the current 8-bit register value
+        char value = read(REG_MODE1);
+
+        //Configure Auto-Increment for 0x00 to 0x41
+        value &= ~(1 << 5); //AI0 bit
+        value &= ~(1 << 6); //AI1 bit
+
+        //Write the value back out
+        write(REG_MODE1, value);
 
         //Return success
         return true;
@@ -36,7 +46,7 @@
     }
 }
 
-void PCA9955::reset(void)
+void PCA9955::reset()
 {
     //The SWRST magic data byte
     char data = 0x06;
@@ -48,7 +58,7 @@
     wait_ms(10);
 }
 
-bool PCA9955::allCallEnabled(void)
+bool PCA9955::allCallEnabled()
 {
     //Read the 8-bit register value
     char value = read(REG_MODE1);
@@ -75,7 +85,7 @@
     write(REG_MODE1, value);
 }
 
-bool PCA9955::subCall3Enabled(void)
+bool PCA9955::subCall3Enabled()
 {
     //Read the 8-bit register value
     char value = read(REG_MODE1);
@@ -102,7 +112,7 @@
     write(REG_MODE1, value);
 }
 
-bool PCA9955::subCall2Enabled(void)
+bool PCA9955::subCall2Enabled()
 {
     //Read the 8-bit register value
     char value = read(REG_MODE1);
@@ -129,7 +139,7 @@
     write(REG_MODE1, value);
 }
 
-bool PCA9955::subCall1Enabled(void)
+bool PCA9955::subCall1Enabled()
 {
     //Read the 8-bit register value
     char value = read(REG_MODE1);
@@ -156,7 +166,7 @@
     write(REG_MODE1, value);
 }
 
-PCA9955::PowerMode PCA9955::powerMode(void)
+PCA9955::PowerMode PCA9955::powerMode()
 {
     //Read the 8-bit register value
     char value = read(REG_MODE1);
@@ -183,7 +193,7 @@
     write(REG_MODE1, value);
 }
 
-PCA9955::OutputChangeMode PCA9955::outputChangeMode(void)
+PCA9955::OutputChangeMode PCA9955::outputChangeMode()
 {
     //Read the 8-bit register value
     char value = read(REG_MODE2);
@@ -210,7 +220,7 @@
     write(REG_MODE2, value);
 }
 
-PCA9955::GroupMode PCA9955::groupMode(void)
+PCA9955::GroupMode PCA9955::groupMode()
 {
     //Read the 8-bit register value
     char value = read(REG_MODE2);
@@ -237,7 +247,7 @@
     write(REG_MODE2, value);
 }
 
-bool PCA9955::overTemp(void)
+bool PCA9955::overTemp()
 {
     //Read the current 8-bit register value
     char value = read(REG_MODE2);
@@ -322,7 +332,7 @@
     write(reg, value);
 }
 
-float PCA9955::groupDuty(void)
+float PCA9955::groupDuty()
 {
     //Return the value as a float
     return groupDuty_char() / 255.0f;
@@ -340,7 +350,7 @@
     groupDuty_char((char)(duty * 255.0f));
 }
 
-char PCA9955::groupDuty_char(void)
+char PCA9955::groupDuty_char()
 {
     //Return the 8-bit register value
     return read(REG_GRPPWM);
@@ -352,7 +362,7 @@
     write(REG_GRPPWM, duty);
 }
 
-float PCA9955::groupBlinkPeriod(void)
+float PCA9955::groupBlinkPeriod()
 {
     //Read the 8-bit register value
     char value = groupBlinkPeriod_char();
@@ -382,7 +392,7 @@
     groupBlinkPeriod_char(value);
 }
 
-char PCA9955::groupBlinkPeriod_char(void)
+char PCA9955::groupBlinkPeriod_char()
 {
     //Return the 8-bit register value
     return read(REG_GRPFREQ);
@@ -454,7 +464,7 @@
     write(REG_IREF0 + (char)output, iref);
 }
 
-char PCA9955::outputDelay(void)
+char PCA9955::outputDelay()
 {
     //Return the 8-bit register value (minus the top 4 bits)
     return read(REG_OFFSET) & 0x0F;
@@ -466,7 +476,7 @@
     write(REG_OFFSET, clocks & 0x0F);
 }
 
-char PCA9955::subCall1Addr(void)
+char PCA9955::subCall1Addr()
 {
     //Return the 8-bit address
     return read(REG_SUBADR1);
@@ -478,7 +488,7 @@
     write(REG_SUBADR1, addr);
 }
 
-char PCA9955::subCall2Addr(void)
+char PCA9955::subCall2Addr()
 {
     //Return the 8-bit address
     return read(REG_SUBADR2);
@@ -490,7 +500,7 @@
     write(REG_SUBADR2, addr);
 }
 
-char PCA9955::subCall3Addr(void)
+char PCA9955::subCall3Addr()
 {
     //Return the 8-bit address
     return read(REG_SUBADR3);
@@ -502,7 +512,7 @@
     write(REG_SUBADR3, addr);
 }
 
-char PCA9955::allCallAddr(void)
+char PCA9955::allCallAddr()
 {
     //Return the 8-bit address
     return read(REG_ALLCALLADR);
@@ -534,6 +544,19 @@
     writeMulti(buff, 5);
 }
 
+void PCA9955::getOutputDuties(float* duties)
+{
+    char buff[16];
+
+    //Read all of the duty cycles as unsigned chars first
+    getOutputDuties_char(buff);
+
+    //Convert all of the duty cycles to percents
+    for (int i = 0; i < 16; i++) {
+        duties[i] = buff[i] / 255.0f;
+    }
+}
+
 void PCA9955::allOutputDuties(float duty)
 {
     //Range check the value
@@ -546,12 +569,64 @@
     allOutputDuties_char((char)(duty * 255.0f));
 }
 
+void PCA9955::allOutputDuties(float* duties)
+{
+    char buff[17];
+
+    //Assemble the sending array
+    buff[0] = REG_PWM0 | REG_AUTO_INC;
+    for (int i = 1; i < 17; i++) {
+        //Range check the value
+        if (duties[i - 1] < 0.0f)
+            duties[i - 1] = 0.0f;
+        if (duties[i - 1] > 1.0f)
+            duties[i - 1] = 1.0f;
+
+        //Convert the value to a char and write it
+        buff[i] = duties[i - 1] * 255.0f;
+    }
+
+    //Send the array
+    writeMulti(buff, 17);
+}
+
+void PCA9955::getOutputDuties_char(char* duties)
+{
+    //Read all of the duty cycles at once
+    readMulti(REG_PWM0 | REG_AUTO_INC, duties, 16);
+}
+
 void PCA9955::allOutputDuties_char(char duty)
 {
     //Write the new 8-bit register value
     write(REG_PWMALL, duty);
 }
 
+void PCA9955::allOutputDuties_char(char* duties)
+{
+    char buff[17];
+
+    //Assemble the sending array
+    buff[0] = REG_PWM0 | REG_AUTO_INC;
+    memcpy(buff + 1, duties, 16);
+
+    //Send the array
+    writeMulti(buff, 17);
+}
+
+void PCA9955::getOutputCurrents(float* irefs)
+{
+    char buff[16];
+
+    //Read all of the current references as unsigned chars first
+    getOutputCurrents_char(buff);
+
+    //Convert all of the duty cycles to percents
+    for (int i = 0; i < 16; i++) {
+        irefs[i] = buff[i] / 255.0f;
+    }
+}
+
 void PCA9955::allOutputCurrents(float iref)
 {
     //Range check the value
@@ -564,13 +639,52 @@
     allOutputCurrents_char((char)(iref * 255.0f));
 }
 
+void PCA9955::allOutputCurrents(float* irefs)
+{
+    char buff[17];
+
+    //Assemble the sending array
+    buff[0] = REG_IREF0 | REG_AUTO_INC;
+    for (int i = 1; i < 17; i++) {
+        //Range check the value
+        if (irefs[i - 1] < 0.0f)
+            irefs[i - 1] = 0.0f;
+        if (irefs[i - 1] > 1.0f)
+            irefs[i - 1] = 1.0f;
+
+        //Convert the value to a char and write it
+        buff[i] = irefs[i - 1] * 255.0f;
+    }
+
+    //Send the array
+    writeMulti(buff, 17);
+}
+
+void PCA9955::getOutputCurrents_char(char* irefs)
+{
+    //Read all of the current references at once
+    readMulti(REG_IREF0 | REG_AUTO_INC, irefs, 16);
+}
+
 void PCA9955::allOutputCurrents_char(char iref)
 {
     //Write the new 8-bit register value
     write(REG_IREFALL, iref);
 }
 
-unsigned short PCA9955::faultTest(void)
+void PCA9955::allOutputCurrents_char(char* irefs)
+{
+    char buff[17];
+
+    //Assemble the sending array
+    buff[0] = REG_IREF0 | REG_AUTO_INC;
+    memcpy(buff + 1, irefs, 16);
+
+    //Send the array
+    writeMulti(buff, 17);
+}
+
+unsigned short PCA9955::faultTest()
 {
     //Read the current 8-bit register value
     char value = read(REG_MODE2);
@@ -594,27 +708,25 @@
     return flags;
 }
 
+PCA9955& PCA9955::operator=(float value)
+{
+    //Set all of the output duties
+    allOutputDuties(value);
+    return *this;
+}
+
 char PCA9955::read(char reg)
 {
     //Select the register
-    m_I2C.write(m_Addr, &reg, 1);
+    m_I2C.write(m_ADDR, &reg, 1, true);
 
     //Read the 8-bit register
-    m_I2C.read(m_Addr, &reg, 1);
+    m_I2C.read(m_ADDR, &reg, 1);
 
     //Return the byte
     return reg;
 }
 
-void PCA9955::readMulti(char reg, char* data, int length)
-{
-    //Select the starting register
-    m_I2C.write(m_Addr, &reg, 1);
-
-    //Read the specified number of bytes
-    m_I2C.read(m_Addr, data, length);
-}
-
 void PCA9955::write(char reg, char data)
 {
     //Create a temporary buffer
@@ -625,11 +737,20 @@
     buff[1] = data;
 
     //Write the data
-    m_I2C.write(m_Addr, buff, 2);
+    m_I2C.write(m_ADDR, buff, 2);
+}
+
+void PCA9955::readMulti(char startReg, char* data, int length)
+{
+    //Select the starting register
+    m_I2C.write(m_ADDR, &startReg, 1, true);
+
+    //Read the specified number of bytes
+    m_I2C.read(m_ADDR, data, length);
 }
 
 void PCA9955::writeMulti(char* data, int length)
 {
     //Write the data
-    m_I2C.write(m_Addr, data, length);
+    m_I2C.write(m_ADDR, data, length);
 }