Browse Source

Added support for RTC using DS3231

Kevin Lee 5 years ago
parent
commit
7f02060127

+ 3 - 0
Nixie_Firmware_Mbed/animation.cpp

@@ -1,3 +1,6 @@
+#include "mbed.h"
+#include "main.h"
+#include "pca9685.h"
 #include "animation.h"
 
 void Animate_Cycle_Basic(void) {

+ 0 - 4
Nixie_Firmware_Mbed/animation.h

@@ -1,10 +1,6 @@
 #ifndef _ANIMATION_H_
 #define _ANIMATION_H_
 
-#include "mbed.h"
-#include "main.h"
-#include "pca9685.h"
-
 void Animate_Cycle_Basic(void);
 void Animate_Cycle_Analog(void);
 void Animate_Cycle_Low_Pwm(void);

+ 63 - 2
Nixie_Firmware_Mbed/ds3231.cpp

@@ -1,7 +1,68 @@
+#include "mbed.h"
+#include "main.h"
 #include "ds3231.h"
 
-extern I2C i2c;
+InterruptIn IO_Rtc(PB_5);
 
-void DS3231_Init(void) {
+#define BCDToDecimal(x) (((x >> 4) * 10) + (x & 0xF))
+#define DecimalToBCD(x) (((x / 10) << 4) | (x % 10))
 
+void DS3231_Init(void (*Callback)()) {
+    DS3231_REGS regs = {0};
+
+    regs.Control_1.nEOSC = 0;  // Enable internal oscillator on VBAT
+    regs.Control_1.BBSQW = 0;  // Disable outputs on VBAT
+    regs.Control_1.RS1 = 0;    // Set square wave output to 1Hz
+    regs.Control_1.RS2 = 0;    // Set square wave output tp 1Hz
+    regs.Control_1.INTCN = 0;  // Enable square wave output
+    regs.Control_1.A1IE = 0;   // Disable alarm 1
+    regs.Control_1.A2IE = 0;   // Disable alarm 2
+
+    regs.Control_2.EN32KHZ = 0;   // Disable 32kHz output
+
+    I2C_Write(DS3231_ADDR, FIELD_OFFSET(DS3231_REGS, Control_1),
+        regs.AS_BYTE + FIELD_OFFSET(DS3231_REGS, Control_1),
+        FIELD_SIZE_THROUGH(DS3231_REGS, Control_1, Control_2));
+
+    IO_Rtc.rise(Callback);
+}
+
+void DS3231_SetTime(int Second, int Minute, int Hour, bool PM) {
+    DS3231_REGS regs = {0};
+
+    regs.Second.Value = DecimalToBCD(Second);
+    regs.Minute.Value = DecimalToBCD(Minute);
+    regs.Hour.Value = DecimalToBCD(Hour);
+    regs.Hour.nAM = PM;
+    regs.Hour.n24 = 1;
+
+    I2C_Write(DS3231_ADDR, FIELD_OFFSET(DS3231_REGS, Second),
+        regs.AS_BYTE + FIELD_OFFSET(DS3231_REGS, Second),
+        FIELD_SIZE_THROUGH(DS3231_REGS, Second, Hour));
+}
+
+void DS3231_SetDate(int Day, int Date, int Month, int Year, int Century) {
+    DS3231_REGS regs = {0};
+
+    regs.Day.Value = DecimalToBCD(Day);
+    regs.Date.Value = DecimalToBCD(Date);
+    regs.Month.Value = DecimalToBCD(Month);
+    regs.Month.Century = DecimalToBCD(Century);
+    regs.Year.Value = DecimalToBCD(Year);
+
+    I2C_Write(DS3231_ADDR, FIELD_OFFSET(DS3231_REGS, Day),
+        regs.AS_BYTE + FIELD_OFFSET(DS3231_REGS, Day),
+        FIELD_SIZE_THROUGH(DS3231_REGS, Day, Year));
+}
+
+void DS3231_GetTime(int *Second, int *Minute, int *Hour) {
+    DS3231_REGS regs = {0};
+
+    I2C_Read(DS3231_ADDR, FIELD_OFFSET(DS3231_REGS, Second),
+        regs.AS_BYTE + FIELD_OFFSET(DS3231_REGS, Second),
+        FIELD_SIZE_THROUGH(DS3231_REGS, Second, Hour));
+
+    *Second = BCDToDecimal(regs.Second.Value);
+    *Minute = BCDToDecimal(regs.Minute.Value);
+    *Hour = BCDToDecimal(regs.Hour.Value);
 }

+ 68 - 75
Nixie_Firmware_Mbed/ds3231.h

@@ -1,160 +1,149 @@
 #ifndef _DS_3231_H_
 #define _DS_3231_H_
 
-#include "mbed.h"
-#include "main.h"
-
 #define DS3231_ADDR 0x68
 
 typedef union {
     struct {
-        uint8_t Value : 7;
-        uint8_t       : 1;
+        char Value : 7;
+        char       : 1;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } T_SECOND;
 
 typedef union {
     struct {
-        uint8_t Value : 7;
-        uint8_t       : 1;
+        char Value : 7;
+        char       : 1;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } T_MINUTE;
 
 typedef union {
     struct {
-        uint8_t Value : 5;
-        uint8_t nAM   : 1;
-        uint8_t n24   : 1;
-        uint8_t       : 1;
+        char Value : 5;
+        char nAM   : 1;
+        char n24   : 1;
+        char       : 1;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } T_HOUR;
 
 typedef union {
     struct {
-        uint8_t Value : 3;
-        uint8_t       : 5;
+        char Value : 3;
+        char       : 5;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } T_DAY;
 
 typedef union {
     struct {
-        uint8_t Value : 6;
-        uint8_t       : 2;
+        char Value : 6;
+        char       : 2;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } T_DATE;
 
 typedef union {
     struct {
-        uint8_t Value   : 5;
-        uint8_t         : 2;
-        uint8_t Century : 1;
+        char Value   : 5;
+        char         : 2;
+        char Century : 1;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } T_MONTH;
 
 typedef union {
     struct {
-        uint8_t Value : 8;
+        char Value : 8;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } T_YEAR;
 
 typedef union {
     struct {
-        uint8_t Value : 7;
-        uint8_t M1    : 1;
+        char Value : 7;
+        char M1    : 1;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } A_SECOND;
 
 typedef union {
     struct {
-        uint8_t Value : 7;
-        uint8_t M2    : 1;
+        char Value : 7;
+        char M2    : 1;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } A_MINUTE;
 
 typedef union {
     struct {
-        uint8_t Value : 5;
-        uint8_t nAM   : 1;
-        uint8_t n24   : 1;
-        uint8_t M3    : 1;
+        char Value : 5;
+        char nAM   : 1;
+        char n24   : 1;
+        char M3    : 1;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } A_HOUR;
 
 typedef union {
     struct {
-        union {
-            struct {
-                uint8_t Value : 4;
-                uint8_t       : 2;
-            } Day;
-            struct {
-                uint8_t Value : 6;
-            } Date;
-        };
-        uint8_t nDT : 1;
-        uint8_t M4  : 1;
+        char Value : 6;
+        char nDT   : 1;
+        char M4    : 1;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } A_DAY_DATE;
 
 typedef union {
     struct {
-        uint8_t A1IE  : 1;
-        uint8_t A2IE  : 1;
-        uint8_t INTCN : 1;
-        uint8_t RS1   : 1;
-        uint8_t RS2   : 1;
-        uint8_t CONV  : 1;
-        uint8_t BBSQW : 1;
-        uint8_t nEOSC : 1;
+        char A1IE  : 1;
+        char A2IE  : 1;
+        char INTCN : 1;
+        char RS1   : 1;
+        char RS2   : 1;
+        char CONV  : 1;
+        char BBSQW : 1;
+        char nEOSC : 1;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } CONTROL_1;
 
 typedef union {
     struct {
-        uint8_t A1F     : 1;
-        uint8_t A2F     : 1;
-        uint8_t BSY     : 1;
-        uint8_t EN32KHZ : 1;
-        uint8_t         : 3;
-        uint8_t OSF     : 1;
+        char A1F     : 1;
+        char A2F     : 1;
+        char BSY     : 1;
+        char EN32KHZ : 1;
+        char         : 3;
+        char OSF     : 1;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } CONTROL_2;
 
 typedef union {
     struct {
-        uint8_t Value : 7;
-        uint8_t Sign  : 1;
+        char Value : 7;
+        char Sign  : 1;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } AGING_OFFSET;
 
 typedef union {
     struct {
-        uint8_t Value : 7;
-        uint8_t Sign  : 1;
+        char Value : 7;
+        char Sign  : 1;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } TEMP_MSB;
 
 typedef union {
     struct {
-        uint8_t       : 6;
-        uint8_t Value : 2;
+        char       : 6;
+        char Value : 2;
     };
-    uint8_t AS_DATA;
+    char AS_BYTE;
 } TEMP_LSB;
 
 typedef union {
@@ -179,8 +168,12 @@ typedef union {
         TEMP_MSB Temp_MSB;          // 0x11
         TEMP_LSB Temp_LSB;          // 0x12
     };
+    char AS_BYTE[0x13];
 } DS3231_REGS;
 
-void DS3231_Init(void);
+void DS3231_Init(void (*Callback)());
+void DS3231_SetTime(int Second, int Minute, int Hour, bool PM);
+void DS3231_SetDate(int Day, int Date, int Month, int Year, int Century);
+void DS3231_GetTime(int *Second, int *Minute, int *Hour);
 
 #endif

+ 7 - 0
Nixie_Firmware_Mbed/ioc.cpp

@@ -1,3 +1,5 @@
+#include "mbed.h"
+#include "main.h"
 #include "ioc.h"
 
 InterruptIn IO_nFault(PA_3);
@@ -22,3 +24,8 @@ void HV_EnableOutput(bool Enable) {
 void LED_SetOutput(bool Value) {
     IO_LED.write(Value);
 }
+
+void LED_Fault(char Pattern) {
+    LED_SetOutput(true);
+    while(1);
+}

+ 2 - 3
Nixie_Firmware_Mbed/ioc.h

@@ -1,10 +1,9 @@
 #ifndef _IOC_H_
 #define _IOC_H_
 
-#include "mbed.h"
-#include "main.h"
-
 void IO_Init(void);
 void HV_EnableOutput(bool Enable);
+void LED_SetOutput(bool Value);
+void LED_Fault(char Pattern);
 
 #endif

+ 64 - 12
Nixie_Firmware_Mbed/main.cpp

@@ -10,6 +10,14 @@
 I2C i2c(PA_10, PA_9);
 // SWO_Channel swo("swo");
 
+bool LED;
+
+void RtcCallback(void) {
+    LED = !LED;
+
+    LED_SetOutput(LED);
+}
+
 int main() {
     
     // Start I2C at 400kHz for DS3231 
@@ -20,6 +28,7 @@ int main() {
     
     TUSB322_Init();
     PCA9685_Init();
+    DS3231_Init(RtcCallback);
     
     // Enable HV PSU
     HV_EnableOutput(true);
@@ -30,23 +39,66 @@ int main() {
     // swo.printf("CPU SystemCoreClock is %d Hz\r\n", SystemCoreClock);
     
     // Bump I2C frequency to 1MHz for PCA9685
-    i2c.frequency(1000000);
+    // i2c.frequency(1000000);
+
+    // DS3231_SetTime(0, 55, 6, true);
+    // DS3231_SetDate(0, 2, 12, 18, 0);
 
-    // PCA9685_SetDot(100);  
-    // PCA9685_SetDigit(3, 1, 100);
-    // PCA9685_SetDigit(2, 3, 100);
-    // PCA9685_SetDigit(1, 5, 100);
-    // PCA9685_SetDigit(0, 7, 100);
+    int currMinute = 0, currHour = 0;
+    int nextSecond, nextMinute, nextHour;
 
     while(1) {
             
-        Animate_Cycle_Basic();
+        DS3231_GetTime(&nextSecond, &nextMinute, &nextHour);
+
+        if (nextMinute != currMinute) {
+
+            PCA9685_SetDigit(3, currMinute % 10, PCA9685_Min_Brightness);
+            PCA9685_SetDigit(2, currMinute / 10, PCA9685_Min_Brightness);
+
+            PCA9685_SetDigit(3, nextMinute % 10, PCA9685_Max_Brightness);
+            PCA9685_SetDigit(2, nextMinute / 10, PCA9685_Max_Brightness);
+
+            currMinute = nextMinute;
+        }
+
+        if (nextHour != currHour) {
+
+            PCA9685_SetDigit(1, currHour % 10, PCA9685_Min_Brightness);
+            PCA9685_SetDigit(0, currHour / 10, PCA9685_Min_Brightness);
+
+            PCA9685_SetDigit(1, nextHour % 10, PCA9685_Max_Brightness);
+            PCA9685_SetDigit(0, nextHour / 10, PCA9685_Max_Brightness);
+
+            currHour = nextHour;
+        }
+
+        wait(0.1);
+
+        // Animate_Cycle_Basic();
         // Animate_Cycle_Analog();
         // Animate_Cycle_Low_Pwm();
-        Animate_Cycle_Pwm();
-        Animate_Cycle_Fade();
-        Animate_Cycle_Fade_Random();
-        Animate_Cycle_Fast();
-        Animate_Cycle_Fast_Random();
+        // Animate_Cycle_Pwm();
+        // Animate_Cycle_Fade();
+        // Animate_Cycle_Fade_Random();
+        // Animate_Cycle_Fast();
+        // Animate_Cycle_Fast_Random();
     }
 }
+
+void I2C_Write(int DeviceAddress, char RegAddress, char *Data, int Length) {
+    char buffer[I2C_MAX_BUFFER+1] = {0};
+
+    if (Length > I2C_MAX_BUFFER) LED_Fault(1);
+
+    buffer[0] = RegAddress;
+    memcpy(&buffer[1], Data, Length);
+
+    i2c.write(DeviceAddress << 1, buffer, Length + 1);
+}
+
+void I2C_Read(int DeviceAddress, char RegAddress, char *Data, int Length) {
+    
+    i2c.write(DeviceAddress << 1, &RegAddress, 1);
+    i2c.read(DeviceAddress << 1, Data, Length);
+}

+ 14 - 0
Nixie_Firmware_Mbed/main.h

@@ -4,4 +4,18 @@
 // Calculate the byte offset of a field in a structure of type type.
 #define FIELD_OFFSET(type, field) ((uint32_t)(uint32_t*)&(((type *)0)->field))
 
+// Calculate the size of a field in a structure of type type 
+#define FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
+
+// Calculate the size from field1 to field2 (inclusive)
+#define FIELD_SIZE_THROUGH(type, field1, field2) \
+    (FIELD_OFFSET(type, field2) + FIELD_SIZE(type, field2) - FIELD_OFFSET(type, field1))
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+#define I2C_MAX_BUFFER 20
+
+void I2C_Write(int DeviceAddress, char RegAddress, char *Data, int Length);
+void I2C_Read(int DeviceAddress, char RegAddress, char *Data, int Length);
+
 #endif

+ 32 - 36
Nixie_Firmware_Mbed/pca9685.cpp

@@ -1,34 +1,34 @@
+#include "mbed.h"
+#include "main.h"
 #include "pca9685.h"
 
-extern I2C i2c;
 DigitalOut PCA9685_PWM_nEN(PA_7);
 DigitalOut PCA9685_VIN_EN(PB_1);
 AnalogOut  PCA9685_VIN(PA_5);
 
 void PCA9685_Init(void) {
+    PCA9685_REGS regs = {0};
+    
     // Power up PCA9685 at full voltage with outputs disabled
     PCA9685_VIN.write(1);
     PCA9685_VIN_EN.write(1);
     PCA9685_PWM_nEN.write(1);
 
-    char buffer[sizeof(REG_MODE1)+sizeof(REG_MODE2)+1] = {0};
-    buffer[0] = FIELD_OFFSET(PCM9685_REGS, MODE1);
-    
-    REG_MODE1 *reg1 = (REG_MODE1*)&buffer[1];
-    reg1->AI = 1;         // Turn on autoincrement
-    reg1->SLEEP = 1;      // Start disabled
-    reg1->ALLCALL = 1;    // Enable response to all call address
+    regs.MODE1.AI = 1;         // Turn on autoincrement
+    regs.MODE1.SLEEP = 1;      // Start disabled
+    regs.MODE1.ALLCALL = 1;    // Enable response to all call address
     
-    REG_MODE2 *reg2 = (REG_MODE2*)&buffer[1+sizeof(REG_MODE1)];
-    reg2->OUTDRV = 1;     // Configure output for totem pole drive
+    regs.MODE2.OUTDRV = 1;     // Configure output for totem pole drive
     
-    i2c.write(PCM9685_All_Call << 1, buffer, sizeof(buffer));
+    I2C_Write(PCA9685_All_Call, FIELD_OFFSET(PCA9685_REGS, MODE1), 
+        regs.AS_BYTE + FIELD_OFFSET(PCA9685_REGS, MODE1),
+        FIELD_SIZE_THROUGH(PCA9685_REGS, MODE1, MODE2));
     
-    char pre_scale[2] = {0};
-    pre_scale[0] = FIELD_OFFSET(PCM9685_REGS, PRE_SCALE);
-    pre_scale[1] = 0x03;  // Set PWM frequency to 1526 Hz
-    
-    i2c.write(PCM9685_All_Call << 1, pre_scale, sizeof(pre_scale));
+    regs.PRE_SCALE = 0x03;      // Set PWM frequency to 1526Hz
+
+    I2C_Write(PCA9685_All_Call, FIELD_OFFSET(PCA9685_REGS, PRE_SCALE), 
+        regs.AS_BYTE + FIELD_OFFSET(PCA9685_REGS, PRE_SCALE),
+        FIELD_SIZE_THROUGH(PCA9685_REGS, PRE_SCALE, PRE_SCALE));
     
     PCA9685_SetDot(0);
     for (int i = 0; i < 4; i++) {
@@ -37,9 +37,11 @@ void PCA9685_Init(void) {
         }
     }
     
-    reg1->SLEEP = 0;
+    regs.MODE1.SLEEP = 0;       // Re-enable outputs
     
-    i2c.write(PCM9685_All_Call << 1, buffer, sizeof(buffer));
+    I2C_Write(PCA9685_All_Call, FIELD_OFFSET(PCA9685_REGS, MODE1), 
+        regs.AS_BYTE + FIELD_OFFSET(PCA9685_REGS, MODE1),
+        FIELD_SIZE_THROUGH(PCA9685_REGS, MODE1, MODE1));
 
     // Enable outputs after configuration has been completed
     PCA9685_PWM_nEN.write(0);
@@ -51,39 +53,33 @@ void PCA9685_SetVoltage(float Percent) {
 }
 
 void PCA9685_SetDigit(int Tube, int Digit, int Brightness) {
-    char buffer[sizeof(LED_CTRL)+1] = {0};
+    LED_CTRL reg = {0};
 
-    buffer[0] = FIELD_OFFSET(PCM9685_REGS, LED0) + 
-        (Tube_Mapping[Tube][Digit][MAP_PIN] * sizeof(LED_CTRL));
-
-    LED_CTRL *reg = (LED_CTRL*)&buffer[1];
     if (Brightness >= PCA9685_Max_Brightness) {
-        reg->ON_FULL = 1;
+        reg.ON_FULL = 1;
     } else if (Brightness == 0) {
-        reg->OFF_FULL = 1;
+        reg.OFF_FULL = 1;
     } else {
-        reg->OFF = Brightness;
+        reg.OFF = Brightness;
     }
 
-    i2c.write(Tube_Mapping[Tube][Digit][MAP_ADDR] << 1, buffer, sizeof(buffer));
+    I2C_Write(Tube_Mapping[Tube][Digit][MAP_ADDR],
+        FIELD_OFFSET(PCA9685_REGS, LED0) + (Tube_Mapping[Tube][Digit][MAP_PIN] * sizeof(LED_CTRL)),
+        reg.AS_BYTE, sizeof(LED_CTRL));
 }
 
 void PCA9685_SetDot(int Brightness) {
-    char buffer[sizeof(LED_CTRL)+1] = {0};
-    
-    buffer[0] = FIELD_OFFSET(PCM9685_REGS, TUBE_DOT_PIN);
+    LED_CTRL reg = {0};
     
-    LED_CTRL *reg = (LED_CTRL*)&buffer[1];
-
     if (Brightness >= PCA9685_Max_Brightness) {
-        reg->ON_FULL = 1;
+        reg.ON_FULL = 1;
     } else if (Brightness == 0) {
-        reg->OFF_FULL = 1;
+        reg.OFF_FULL = 1;
     } else {
-        reg->OFF = Brightness;
+        reg.OFF = Brightness;
     }
 
-    i2c.write(TUBE_DOT_ADDR << 1, buffer, sizeof(buffer));
+    I2C_Write(TUBE_DOT_ADDR, FIELD_OFFSET(PCA9685_REGS, TUBE_DOT_PIN), reg.AS_BYTE, sizeof(LED_CTRL));
 }
 
 void PCA9685_EnableOutput(bool Enabled) {

+ 120 - 112
Nixie_Firmware_Mbed/pca9685.h

@@ -1,151 +1,159 @@
 #ifndef _PCA_9685_H_
 #define _PCA_9685_H_
 
-#include "mbed.h"
-#include "main.h"
-
-#define PCM9685_ADDR_1     0x41
-#define PCM9685_ADDR_2     0x42
-#define PCM9685_ADDR_3     0x43
+#define PCA9685_ADDR_1     0x41
+#define PCA9685_ADDR_2     0x42
+#define PCA9685_ADDR_3     0x43
 
 // Hardcoded addresses available on powerup
-#define PCM9685_All_Call   0x70     // Default enabled
-#define PCM9685_Sub_Call_1 0x71     // Default disabled
-#define PCM9685_Sub_Call_2 0x72     // Default disabled
-#define PCM9685_Sub_Call_3 0x73     // Default disabled
-#define PCM9685_Reset      0x03     // Default enabled?
+#define PCA9685_All_Call   0x70     // Default enabled
+#define PCA9685_Sub_Call_1 0x71     // Default disabled
+#define PCA9685_Sub_Call_2 0x72     // Default disabled
+#define PCA9685_Sub_Call_3 0x73     // Default disabled
+#define PCA9685_Reset      0x03     // Default enabled?
 
 #define PCA9685_Max_Brightness 4096
 #define PCA9685_Min_Brightness 0
 
 typedef union {
     struct {
-        uint8_t ALLCALL : 1;
-        uint8_t SUB3    : 1;
-        uint8_t SUB2    : 1;
-        uint8_t SUB1    : 1;
-        uint8_t SLEEP   : 1;
-        uint8_t AI      : 1;
-        uint8_t EXTCLK  : 1;
-        uint8_t RESTART : 1;
+        char ALLCALL : 1;
+        char SUB3    : 1;
+        char SUB2    : 1;
+        char SUB1    : 1;
+        char SLEEP   : 1;
+        char AI      : 1;
+        char EXTCLK  : 1;
+        char RESTART : 1;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } REG_MODE1;
 
 typedef union {
     struct {
-        uint8_t OUTNE  : 2;
-        uint8_t OUTDRV : 1;
-        uint8_t OCH    : 1;
-        uint8_t INVRT  : 1;
-        uint8_t        : 3;
+        char OUTNE  : 2;
+        char OUTDRV : 1;
+        char OCH    : 1;
+        char INVRT  : 1;
+        char        : 3;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } REG_MODE2;
 
 typedef union {
     struct {
-        uint16_t ON       : 12;
-        uint16_t ON_FULL  : 1;
-        uint16_t          : 3;
-        uint16_t OFF      : 12;
-        uint16_t OFF_FULL : 1;
-        uint16_t          : 3;
+        ushort ON       : 12;
+        ushort ON_FULL  : 1;
+        ushort          : 3;
+        ushort OFF      : 12;
+        ushort OFF_FULL : 1;
+        ushort          : 3;
     };
-    uint8_t AS_BYTE[4];
+    char AS_BYTE[4];
 } LED_CTRL;
 
 typedef union {
     struct {
-        uint16_t ON       : 12;
-        uint16_t ON_FULL  : 1;
-        uint16_t          : 3;
-        uint16_t OFF      : 12;
-        uint16_t OFF_FULL : 1;
-        uint16_t          : 3;
+        ushort ON       : 12;
+        ushort ON_FULL  : 1;
+        ushort          : 3;
+        ushort OFF      : 12;
+        ushort OFF_FULL : 1;
+        ushort          : 3;
     };
-    uint8_t AS_BYTE[4];
+    char AS_BYTE[4];
 } ALL_LED_CTRL;
  
-typedef struct {
-    REG_MODE1       MODE1;          // +0x00
-    REG_MODE2       MODE2;          // +0x01
-    uint8_t         SUBADR1;        // +0x02
-    uint8_t         SUBADR2;        // +0x03
-    uint8_t         SUBADR3;        // +0x04
-    uint8_t         ALLCALLADR;     // +0x05
-    LED_CTRL        LED0;           // +0x06
-    LED_CTRL        LED1;           // +0x0A
-    LED_CTRL        LED2;           // +0x0E
-    LED_CTRL        LED3;           // +0x12
-    LED_CTRL        LED4;           // +0x16
-    LED_CTRL        LED5;           // +0x1A
-    LED_CTRL        LED6;           // +0x1E
-    LED_CTRL        LED7;           // +0x22
-    LED_CTRL        LED8;           // +0x26
-    LED_CTRL        LED9;           // +0x2A
-    LED_CTRL        LED10;          // +0x2E
-    LED_CTRL        LED11;          // +0x32
-    LED_CTRL        LED12;          // +0x36
-    LED_CTRL        LED13;          // +0x3A
-    LED_CTRL        LED14;          // +0x3E
-    LED_CTRL        LED15;          // +0x42
-    uint8_t         RESERVED[180];  // +0x46
-    ALL_LED_CTRL    ALL_LED;        // +0xFA
-    uint8_t         PRE_SCALE;      // +0xFE
-    uint8_t         TestMode;       // +0xFF
-} PCM9685_REGS;
+typedef union {
+    struct {
+        REG_MODE1       MODE1;          // +0x00
+        REG_MODE2       MODE2;          // +0x01
+        char            SUBADR1;        // +0x02
+        char            SUBADR2;        // +0x03
+        char            SUBADR3;        // +0x04
+        char            ALLCALLADR;     // +0x05
+        LED_CTRL        LED0;           // +0x06
+        LED_CTRL        LED1;           // +0x0A
+        LED_CTRL        LED2;           // +0x0E
+        LED_CTRL        LED3;           // +0x12
+        LED_CTRL        LED4;           // +0x16
+        LED_CTRL        LED5;           // +0x1A
+        LED_CTRL        LED6;           // +0x1E
+        LED_CTRL        LED7;           // +0x22
+        LED_CTRL        LED8;           // +0x26
+        LED_CTRL        LED9;           // +0x2A
+        LED_CTRL        LED10;          // +0x2E
+        LED_CTRL        LED11;          // +0x32
+        LED_CTRL        LED12;          // +0x36
+        LED_CTRL        LED13;          // +0x3A
+        LED_CTRL        LED14;          // +0x3E
+        LED_CTRL        LED15;          // +0x42
+        char            RESERVED[180];  // +0x46
+        ALL_LED_CTRL    ALL_LED;        // +0xFA
+        char            PRE_SCALE;      // +0xFE
+        char            TestMode;       // +0xFF
+    };
+    char AS_BYTE[0x100];
+} PCA9685_REGS;
 
-#define TUBE_DOT_ADDR PCM9685_ADDR_2
+#define TUBE_DOT_ADDR PCA9685_ADDR_2
 #define TUBE_DOT_PIN LED15
 
 #define MAP_ADDR 0
 #define MAP_PIN  1
 
 const char Tube_Mapping[4][10][2] = 
-    { { { PCM9685_ADDR_1, 9  },     // Tube 0 Digit 0
-        { PCM9685_ADDR_1, 10 },     // Tube 0 Digit 1
-        { PCM9685_ADDR_1, 12 },     // Tube 0 Digit 2
-        { PCM9685_ADDR_1, 15 },     // Tube 0 Digit 3
-        { PCM9685_ADDR_1, 14 },     // Tube 0 Digit 4
-        { PCM9685_ADDR_1, 11 },     // Tube 0 Digit 5
-        { PCM9685_ADDR_1, 0  },     // Tube 0 Digit 6
-        { PCM9685_ADDR_1, 1  },     // Tube 0 Digit 7
-        { PCM9685_ADDR_1, 13 },     // Tube 0 Digit 8
-        { PCM9685_ADDR_1, 8  } },   // Tube 0 Digit 9
-
-      { { PCM9685_ADDR_1, 6  },     // Tube 1 Digit 0
-        { PCM9685_ADDR_1, 7  },     // Tube 1 Digit 1
-        { PCM9685_ADDR_1, 2  },     // Tube 1 Digit 2
-        { PCM9685_ADDR_2, 4  },     // Tube 1 Digit 3
-        { PCM9685_ADDR_2, 1  },     // Tube 1 Digit 4
-        { PCM9685_ADDR_1, 4  },     // Tube 1 Digit 5
-        { PCM9685_ADDR_2, 2  },     // Tube 1 Digit 6
-        { PCM9685_ADDR_2, 3  },     // Tube 1 Digit 7
-        { PCM9685_ADDR_1, 3  },     // Tube 1 Digit 8
-        { PCM9685_ADDR_1, 5  } },   // Tube 1 Digit 9
-
-      { { PCM9685_ADDR_3, 9  },     // Tube 2 Digit 0
-        { PCM9685_ADDR_3, 10 },     // Tube 2 Digit 1
-        { PCM9685_ADDR_3, 12 },     // Tube 2 Digit 2
-        { PCM9685_ADDR_2, 12 },     // Tube 2 Digit 3
-        { PCM9685_ADDR_2, 13 },     // Tube 2 Digit 4
-        { PCM9685_ADDR_3, 11 },     // Tube 2 Digit 5
-        { PCM9685_ADDR_2, 14 },     // Tube 2 Digit 6
-        { PCM9685_ADDR_2, 11 },     // Tube 2 Digit 7
-        { PCM9685_ADDR_3, 13 },     // Tube 2 Digit 8
-        { PCM9685_ADDR_3, 8  } },   // Tube 2 Digit 9
-
-      { { PCM9685_ADDR_3, 6  },     // Tube 3 Digit 0
-        { PCM9685_ADDR_3, 7  },     // Tube 3 Digit 1
-        { PCM9685_ADDR_3, 2  },     // Tube 3 Digit 2
-        { PCM9685_ADDR_3, 14 },     // Tube 3 Digit 3
-        { PCM9685_ADDR_3, 15 },     // Tube 3 Digit 4
-        { PCM9685_ADDR_3, 4  },     // Tube 3 Digit 5
-        { PCM9685_ADDR_3, 1  },     // Tube 3 Digit 6
-        { PCM9685_ADDR_3, 0  },     // Tube 3 Digit 7
-        { PCM9685_ADDR_3, 3  },     // Tube 3 Digit 8
-        { PCM9685_ADDR_3, 5  } } }; // Tube 3 Digit 9
+    { { 
+        { PCA9685_ADDR_1, 8  },     // Tube 0 Digit 0
+        { PCA9685_ADDR_1, 9  },     // Tube 0 Digit 1
+        { PCA9685_ADDR_1, 10 },     // Tube 0 Digit 2
+        { PCA9685_ADDR_1, 12 },     // Tube 0 Digit 3
+        { PCA9685_ADDR_1, 15 },     // Tube 0 Digit 4
+        { PCA9685_ADDR_1, 14 },     // Tube 0 Digit 5
+        { PCA9685_ADDR_1, 11 },     // Tube 0 Digit 6
+        { PCA9685_ADDR_1, 0  },     // Tube 0 Digit 7
+        { PCA9685_ADDR_1, 1  },     // Tube 0 Digit 8
+        { PCA9685_ADDR_1, 13 },     // Tube 0 Digit 9
+      },   
+
+      { 
+        { PCA9685_ADDR_1, 5  },     // Tube 1 Digit 0
+        { PCA9685_ADDR_1, 6  },     // Tube 1 Digit 1
+        { PCA9685_ADDR_1, 7  },     // Tube 1 Digit 2
+        { PCA9685_ADDR_1, 2  },     // Tube 1 Digit 3
+        { PCA9685_ADDR_2, 4  },     // Tube 1 Digit 4
+        { PCA9685_ADDR_2, 1  },     // Tube 1 Digit 5
+        { PCA9685_ADDR_1, 4  },     // Tube 1 Digit 6
+        { PCA9685_ADDR_2, 2  },     // Tube 1 Digit 7
+        { PCA9685_ADDR_2, 3  },     // Tube 1 Digit 8
+        { PCA9685_ADDR_1, 3  },     // Tube 1 Digit 9
+      },   
+
+      { 
+        { PCA9685_ADDR_3, 8  },     // Tube 2 Digit 0
+        { PCA9685_ADDR_3, 9  },     // Tube 2 Digit 1
+        { PCA9685_ADDR_3, 10 },     // Tube 2 Digit 2
+        { PCA9685_ADDR_3, 12 },     // Tube 2 Digit 3
+        { PCA9685_ADDR_2, 12 },     // Tube 2 Digit 4
+        { PCA9685_ADDR_2, 13 },     // Tube 2 Digit 5
+        { PCA9685_ADDR_3, 11 },     // Tube 2 Digit 6
+        { PCA9685_ADDR_2, 14 },     // Tube 2 Digit 7
+        { PCA9685_ADDR_2, 11 },     // Tube 2 Digit 8
+        { PCA9685_ADDR_3, 13 },     // Tube 2 Digit 9
+      },
+
+      { 
+        { PCA9685_ADDR_3, 5  },     // Tube 3 Digit 0
+        { PCA9685_ADDR_3, 6  },     // Tube 3 Digit 1
+        { PCA9685_ADDR_3, 7  },     // Tube 3 Digit 2
+        { PCA9685_ADDR_3, 2  },     // Tube 3 Digit 3
+        { PCA9685_ADDR_3, 14 },     // Tube 3 Digit 4
+        { PCA9685_ADDR_3, 15 },     // Tube 3 Digit 5
+        { PCA9685_ADDR_3, 4  },     // Tube 3 Digit 6
+        { PCA9685_ADDR_3, 1  },     // Tube 3 Digit 7
+        { PCA9685_ADDR_3, 0  },     // Tube 3 Digit 8
+        { PCA9685_ADDR_3, 3  },     // Tube 3 Digit 9
+      } };
 
 void PCA9685_Init(void);
 void PCA9685_SetVoltage(float Percent);

+ 16 - 15
Nixie_Firmware_Mbed/tusb322.cpp

@@ -1,6 +1,7 @@
+#include "mbed.h"
+#include "main.h"
 #include "tusb322.h"
 
-extern I2C i2c;
 InterruptIn IO_Usb(PB_4);
 
 void UsbInterrupt(void) {
@@ -8,27 +9,27 @@ void UsbInterrupt(void) {
 }
 
 void TUSB322_Init(void) {
-    char buffer[sizeof(TUSB322_REGS)] = {0};
+    TUSB322_REGS regs = {0};
     
-    IO_Usb.fall(&UsbInterrupt);
+    IO_Usb.fall(UsbInterrupt);
 
     // Disable UFP accessory support (otherwise IC stays in DRP mode)
-    buffer[0] = FIELD_OFFSET(TUSB322_REGS, Status2);
-    CONN_STATUS2 *stat = (CONN_STATUS2*)&buffer[1];
-    stat->UFP_ACCESSORY = 0x1;
-    i2c.write(TUSB322_ADDR << 1, buffer, 2);
+    regs.Status2.UFP_ACCESSORY = 0x1;
 
     // Disable CC termination to change to UFP mode
-    buffer[0] = FIELD_OFFSET(TUSB322_REGS, Control);
-    CTRL *ctrl = (CTRL*)&buffer[1];
-    ctrl->DISABLE_TERM = 0x1;
-    i2c.write(TUSB322_ADDR << 1, buffer, 2);
+    regs.Control.DISABLE_TERM = 0x1;
 
     // For operation in UFP mode
-    ctrl->MODE_SELECT = 0x01;
-    i2c.write(TUSB322_ADDR << 1, buffer, 2);
+    regs.Control.MODE_SELECT = 0x01;
+
+    I2C_Write(TUSB322_ADDR, FIELD_OFFSET(TUSB322_REGS, Status2), 
+        regs.AS_BYTE + FIELD_OFFSET(TUSB322_REGS, Status2),
+        FIELD_SIZE_THROUGH(TUSB322_REGS, Status2, Control));
 
     // Reenable CC termination
-    ctrl->DISABLE_TERM = 0x0;
-    i2c.write(TUSB322_ADDR << 1, buffer, 2);
+    regs.Control.DISABLE_TERM = 0x0;
+
+    I2C_Write(TUSB322_ADDR, FIELD_OFFSET(TUSB322_REGS, Control), 
+        regs.AS_BYTE + FIELD_OFFSET(TUSB322_REGS, Control),
+        FIELD_SIZE_THROUGH(TUSB322_REGS, Control, Control));
 }

+ 20 - 23
Nixie_Firmware_Mbed/tusb322.h

@@ -1,52 +1,49 @@
 #ifndef _TUSB_322_H_
 #define _TUSB_322_H_
 
-#include "mbed.h"
-#include "main.h"
-
 #define TUSB322_ADDR 0x47 
 
 typedef union {
     struct {
-        uint8_t ACTIVE_CABLE      : 1;
-        uint8_t ACCESSORY         : 3;
-        uint8_t CURRENT_DETECT    : 2;
-        uint8_t CURRENT_ADVERTISE : 2;
+        char ACTIVE_CABLE      : 1;
+        char ACCESSORY         : 3;
+        char CURRENT_DETECT    : 2;
+        char CURRENT_ADVERTISE : 2;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } CONN_STATUS1;
 
 typedef union {
     struct {
-        uint8_t UFP_ACCESSORY  : 1;
-        uint8_t DRP_DUTY_CYCLE : 2;
-        uint8_t VCONN_FAULT    : 1;
-        uint8_t INTERRUPT      : 1;
-        uint8_t CABLE_DIR      : 1;
-        uint8_t ATTACHED_STATE : 2;
+        char UFP_ACCESSORY  : 1;
+        char DRP_DUTY_CYCLE : 2;
+        char VCONN_FAULT    : 1;
+        char INTERRUPT      : 1;
+        char CABLE_DIR      : 1;
+        char ATTACHED_STATE : 2;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } CONN_STATUS2;
 
 typedef union {
     struct {
-        uint8_t DISABLE_TERM : 1;
-        uint8_t SOURCE_PERF  : 2;
-        uint8_t RESET        : 1;
-        uint8_t MODE_SELECT  : 2;
-        uint8_t DEBOUNCE     : 2;
+        char DISABLE_TERM : 1;
+        char SOURCE_PERF  : 2;
+        char RESET        : 1;
+        char MODE_SELECT  : 2;
+        char DEBOUNCE     : 2;
     };
-    uint8_t AS_BYTE;
+    char AS_BYTE;
 } CTRL;
 
 typedef union {
     struct {
-        uint8_t      ID[8];          // +0x00
+        char      ID[8];          // +0x00
         CONN_STATUS1 Status1;        // +0x08
         CONN_STATUS2 Status2;        // +0x09
         CTRL         Control;        // +0x0A
     };
-    uint8_t AS_BYTE[11];
+    char AS_BYTE[0xB];
 } TUSB322_REGS;
 
 void TUSB322_Init(void);