main.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. #include "mbed.h"
  2. #include "main.h"
  3. #include "SWO.h"
  4. #include "pca9685.h"
  5. #include "tusb322.h"
  6. #include "ds3231.h"
  7. #include "ioc.h"
  8. #include "animation.h"
  9. I2C i2c(PA_10, PA_9);
  10. // SWO_Channel swo("swo");
  11. bool RtcTick, RefreshTick, RngTick;
  12. typedef struct {
  13. char Value;
  14. ushort Reg;
  15. bool Active;
  16. bool Increment;
  17. } DIGIT;
  18. typedef struct {
  19. DIGIT Digits[MAX_FADE_DIGITS];
  20. DIGIT *NextDigit;
  21. DIGIT *PrevDigit;
  22. bool Updated;
  23. bool RefreshActive;
  24. } TUBE;
  25. TUBE Tube[NUM_TUBES] = {0}; // Active per-tube digit setting
  26. ushort DotValue = PCA9685_Min_Brightness;
  27. bool DotUpdated = false;
  28. bool DotIncrement = true;
  29. Ticker StartupUpdateTicker, RuntimeUpdateTicker, RngUpdateTicker;
  30. int StartupTickerIter, RuntimeTickerIter, RngTickerIter;
  31. void RtcTickCallback(void) {
  32. RtcTick = true;
  33. }
  34. void RefreshTickCallback(void) {
  35. RefreshTick = true;
  36. }
  37. void RngTickCallback(void) {
  38. RngTick = true;
  39. }
  40. void RuntimeTickerUpdate(void) {
  41. for (int i = 0; i < NUM_TUBES; i++) {
  42. if(!Tube[i].RefreshActive) {
  43. for (int j = 0; j < MAX_FADE_DIGITS; j++) {
  44. DIGIT *digit = &Tube[i].Digits[j];
  45. if (digit->Active) {
  46. if (digit->Increment && digit->Reg < PCA9685_Max_Brightness) {
  47. digit->Reg += FADE_TICK_STEP;
  48. } else if (digit->Reg > PCA9685_Min_Brightness) {
  49. digit->Reg -= FADE_TICK_STEP;
  50. }
  51. Tube[i].Updated = true;
  52. }
  53. }
  54. }
  55. }
  56. DotValue = DotIncrement ? DotValue + FADE_TICK_STEP : DotValue - FADE_TICK_STEP;
  57. DotUpdated = true;
  58. if (--RuntimeTickerIter == 0) {
  59. RuntimeUpdateTicker.detach();
  60. DotIncrement = !DotIncrement;
  61. }
  62. }
  63. void RngTickerUpdate(void) {
  64. if (--RngTickerIter == 0) {
  65. RngUpdateTicker.detach();
  66. }
  67. }
  68. int main() {
  69. // Initialize pointers in global data structure
  70. for (int i = 0; i < NUM_TUBES; i++) {
  71. Tube[i].NextDigit = &Tube[i].Digits[0];
  72. }
  73. RtcTick = false;
  74. RefreshTick = false;
  75. RngTick = false;
  76. int nextSecond, nextMinute, nextHour;
  77. int prevMinute, prevHour;
  78. bool startup = true;
  79. // Start I2C at 400kHz for DS3231
  80. i2c.frequency(400000);
  81. // Start with HV PSU disabled
  82. HV_EnableOutput(false);
  83. TUSB322_Init();
  84. PCA9685_Init();
  85. DS3231_Init(RtcTickCallback);
  86. // Enable HV PSU
  87. HV_EnableOutput(true);
  88. // Set PCA9685 input voltage to highest possible
  89. PCA9685_SetVoltage(1.0);
  90. // swo.printf("CPU SystemCoreClock is %d Hz\r\n", SystemCoreClock);
  91. // Bump I2C frequency to 1MHz
  92. // i2c.frequency(1000000);
  93. // Setup a ticker to refresh the display at 1kHz
  94. Ticker refreshTicker;
  95. refreshTicker.attach_us(RefreshTickCallback, DIGIT_REFRESH_RATE_US);
  96. // Kick off the RNG ticker at 0.1Hz
  97. // Ticker rngTicker;
  98. // rngTicker.attach(RngTickCallback, DIGIT_RNG_REFRESH_RATE_S);
  99. // DS3231_SetTime(0, 55, 6, true);
  100. // DS3231_SetDate(0, 2, 12, 18, 0);
  101. while(1) {
  102. // Animate_Cycle_Basic();
  103. // Animate_Cycle_Analog();
  104. // Animate_Cycle_Low_Pwm();
  105. // Animate_Cycle_Pwm();
  106. // Animate_Cycle_Fade();
  107. // Animate_Cycle_Fade_Random();
  108. // Animate_Cycle_Fast();
  109. // Animate_Cycle_Fast_Random();
  110. if (RefreshTick) {
  111. RefreshTick = false;
  112. // On refresh, update the display with new values
  113. for (int i = 0; i < NUM_TUBES; i++) {
  114. if (Tube[i].Updated) {
  115. Tube[i].Updated = false;
  116. for (int j = 0; j < MAX_FADE_DIGITS; j++) {
  117. DIGIT *digit = &Tube[i].Digits[j];
  118. if (digit->Active) {
  119. PCA9685_SetDigit(i, digit->Value, digit->Reg);
  120. if (digit->Reg == 0 && !digit->Increment) {
  121. digit->Active = false;
  122. }
  123. }
  124. }
  125. }
  126. }
  127. if (DotUpdated) {
  128. PCA9685_SetDot(DotValue);
  129. DotUpdated = false;
  130. }
  131. }
  132. if (RtcTick) {
  133. RtcTick = false;
  134. prevMinute = nextMinute;
  135. prevHour = nextHour;
  136. DS3231_GetTime(&nextSecond, &nextMinute, &nextHour);
  137. if (startup) {
  138. startup = false;
  139. for (int i = 0; i < NUM_TUBES; i++) {
  140. bool Update = false;
  141. if (i == 0 && nextHour / 10 != 0) {
  142. Tube[i].NextDigit->Value = nextHour / 10;
  143. Update = true;
  144. } else if (i == 1) {
  145. Tube[i].NextDigit->Value = nextHour % 10;
  146. Update = true;
  147. } else if (i == 2) {
  148. Tube[i].NextDigit->Value = nextMinute / 10;
  149. Update = true;
  150. } else if (i == 3) {
  151. Tube[i].NextDigit->Value = nextMinute % 10;
  152. Update = true;
  153. }
  154. if (Update) {
  155. Tube[i].NextDigit->Increment = true;
  156. Tube[i].NextDigit->Active = true;
  157. Tube[i].PrevDigit = Tube[i].NextDigit;
  158. Tube[i].NextDigit = (Tube[i].NextDigit == &Tube[i].Digits[0]) ?
  159. &Tube[i].Digits[1] : &Tube[i].Digits[0];
  160. }
  161. }
  162. } else {
  163. for (int i = 0; i < NUM_TUBES; i++) {
  164. bool Update = false;
  165. if (i == 0 && ((prevHour / 10) != (nextHour / 10))) {
  166. if (nextHour / 10 != 0) {
  167. Tube[i].NextDigit->Value = nextHour / 10;
  168. Tube[i].NextDigit->Increment = true;
  169. Tube[i].NextDigit->Active = true;
  170. }
  171. Update = true;
  172. } else if (i == 1 && ((prevHour % 10) != (nextHour % 10))) {
  173. Tube[i].NextDigit->Value = nextHour % 10;
  174. Tube[i].NextDigit->Increment = true;
  175. Tube[i].NextDigit->Active = true;
  176. Update = true;
  177. } else if (i == 2 && ((prevMinute / 10) != (nextMinute / 10))) {
  178. Tube[i].NextDigit->Value = nextMinute / 10;
  179. Tube[i].NextDigit->Increment = true;
  180. Tube[i].NextDigit->Active = true;
  181. Update = true;
  182. } else if (i == 3 && ((prevMinute % 10) != (nextMinute % 10))) {
  183. Tube[i].NextDigit->Value = nextMinute % 10;
  184. Tube[i].NextDigit->Increment = true;
  185. Tube[i].NextDigit->Active = true;
  186. Update = true;
  187. }
  188. if (Update) {
  189. Tube[i].PrevDigit->Increment = false;
  190. Tube[i].PrevDigit = Tube[i].NextDigit;
  191. Tube[i].NextDigit = (Tube[i].NextDigit == &Tube[i].Digits[0]) ?
  192. &Tube[i].Digits[1] : &Tube[i].Digits[0];
  193. }
  194. }
  195. }
  196. // Fade in the new time
  197. RuntimeTickerIter = FADE_TICKS;
  198. RuntimeUpdateTicker.attach(RuntimeTickerUpdate, (float)(DIGIT_REFRESH_RATE_US / 1000) / RuntimeTickerIter);
  199. }
  200. if (RngTick) {
  201. // Choose a random tube to refresh
  202. Tube[rand() % 4].RefreshActive = true;
  203. RngTickerIter = DIGIT_RNG_REFRESH_ITER * FADE_TICKS;
  204. RngUpdateTicker.attach(RngTickerUpdate, (DIGIT_REFRESH_RATE_US/1000)/FADE_TICKS);
  205. RngTick = false;
  206. }
  207. }
  208. }
  209. void I2C_Write(int DeviceAddress, char RegAddress, char *Data, int Length) {
  210. char buffer[I2C_MAX_BUFFER+1] = {0};
  211. if (Length > I2C_MAX_BUFFER) LED_Fault(1);
  212. buffer[0] = RegAddress;
  213. memcpy(&buffer[1], Data, Length);
  214. i2c.write(DeviceAddress << 1, buffer, Length + 1);
  215. }
  216. void I2C_Read(int DeviceAddress, char RegAddress, char *Data, int Length) {
  217. i2c.write(DeviceAddress << 1, &RegAddress, 1);
  218. i2c.read(DeviceAddress << 1, Data, Length);
  219. }