|  | @@ -10,10 +10,89 @@
 | 
	
		
			
				|  |  |  I2C i2c(PA_10, PA_9);
 | 
	
		
			
				|  |  |  // SWO_Channel swo("swo");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -bool Tick = false;
 | 
	
		
			
				|  |  | +bool RtcTick = false;
 | 
	
		
			
				|  |  | +bool RefreshTick = false;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void RtcCallback(void) {
 | 
	
		
			
				|  |  | -    Tick = true;
 | 
	
		
			
				|  |  | +    RtcTick = true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void RefreshCallback(void) {
 | 
	
		
			
				|  |  | +    RefreshTick = true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +typedef union {
 | 
	
		
			
				|  |  | +    struct {
 | 
	
		
			
				|  |  | +        char Hour10;
 | 
	
		
			
				|  |  | +        char Hour1;
 | 
	
		
			
				|  |  | +        char Minute10;
 | 
	
		
			
				|  |  | +        char Minute1;
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +} DigitValue;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +DigitValue DigitPrev, DigitNext;
 | 
	
		
			
				|  |  | +int DigitNextValue[4][10] = {0};
 | 
	
		
			
				|  |  | +int DigitPrevValue[4][10] = {0};
 | 
	
		
			
				|  |  | +int DotNextValue, DotPrevValue;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bool StartupFlag = true;
 | 
	
		
			
				|  |  | +bool RuntimeFlag = false;
 | 
	
		
			
				|  |  | +bool DotIncrement = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Ticker StartupTicker;
 | 
	
		
			
				|  |  | +int StartupTickerIter = 1024;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void StartupTickerCallback(void) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    DigitNextValue[3][DigitNext.Minute1] += 4;
 | 
	
		
			
				|  |  | +    DigitNextValue[2][DigitNext.Minute10] += 4;
 | 
	
		
			
				|  |  | +    DigitNextValue[1][DigitNext.Hour1] += 4;
 | 
	
		
			
				|  |  | +    if (DigitNext.Hour10 != 0) {
 | 
	
		
			
				|  |  | +        DigitNextValue[0][DigitNext.Hour10] += 4;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    DotNextValue += 4;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (--StartupTickerIter == 0) {
 | 
	
		
			
				|  |  | +        StartupTicker.detach();
 | 
	
		
			
				|  |  | +        memcpy(&DigitPrev, &DigitNext, sizeof(DigitValue));
 | 
	
		
			
				|  |  | +        RuntimeFlag = true;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Ticker RuntimeTicker;
 | 
	
		
			
				|  |  | +int RuntimeTickerIter = 1024;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void RuntimeTickerCallback(void) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (DigitPrev.Minute1 != DigitNext.Minute1) {
 | 
	
		
			
				|  |  | +        DigitNextValue[3][DigitPrev.Minute1] -= 4;
 | 
	
		
			
				|  |  | +        DigitNextValue[3][DigitNext.Minute1] += 4;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (DigitPrev.Minute10 != DigitNext.Minute10) {
 | 
	
		
			
				|  |  | +        DigitNextValue[2][DigitPrev.Minute10] -= 4;
 | 
	
		
			
				|  |  | +        DigitNextValue[2][DigitNext.Minute10] += 4;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (DigitPrev.Hour1 != DigitNext.Hour1) {
 | 
	
		
			
				|  |  | +        DigitNextValue[1][DigitPrev.Hour1] -= 4;
 | 
	
		
			
				|  |  | +        DigitNextValue[1][DigitNext.Hour1] += 4;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (DigitPrev.Hour10 != DigitNext.Hour10) {
 | 
	
		
			
				|  |  | +        DigitNextValue[0][DigitPrev.Hour10] -= 4;
 | 
	
		
			
				|  |  | +        if (DigitNext.Hour10 != 0) {
 | 
	
		
			
				|  |  | +            DigitNextValue[0][DigitNext.Hour10] += 4;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    DotNextValue = DotIncrement ? DotNextValue + 4 : DotNextValue - 4;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (--RuntimeTickerIter == 0) {
 | 
	
		
			
				|  |  | +        RuntimeTicker.detach();
 | 
	
		
			
				|  |  | +        memcpy(&DigitPrev, &DigitNext, sizeof(DigitValue));
 | 
	
		
			
				|  |  | +        DotIncrement = !DotIncrement;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  int main() {
 | 
	
	
		
			
				|  | @@ -39,13 +118,13 @@ int main() {
 | 
	
		
			
				|  |  |      // Bump I2C frequency to 1MHz
 | 
	
		
			
				|  |  |      i2c.frequency(1000000);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    // Setup a ticker to refresh the display at 1kHz
 | 
	
		
			
				|  |  | +    Ticker refreshTicker;
 | 
	
		
			
				|  |  | +    refreshTicker.attach_us(RefreshCallback, 1000);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      // DS3231_SetTime(0, 55, 6, true);
 | 
	
		
			
				|  |  |      // DS3231_SetDate(0, 2, 12, 18, 0);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    int currMinute = 0, currHour = 0;
 | 
	
		
			
				|  |  | -    int nextSecond, nextMinute, nextHour;
 | 
	
		
			
				|  |  | -    int rngTick = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      while(1) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          // Animate_Cycle_Basic();
 | 
	
	
		
			
				|  | @@ -57,58 +136,55 @@ int main() {
 | 
	
		
			
				|  |  |          // Animate_Cycle_Fast();
 | 
	
		
			
				|  |  |          // Animate_Cycle_Fast_Random();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        rngTick = rand() % 60;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if (Tick) {
 | 
	
		
			
				|  |  | -            
 | 
	
		
			
				|  |  | -            Tick = false;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            rngTick--;
 | 
	
		
			
				|  |  | -            if (rngTick == 0) {
 | 
	
		
			
				|  |  | +        if (RefreshTick) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +            RefreshTick = false;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +            // On refresh, update the display with new values
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                rngTick = rand() % 60;
 | 
	
		
			
				|  |  | +            for (int i = 0; i < 4; i++) {
 | 
	
		
			
				|  |  | +                for (int j = 0; j < 10; j++) {
 | 
	
		
			
				|  |  | +                    if (DigitNextValue[i][j] != DigitPrevValue[i][j]) {
 | 
	
		
			
				|  |  | +                        PCA9685_SetDigit(i, j, DigitNextValue[i][j]);
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            if (DotNextValue != DotPrevValue) {
 | 
	
		
			
				|  |  | +                PCA9685_SetDot(DotNextValue);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            DS3231_GetTime(&nextSecond, &nextMinute, &nextHour);
 | 
	
		
			
				|  |  | +            memcpy(DigitPrevValue, DigitNextValue, sizeof(DigitPrevValue));
 | 
	
		
			
				|  |  | +            DotPrevValue = DotNextValue;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            // Fade dot/digits to show the updated time
 | 
	
		
			
				|  |  | -            for (int i = 0; i < PCA9685_Max_Brightness; i += 4) {
 | 
	
		
			
				|  |  | +        if (RtcTick) {
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  | +            RtcTick = false;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                if (nextMinute % 10 != currMinute % 10) {
 | 
	
		
			
				|  |  | -                    PCA9685_SetDigit(3, currMinute % 10, PCA9685_Max_Brightness - i);
 | 
	
		
			
				|  |  | -                    PCA9685_SetDigit(3, nextMinute % 10, PCA9685_Min_Brightness + i);
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | +            // On RTC 1Hz ticks, get the time and begin update
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                if (nextMinute / 10 != currMinute / 10) {
 | 
	
		
			
				|  |  | -                    PCA9685_SetDigit(2, currMinute / 10, PCA9685_Max_Brightness - i);
 | 
	
		
			
				|  |  | -                    PCA9685_SetDigit(2, nextMinute / 10, PCA9685_Min_Brightness + i);
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | +            int nextSecond, nextMinute, nextHour;
 | 
	
		
			
				|  |  | +            DS3231_GetTime(&nextSecond, &nextMinute, &nextHour);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                if (nextHour % 10 != currHour % 10 ) {
 | 
	
		
			
				|  |  | -                    PCA9685_SetDigit(1, currHour % 10, PCA9685_Max_Brightness - i);
 | 
	
		
			
				|  |  | -                    PCA9685_SetDigit(1, nextHour % 10, PCA9685_Min_Brightness + i);
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | +            DigitNext.Minute1 = nextMinute % 10;
 | 
	
		
			
				|  |  | +            DigitNext.Minute10 = nextMinute / 10;
 | 
	
		
			
				|  |  | +            DigitNext.Hour1 = nextHour % 10;
 | 
	
		
			
				|  |  | +            DigitNext.Hour10 = nextHour / 10;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                if (nextHour / 10 != currHour / 10) {
 | 
	
		
			
				|  |  | -                    PCA9685_SetDigit(0, currHour / 10, PCA9685_Max_Brightness - i);
 | 
	
		
			
				|  |  | -                    if (nextHour / 10 != 0) {
 | 
	
		
			
				|  |  | -                        PCA9685_SetDigit(0, nextHour / 10, PCA9685_Min_Brightness + i);
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | +            if (StartupFlag) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                PCA9685_SetDot(nextSecond % 2 ? i : PCA9685_Max_Brightness - i);
 | 
	
		
			
				|  |  | +                // Fade in the current time
 | 
	
		
			
				|  |  | +                StartupTicker.attach_us(StartupTickerCallback, 900);
 | 
	
		
			
				|  |  | +                StartupFlag = false;
 | 
	
		
			
				|  |  | +            } 
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                wait(0.0007);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | +            if (RuntimeFlag) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            currMinute = nextMinute;
 | 
	
		
			
				|  |  | -            currHour = nextHour;
 | 
	
		
			
				|  |  | +                // Fade in the new time
 | 
	
		
			
				|  |  | +                RuntimeTickerIter = 1024;
 | 
	
		
			
				|  |  | +                RuntimeTicker.attach_us(RuntimeTickerCallback, 900);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        // Delay a bit to avoid constant polling
 | 
	
		
			
				|  |  | -        wait(0.001);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 |