main.cpp 8.9 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 enum {
  13. Idle = 0,
  14. Incrementing = 1,
  15. Decrementing = 2,
  16. } DigitState;
  17. typedef struct {
  18. DigitState CurrentState;
  19. int Value;
  20. int Brightness;
  21. int Step;
  22. bool Updated;
  23. } Digit;
  24. typedef struct {
  25. Digit Digits[10];
  26. bool Refresh;
  27. int UpdateRate;
  28. } Tube;
  29. Tube Tubes[4]; // Active per-tube configuration
  30. Digit Dot;
  31. Ticker RuntimeUpdateTicker, RngUpdateTicker;
  32. int RuntimeTickerIter, RngTickerIter;
  33. void RtcTickCallback(void) {
  34. RtcTick = true;
  35. }
  36. void RefreshTickCallback(void) {
  37. RefreshTick = true;
  38. }
  39. void RngTickCallback(void) {
  40. RngTick = true;
  41. }
  42. Timeout DotUpdateTick;
  43. void DotUpdateCallback(void) {
  44. if (Dot.CurrentState == Incrementing && Dot.Brightness < PCA9685_Max_Brightness) {
  45. Dot.Brightness += Dot.Step;
  46. } else if (Dot.CurrentState == Decrementing && Dot.Brightness > PCA9685_Min_Brightness) {
  47. Dot.Brightness -= Dot.Step;
  48. }
  49. Dot.Updated = true;
  50. if (Dot.Brightness == PCA9685_Max_Brightness ||
  51. Dot.Brightness == PCA9685_Min_Brightness) {
  52. DotUpdateTick.detach();
  53. } else {
  54. // DotUpdateTick.attach(DotUpdateCallback, (float)1/DOT_FADE_TICKS);
  55. DotUpdateTick.attach_us(DotUpdateCallback, 700);
  56. }
  57. }
  58. void Tube0UpdateCallback(void) {
  59. }
  60. // void RuntimeTickerUpdate(void) {
  61. // for (int i = 0; i < NUM_TUBES; i++) {
  62. // if(!Tube[i].RefreshActive) {
  63. // for (int j = 0; j < MAX_FADE_DIGITS; j++) {
  64. // DIGIT *digit = &Tube[i].Digits[j];
  65. // if (digit->Active) {
  66. // if (digit->Increment && digit->Reg < PCA9685_Max_Brightness) {
  67. // digit->Reg += FADE_TICK_STEP;
  68. // } else if (digit->Reg > PCA9685_Min_Brightness) {
  69. // digit->Reg -= FADE_TICK_STEP;
  70. // }
  71. // Tube[i].Updated = true;
  72. // }
  73. // }
  74. // }
  75. // }
  76. // DotValue = DotIncrement ? DotValue + FADE_TICK_STEP : DotValue - FADE_TICK_STEP;
  77. // DotUpdated = true;
  78. // if (--RuntimeTickerIter == 0) {
  79. // RuntimeUpdateTicker.detach();
  80. // DotIncrement = !DotIncrement;
  81. // }
  82. // }
  83. void RngTickerUpdate(void) {
  84. if (--RngTickerIter == 0) {
  85. RngUpdateTicker.detach();
  86. }
  87. }
  88. int main() {
  89. // Initialize pointers in global data structure
  90. // for (int i = 0; i < NUM_TUBES; i++) {
  91. // Tube[i].NextDigit = &Tube[i].Digits[0];
  92. // }
  93. RtcTick = false;
  94. RefreshTick = false;
  95. RngTick = false;
  96. int nextSecond, nextMinute, nextHour;
  97. int prevMinute, prevHour;
  98. bool startup = true;
  99. // Start I2C at 400kHz for DS3231
  100. i2c.frequency(400000);
  101. // Start with HV PSU disabled
  102. HV_EnableOutput(false);
  103. TUSB322_Init();
  104. PCA9685_Init();
  105. DS3231_Init(RtcTickCallback);
  106. // Enable HV PSU
  107. HV_EnableOutput(true);
  108. // Set PCA9685 input voltage to highest possible
  109. PCA9685_SetVoltage(1.0);
  110. // swo.printf("CPU SystemCoreClock is %d Hz\r\n", SystemCoreClock);
  111. // Bump I2C frequency to 1MHz
  112. // i2c.frequency(1000000);
  113. // Setup a ticker to refresh the display at 1kHz
  114. Ticker refreshTicker;
  115. refreshTicker.attach_us(RefreshTickCallback, DIGIT_REFRESH_RATE_US);
  116. // Kick off the RNG ticker at 0.1Hz
  117. // Ticker rngTicker;
  118. // rngTicker.attach(RngTickCallback, DIGIT_RNG_REFRESH_RATE_S);
  119. // DS3231_SetTime(0, 55, 6, true);
  120. // DS3231_SetDate(0, 2, 12, 18, 0);
  121. Dot.CurrentState = Decrementing;
  122. Dot.Step = DOT_TICK_STEP;
  123. Dot.Brightness = 0;
  124. while(1) {
  125. // Animate_Cycle_Basic();
  126. // Animate_Cycle_Analog();
  127. // Animate_Cycle_Low_Pwm();
  128. // Animate_Cycle_Pwm();
  129. // Animate_Cycle_Fade();
  130. // Animate_Cycle_Fade_Random();
  131. // Animate_Cycle_Fast();
  132. // Animate_Cycle_Fast_Random();
  133. // On every refresh tick, update the display with new values
  134. if (RefreshTick) {
  135. RefreshTick = false;
  136. // for (int i = 0; i < NUM_TUBES; i++) {
  137. // if (Tube[i].Updated) {
  138. // Tube[i].Updated = false;
  139. // for (int j = 0; j < MAX_FADE_DIGITS; j++) {
  140. // DIGIT *digit = &Tube[i].Digits[j];
  141. // if (digit->Active) {
  142. // PCA9685_SetDigit(i, digit->Value, digit->Reg);
  143. // if (digit->Reg == 0 && !digit->Increment) {
  144. // digit->Active = false;
  145. // }
  146. // }
  147. // }
  148. // }
  149. // }
  150. if (Dot.Updated) {
  151. PCA9685_SetDot(Dot.Brightness);
  152. Dot.Updated = false;
  153. }
  154. }
  155. // On every RTC tick, read and process the current time
  156. if (RtcTick) {
  157. RtcTick = false;
  158. // Save the previous time to check if digit(s) has changed
  159. prevMinute = nextMinute;
  160. prevHour = nextHour;
  161. DS3231_GetTime(&nextSecond, &nextMinute, &nextHour);
  162. // Update the display configuration based on the new/previous time
  163. // for (int i = 0; i < NUM_TUBES; i++) {
  164. // bool Update = false;
  165. // if (i == 0 && (startup || 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 && (startup || 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 && (startup || 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 && (startup || 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. // Handle display configuration changes for the given tube
  189. // if (Update) {
  190. // if (!startup) {
  191. // Tube[i].PrevDigit->Increment = false;
  192. // }
  193. // Tube[i].PrevDigit = Tube[i].NextDigit;
  194. // Tube[i].NextDigit = Tube[i].NextDigit == &Tube[i].Digits[0] ?
  195. // &Tube[i].Digits[1] : &Tube[i].Digits[0];
  196. // }
  197. // }
  198. Dot.CurrentState = (Dot.CurrentState == Decrementing) ? Incrementing : Decrementing;
  199. // DotUpdateTick.attach(DotUpdateCallback, (float)1/DOT_FADE_TICKS);
  200. DotUpdateTick.attach_us(DotUpdateCallback, 700);
  201. // Clear the startup run-once flag after the first iteration
  202. // startup = false;
  203. // Fade in the new time
  204. // RuntimeTickerIter = FADE_TICKS;
  205. // RuntimeUpdateTicker.attach(RuntimeTickerUpdate, (float)(DIGIT_REFRESH_RATE_US / 1000) / RuntimeTickerIter);
  206. }
  207. if (RngTick) {
  208. // Choose a random tube to refresh
  209. // Tube[rand() % 4].RefreshActive = true;
  210. // RngTickerIter = DIGIT_RNG_REFRESH_ITER * FADE_TICKS;
  211. // RngUpdateTicker.attach(RngTickerUpdate, (DIGIT_REFRESH_RATE_US/1000)/FADE_TICKS);
  212. // RngTick = false;
  213. }
  214. }
  215. }
  216. void I2C_Write(int DeviceAddress, char RegAddress, char *Data, int Length) {
  217. char buffer[I2C_MAX_BUFFER+1] = {0};
  218. if (Length > I2C_MAX_BUFFER) LED_Fault(1);
  219. buffer[0] = RegAddress;
  220. memcpy(&buffer[1], Data, Length);
  221. i2c.write(DeviceAddress << 1, buffer, Length + 1);
  222. }
  223. void I2C_Read(int DeviceAddress, char RegAddress, char *Data, int Length) {
  224. i2c.write(DeviceAddress << 1, &RegAddress, 1);
  225. i2c.read(DeviceAddress << 1, Data, Length);
  226. }