#include "mbed.h" #include "main.h" #include "SWO.h" #include "pca9685.h" #include "tusb322.h" #include "ds3231.h" #include "ioc.h" #include "animation.h" I2C i2c(PA_10, PA_9); // SWO_Channel swo("swo"); bool RtcTick, RefreshTick, RngTick; typedef enum { Idle = 0, Incrementing = 1, Decrementing = 2, } DigitState; typedef struct { DigitState CurrentState; int Value; int Brightness; int Step; bool Updated; } Digit; typedef struct { Digit Digits[10]; bool Refresh; int UpdateRate; } Tube; Tube Tubes[4]; // Active per-tube configuration Digit Dot; Ticker RuntimeUpdateTicker, RngUpdateTicker; int RuntimeTickerIter, RngTickerIter; void RtcTickCallback(void) { RtcTick = true; } void RefreshTickCallback(void) { RefreshTick = true; } void RngTickCallback(void) { RngTick = true; } Timeout DotUpdateTick; void DotUpdateCallback(void) { if (Dot.CurrentState == Incrementing && Dot.Brightness < PCA9685_Max_Brightness) { Dot.Brightness += Dot.Step; } else if (Dot.CurrentState == Decrementing && Dot.Brightness > PCA9685_Min_Brightness) { Dot.Brightness -= Dot.Step; } Dot.Updated = true; if (Dot.Brightness == PCA9685_Max_Brightness || Dot.Brightness == PCA9685_Min_Brightness) { DotUpdateTick.detach(); } else { // DotUpdateTick.attach(DotUpdateCallback, (float)1/DOT_FADE_TICKS); DotUpdateTick.attach_us(DotUpdateCallback, 700); } } void Tube0UpdateCallback(void) { } // void RuntimeTickerUpdate(void) { // for (int i = 0; i < NUM_TUBES; i++) { // if(!Tube[i].RefreshActive) { // for (int j = 0; j < MAX_FADE_DIGITS; j++) { // DIGIT *digit = &Tube[i].Digits[j]; // if (digit->Active) { // if (digit->Increment && digit->Reg < PCA9685_Max_Brightness) { // digit->Reg += FADE_TICK_STEP; // } else if (digit->Reg > PCA9685_Min_Brightness) { // digit->Reg -= FADE_TICK_STEP; // } // Tube[i].Updated = true; // } // } // } // } // DotValue = DotIncrement ? DotValue + FADE_TICK_STEP : DotValue - FADE_TICK_STEP; // DotUpdated = true; // if (--RuntimeTickerIter == 0) { // RuntimeUpdateTicker.detach(); // DotIncrement = !DotIncrement; // } // } void RngTickerUpdate(void) { if (--RngTickerIter == 0) { RngUpdateTicker.detach(); } } int main() { // Initialize pointers in global data structure // for (int i = 0; i < NUM_TUBES; i++) { // Tube[i].NextDigit = &Tube[i].Digits[0]; // } RtcTick = false; RefreshTick = false; RngTick = false; int nextSecond, nextMinute, nextHour; int prevMinute, prevHour; bool startup = true; // Start I2C at 400kHz for DS3231 i2c.frequency(400000); // Start with HV PSU disabled HV_EnableOutput(false); TUSB322_Init(); PCA9685_Init(); DS3231_Init(RtcTickCallback); // Enable HV PSU HV_EnableOutput(true); // Set PCA9685 input voltage to highest possible PCA9685_SetVoltage(1.0); // swo.printf("CPU SystemCoreClock is %d Hz\r\n", SystemCoreClock); // Bump I2C frequency to 1MHz // i2c.frequency(1000000); // Setup a ticker to refresh the display at 1kHz Ticker refreshTicker; refreshTicker.attach_us(RefreshTickCallback, DIGIT_REFRESH_RATE_US); // Kick off the RNG ticker at 0.1Hz // Ticker rngTicker; // rngTicker.attach(RngTickCallback, DIGIT_RNG_REFRESH_RATE_S); // DS3231_SetTime(0, 55, 6, true); // DS3231_SetDate(0, 2, 12, 18, 0); Dot.CurrentState = Decrementing; Dot.Step = DOT_TICK_STEP; Dot.Brightness = 0; while(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(); // On every refresh tick, update the display with new values if (RefreshTick) { RefreshTick = false; // for (int i = 0; i < NUM_TUBES; i++) { // if (Tube[i].Updated) { // Tube[i].Updated = false; // for (int j = 0; j < MAX_FADE_DIGITS; j++) { // DIGIT *digit = &Tube[i].Digits[j]; // if (digit->Active) { // PCA9685_SetDigit(i, digit->Value, digit->Reg); // if (digit->Reg == 0 && !digit->Increment) { // digit->Active = false; // } // } // } // } // } if (Dot.Updated) { PCA9685_SetDot(Dot.Brightness); Dot.Updated = false; } } // On every RTC tick, read and process the current time if (RtcTick) { RtcTick = false; // Save the previous time to check if digit(s) has changed prevMinute = nextMinute; prevHour = nextHour; DS3231_GetTime(&nextSecond, &nextMinute, &nextHour); // Update the display configuration based on the new/previous time // for (int i = 0; i < NUM_TUBES; i++) { // bool Update = false; // if (i == 0 && (startup || prevHour / 10 != nextHour / 10)) { // if (nextHour / 10 != 0) { // Tube[i].NextDigit->Value = nextHour / 10; // Tube[i].NextDigit->Increment = true; // Tube[i].NextDigit->Active = true; // } // Update = true; // ? // } else if (i == 1 && (startup || prevHour % 10 != nextHour % 10)) { // Tube[i].NextDigit->Value = nextHour % 10; // Tube[i].NextDigit->Increment = true; // Tube[i].NextDigit->Active = true; // Update = true; // } else if (i == 2 && (startup || prevMinute / 10 != nextMinute / 10)) { // Tube[i].NextDigit->Value = nextMinute / 10; // Tube[i].NextDigit->Increment = true; // Tube[i].NextDigit->Active = true; // Update = true; // } else if (i == 3 && (startup || prevMinute % 10 != nextMinute % 10)) { // Tube[i].NextDigit->Value = nextMinute % 10; // Tube[i].NextDigit->Increment = true; // Tube[i].NextDigit->Active = true; // Update = true; // } // Handle display configuration changes for the given tube // if (Update) { // if (!startup) { // Tube[i].PrevDigit->Increment = false; // } // Tube[i].PrevDigit = Tube[i].NextDigit; // Tube[i].NextDigit = Tube[i].NextDigit == &Tube[i].Digits[0] ? // &Tube[i].Digits[1] : &Tube[i].Digits[0]; // } // } Dot.CurrentState = (Dot.CurrentState == Decrementing) ? Incrementing : Decrementing; // DotUpdateTick.attach(DotUpdateCallback, (float)1/DOT_FADE_TICKS); DotUpdateTick.attach_us(DotUpdateCallback, 700); // Clear the startup run-once flag after the first iteration // startup = false; // Fade in the new time // RuntimeTickerIter = FADE_TICKS; // RuntimeUpdateTicker.attach(RuntimeTickerUpdate, (float)(DIGIT_REFRESH_RATE_US / 1000) / RuntimeTickerIter); } if (RngTick) { // Choose a random tube to refresh // Tube[rand() % 4].RefreshActive = true; // RngTickerIter = DIGIT_RNG_REFRESH_ITER * FADE_TICKS; // RngUpdateTicker.attach(RngTickerUpdate, (DIGIT_REFRESH_RATE_US/1000)/FADE_TICKS); // RngTick = false; } } } 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); }