LED clock
 All Files Functions Variables Macros Groups Pages
main.c
Go to the documentation of this file.
1 /* This program is free software: you can redistribute it and/or modify
2  * it under the terms of the GNU General Public License as published by
3  * the Free Software Foundation, either version 3 of the License, or
4  * (at your option) any later version.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public License
12  * along with this program. If not, see <http://www.gnu.org/licenses/>.
13  *
14  */
21 /* standard libraries */
22 #include <stdint.h> // standard integer types
23 #include <stdio.h> // standard I/O facilities
24 #include <stdlib.h> // standard utilities
25 #include <unistd.h> // standard streams
26 #include <errno.h> // error number utilities
27 #include <string.h> // string utilities
28 #include <math.h> // mathematical utilities
29 
30 /* STM32 (including CM3) libraries */
31 #include <libopencm3/stm32/rcc.h> // real-time control clock library
32 #include <libopencm3/stm32/gpio.h> // general purpose input output library
33 #include <libopencm3/cm3/scb.h> // vector table definition
34 #include <libopencmsis/core_cm3.h> // Cortex M3 utilities
35 #include <libopencm3/cm3/nvic.h> // interrupt utilities
36 #include <libopencm3/stm32/exti.h> // external interrupt utilities
37 #include <libopencm3/stm32/timer.h> // timer utilities
38 #include <libopencm3/stm32/adc.h> // ADC utilities
39 #include <libopencm3/stm32/rtc.h> // real time clock utilities
40 
41 /* own libraries */
42 #include "global.h" // board definitions
43 #include "usart.h" // USART utilities
44 #include "usb_cdcacm.h" // USB CDC ACM utilities
45 #include "led_ws2812b.h" // WS2812b LEDs utilities
46 
50 volatile bool button_flag = false;
51 volatile bool time_flag = false;
52 volatile bool photoresistor_flag = false;
61 #define TICKS_PER_SECOND 256
62 
63 const uint32_t ticks_second = TICKS_PER_SECOND;
65 const uint32_t ticks_minute = 60*TICKS_PER_SECOND;
67 const uint32_t ticks_hour = 60*60*TICKS_PER_SECOND;
69 const uint32_t ticks_midday = 12*60*60*TICKS_PER_SECOND;
75 #define BATTERY_ADC_CHANNEL ADC_CHANNEL1
76 #define BATTERY_PORT GPIOA
77 #define BATTERY_PORT_RCC RCC_GPIOA
78 #define BATTERY_PIN GPIO1
83 #define PHOTORESISTOR_ADC_CHANNEL ADC_CHANNEL0
84 #define PHOTORESISTOR_PORT GPIOA
85 #define PHOTORESISTOR_PORT_RCC RCC_GPIOA
86 #define PHOTORESISTOR_PIN GPIO0
91 uint8_t clock_leds[WS2812B_LEDS*3] = {0};
92 
93 char command[32] = {0};
95 uint8_t command_i = 0;
97 uint8_t gamma_correction_lut[256] = {0};
99 volatile uint16_t photoresistor_value = 0;
101 #define PHOTORESISTOR_MIN 2.7
102 
103 #define PHOTORESISTOR_MAX 1.7
104 
107 #define BRIGHTNESS_MIN 0.2
108 
109 #define BRIGHTNESS_MAX 1.0
110 
111 #define BRIGHTNESS_FACTOR 0.1
112 
113 int _write(int file, char *ptr, int len)
114 {
115  int i;
116 
117  if (file == STDOUT_FILENO || file == STDERR_FILENO) {
118  for (i = 0; i < len; i++) {
119  if (ptr[i] == '\n') { // add carrier return before line feed. this is recommended for most UART terminals
120  usart_putchar_nonblocking('\r'); // a second line feed doesn't break the display
121  cdcacm_putchar('\r'); // a second line feed doesn't break the display
122  }
123  usart_putchar_nonblocking(ptr[i]); // send byte over USART
124  cdcacm_putchar(ptr[i]); // send byte over USB
125  }
126  return i;
127  }
128  errno = EIO;
129  return -1;
130 }
131 
132 char* b2s(uint32_t binary, uint8_t rjust)
133 {
134  static char string[32+1] = {0}; // the string representation to return
135  int16_t bit = LENGTH(string)-1; // the index of the bit to print
136  string[bit--] = 0; // terminate string
137 
138  while (binary) {
139  if (binary & 1) {
140  string[bit--] = '1';
141  } else {
142  string[bit--] = '0';
143  }
144  binary >>= 1;
145  }
146 
147  while (32-bit-1<rjust && bit>=0) {
148  string[bit--] = '0';
149  }
150 
151  return &string[bit+1];
152 }
153 
157 static void clock_clear(void)
158 {
159  // set all colors of all LEDs to 0
160  for (uint16_t i=0; i<LENGTH(clock_leds); i++) {
161  clock_leds[i] = 0;
162  }
163 }
164 
170 static void clock_show_time(uint32_t time)
171 {
172  uint32_t led_hour = (WS2812B_LEDS*(256*(uint64_t)(time%ticks_midday)))/ticks_midday; // scale to LED brightnesses for hours
173  uint32_t led_minute = (WS2812B_LEDS*(256*(uint64_t)(time%ticks_hour)))/ticks_hour; // scale to LED brightnesses for minutes
174  if (led_hour>=WS2812B_LEDS*256 || led_minute>=WS2812B_LEDS*256) { // a calculation error occurred
175  return;
176  }
177  // show hours and minutes on LEDs
178  if (led_hour>led_minute) {
179  // show hours in blue (and clear other LEDs)
180  for (uint16_t led=0; led<WS2812B_LEDS; led++) {
181  clock_leds[led*3+0] = 0;
182  clock_leds[led*3+1] = 0;
183  if (led_hour>=0xff) { // full hours
184  clock_leds[led*3+2] = 0xff;
185  } else { // running hours
186  clock_leds[led*3+2] = led_hour;
187  }
188  led_hour -= clock_leds[led*3+2];
189  }
190  // show minutes in green (override hours)
191  for (uint16_t led=0; led<WS2812B_LEDS && led_minute>0; led++) {
192  clock_leds[led*3+0] = 0;
193  if (led_minute>=0xff) { // full minutes
194  clock_leds[led*3+1] = 0xff;
195  } else { // running minutes
196  clock_leds[led*3+1] = led_minute;
197  }
198  led_minute -= clock_leds[led*3+1];
199  clock_leds[led*3+2] = 0;
200  }
201  } else {
202  // show minutes in green (and clear other LEDs)
203  for (uint16_t led=0; led<WS2812B_LEDS; led++) {
204  clock_leds[led*3+0] = 0;
205  if (led_minute>=0xff) { // full minutes
206  clock_leds[led*3+1] = 0xff;
207  } else { // running minutes
208  clock_leds[led*3+1] = led_minute;
209  }
210  led_minute -= clock_leds[led*3+1];
211  clock_leds[led*3+2] = 0;
212  }
213  // show hours in blue (override minutes)
214  for (uint16_t led=0; led<WS2812B_LEDS && led_hour>0; led++) {
215  clock_leds[led*3+0] = 0;
216  clock_leds[led*3+1] = 0;
217  if (led_hour>=0xff) { // full hours
218  clock_leds[led*3+2] = 0xff;
219  } else { // running hours
220  clock_leds[led*3+2] = led_hour;
221  }
222  led_hour -= clock_leds[led*3+2];
223  }
224  }
225  // don't show seconds on full minute (better for first time setting, barely visible else)
226  if (time%ticks_minute==0) {
227  return;
228  }
229  uint32_t led_second = (WS2812B_LEDS*(256*(uint64_t)(time%ticks_minute)))/ticks_minute; // scale to LED brightnesses for seconds
230  uint8_t brightness_second = led_second%256; // get brightness for seconds for last LED
231  uint16_t second_led = (WS2812B_LEDS*(time%ticks_minute))/ticks_minute; // get LED for seconds (we only use the last LED as runner instead of all LEDs as arc)
232  // set seconds LED
233  clock_leds[second_led*3+0] = brightness_second;
234  //clock_leds[second_led*3+1] = 0; // clear other colors (minutes/hours indication)
235  //clock_leds[second_led*3+2] = 0; // clear other colors (minutes/hours indication)
236  // set previous seconds LED
237  second_led = ((second_led==0) ? WS2812B_LEDS-1 : second_led-1); // previous LED
238  clock_leds[second_led*3+0] = 0xff-brightness_second;
239  //clock_leds[second_led*3+1] = 0; // clear other colors (minutes/hours indication)
240  //clock_leds[second_led*3+2] = 0; // clear other colors (minutes/hours indication)
241 }
242 
247 static void clock_leds_set(void)
248 {
249  for (uint16_t i=0; i<LENGTH(clock_leds)/3; i++) {
250  ws2812b_set_rgb(i,gamma_correction_lut[(uint8_t)(clock_leds[i*3+0]*clock_brightness)],gamma_correction_lut[(uint8_t)(clock_leds[i*3+1]*clock_brightness)],gamma_correction_lut[(uint8_t)(clock_leds[i*3+2]*clock_brightness)]); // set new value (this costs time)
251  }
252 }
253 
257 static void clock_set_time(uint32_t time)
258 {
259  clock_show_time(time); // set time
260  clock_leds_set(); // set the colors of all LEDs
261  ws2812b_transmit(); // transmit set color
262 }
263 
268 static void clock_animate_time(uint32_t time)
269 {
270  static uint32_t display_time = 0; // the time to display
271  while (display_time<time) {
272  if (display_time+ticks_hour<=time) { // first set hours
273  display_time += ticks_hour; // increment hours
274  } else if (display_time+ticks_minute<=time) { // second set minutes
275  display_time += ticks_minute; // increment minutes
276  } else if (display_time+ticks_second<=time) { // third set seconds
277  display_time += ticks_second; // increment seconds
278  } else { // finally set time
279  display_time = time;
280  }
281  clock_set_time(display_time); // set time (progress)
282  // delay some time for the animation
283  for (uint32_t i=0; i<400000; i++) {
284  __asm__("nop");
285  }
286  }
287 }
288 
291 static void clock_hours(void)
292 {
293  for (uint16_t i=0; i<512; i++) { // fade in and out
294  uint8_t brightness = (i>255 ? 512-i-1 : i); // get fade brightness
295  for (uint8_t hour=0; hour<12; hour++) { // set all hour colors
296  uint16_t led = WS2812B_LEDS/12*hour; // get LED four hour mark
297  clock_leds[led*3+0] = brightness; // set brightness
298  clock_leds[led*3+1] = brightness; // set brightness
299  clock_leds[led*3+2] = brightness; // set brightness
300  }
301  clock_leds_set(); // set the colors of all LEDs
302  ws2812b_transmit(); // transmit set color
303  // delay some time for the animation
304  for (uint32_t j=0; j<40000; j++) {
305  __asm__("nop");
306  }
307  }
308 }
309 
313 static void process_command(char* str)
314 {
315  // split command
316  const char* delimiter = " ";
317  char* word = strtok(str,delimiter);
318  if (!word) {
319  goto error;
320  }
321  // parse command
322  if (0==strcmp(word,"help")) {
323  printf("available commands:\n");
324  printf("time [HH:MM:SS]\n");
325  } else if (0==strcmp(word,"time")) {
326  word = strtok(NULL,delimiter);
327  if (!word) {
328  printf("%02lu:%02lu:%02lu\n", rtc_get_counter_val()/ticks_hour, (rtc_get_counter_val()%ticks_hour)/ticks_minute, (rtc_get_counter_val()%ticks_minute)/ticks_second);
329  } else if (strlen(word)!=8 || word[0]<'0' || word[0]>'2' || word[1]<'0' || word[1]>'9' || word[3]<'0' || word[3]>'5' || word[4]<'0' || word[4]>'9' || word[6]<'0' || word[6]>'5' || word[7]<'0' || word[7]>'9') {
330  goto error;
331  } else {
332  rtc_set_counter_val(((word[0]-'0')*10+(word[1]-'0')*1)*ticks_hour+((word[3]-'0')*10+(word[4]-'0')*1)*ticks_minute+((word[6]-'0')*10+(word[7]-'0')*1)*ticks_second); // set time in RTC counter
333  printf("time set\n");
334  }
335  } else {
336  goto error;
337  }
338 
339  return; // command successfully processed
340 error:
341  puts("command not recognized. enter help to list commands");
342 }
343 
347 int main(void)
348 {
349  rcc_clock_setup_in_hse_8mhz_out_72mhz(); // use 8 MHz high speed external clock to generate 72 MHz internal clock
350  usart_setup(); // setup USART (for printing)
351  cdcacm_setup(); // setup USB CDC ACM (for printing)
352  setbuf(stdout, NULL); // set standard out buffer to NULL to immediately print
353  setbuf(stderr, NULL); // set standard error buffer to NULL to immediately print
354 
355  // setup LED
356  rcc_periph_clock_enable(LED_RCC); // enable clock for LED
357  gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, LED_PIN); // set LED pin to 'output push-pull'
358  led_off(); // switch off LED to indicate setup started
359 
360  // setup button
361 #if defined(BUTTON_RCC) && defined(BUTTON_PORT) && defined(BUTTON_PIN) && defined(BUTTON_EXTI) && defined(BUTTON_IRQ)
362  rcc_periph_clock_enable(BUTTON_RCC); // enable clock for button
363  gpio_set_mode(BUTTON_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, BUTTON_PIN); // set button pin to input
364  rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt
365  exti_select_source(BUTTON_EXTI, BUTTON_PORT); // mask external interrupt of this pin only for this port
366  exti_set_trigger(BUTTON_EXTI, EXTI_TRIGGER_BOTH); // trigger on both edge
367  exti_enable_request(BUTTON_EXTI); // enable external interrupt
368  nvic_enable_irq(BUTTON_IRQ); // enable interrupt
369 #endif
370 
371  // setup RTC
372  rtc_auto_awake(RCC_LSE, 32768/ticks_second-1); // ensure RTC is on, uses the 32.678 kHz LSE, and the prescale is set to our tick speed, else update backup registers accordingly (power off the micro-controller for the change to take effect)
373  rtc_interrupt_enable(RTC_SEC); // enable RTC interrupt on "seconds"
374  nvic_enable_irq(NVIC_RTC_IRQ); // allow the RTC to interrupt
375 
376  // generate gamma correction table (with fixed gamma value)
377  for (uint16_t i=0; i<LENGTH(gamma_correction_lut); i++) {
378  gamma_correction_lut[i] = powf((float)i / (float)LENGTH(gamma_correction_lut), 2.2)*LENGTH(gamma_correction_lut);
379  }
380 
381  // setup WS2812b LEDs
382  ws2812b_setup(); // setup WS2812b LEDs
383  clock_clear(); // clear all LEDs
384  clock_leds_set(); // set the colors of all LEDs
385  ws2812b_transmit(); // transmit set color
386 
387  // setup ADC to read battery voltage
388  rcc_periph_clock_enable(BATTERY_PORT_RCC); // enable clock for battery GPIO peripheral
389  gpio_set_mode(BATTERY_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG, BATTERY_PIN); // set battery GPIO as analogue input for the ADC
390  rcc_periph_clock_enable(PHOTORESISTOR_PORT_RCC); // enable clock for photo-resistor GPIO peripheral
391  gpio_set_mode(PHOTORESISTOR_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG, PHOTORESISTOR_PIN); // set photo-resistor GPIO as analogue input for the ADC
392  rcc_periph_clock_enable(RCC_ADC1); // enable clock for ADC peripheral
393  adc_off(ADC1); // switch off ADC while configuring it
394  // configuration is correct per default
395  adc_set_single_conversion_mode(ADC1); // we just want one measurement
396  adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_28DOT5CYC); // use 28.5 cycles to sample (long enough to be stable)
397  adc_enable_temperature_sensor(ADC1); // enable internal voltage reference
398  adc_enable_discontinuous_mode_regular(ADC1, 1); // do only one conversion per sequence
399  adc_enable_external_trigger_regular(ADC1, ADC_CR2_EXTSEL_SWSTART); // use software trigger to start conversion
400  adc_power_on(ADC1); // switch on ADC
401  for (uint32_t i=0; i<800000; i++) { // wait t_stab for the ADC to stabilize
402  __asm__("nop");
403  }
404  adc_reset_calibration(ADC1); // remove previous non-calibration
405  adc_calibration(ADC1); // calibrate ADC for less accuracy errors
406 
407  printf("welcome to the CuVoodoo LED clock\n"); // print welcome message
408  led_on(); // switch on LED to indicate setup completed
409 
410  // read internal reference 1.2V and RTC battery voltages
411  uint8_t channels[] = {ADC_CHANNEL17, BATTERY_ADC_CHANNEL}; // voltages to convert
412  adc_set_regular_sequence(ADC1, LENGTH(channels), channels); // set channels to convert
413  adc_start_conversion_regular(ADC1); // start conversion to get first voltage of this group
414  while (!adc_eoc(ADC1)); // wait until conversion finished
415  uint16_t ref_value = adc_read_regular(ADC1); // read internal reference 1.2V voltage value
416  adc_start_conversion_regular(ADC1); // start conversion to get second voltage of this group
417  while (!adc_eoc(ADC1)); // wait until conversion finished
418  uint16_t battery_value = adc_read_regular(ADC1); // read converted battery voltage
419  float battery_voltage = battery_value*1.2/ref_value; // calculate battery voltage
420  if (battery_voltage<1.0) {
421  printf("no battery detected\n");
422  } else {
423  if (battery_voltage<2.4) { // low battery voltage
424  printf("/!\\ low ");
425  for (uint16_t led=0; led<2; led++) { // display red on 2 LEDs
426  clock_leds[led*3+0] = 0xff; // set red
427  }
428  } else if (battery_voltage>3.0) { // battery full
429  for (uint16_t led=0; led<WS2812B_LEDS; led++) { // display green on all LEDs
430  clock_leds[led*3+1] = 0xff; // set green
431  }
432  } else { // intermediate batter voltage
433  for (uint16_t led=0; led<(uint8_t)(WS2812B_LEDS*(battery_voltage-2.4)/0.6); led++) { // display blue on proportional LEDs
434  clock_leds[led*3+2] = 0xff; // set blue
435  }
436  }
437  printf("battery voltage: %.2fV\n", battery_voltage);
438  clock_leds_set(); // set the colors of all LEDs
439  ws2812b_transmit(); // transmit set color
440  for (uint32_t i=0; i<10000000; i++) { // display for a small while
441  __asm__("nop");
442  }
443  }
444 
445  // now use interrupts to only measure ambient luminosity
446  channels[0] = PHOTORESISTOR_ADC_CHANNEL; // only measure ambient luminosity
447  adc_set_regular_sequence(ADC1, 1, channels); // set now group
448  adc_enable_eoc_interrupt(ADC1); // enable interrupt for end of convertion
449  nvic_enable_irq(NVIC_ADC1_2_IRQ); // enable ADC interrupts
450 
451  // get date and time
452  printf("current time: %02lu:%02lu:%02lu\n", rtc_get_counter_val()/ticks_hour, (rtc_get_counter_val()%ticks_hour)/ticks_minute, (rtc_get_counter_val()%ticks_minute)/ticks_second); // display time
453  clock_animate_time(rtc_get_counter_val()); // set time with animation
454 
455  printf("input commands\n");
456  bool action = false; // if an action has been performed don't go to sleep
457  button_flag = false; // reset button flag
458  char c = ' '; // to store received character
459  bool char_flag = false; // a new character has been received
460  while (true) { // infinite loop
461  while (usart_received) { // data received over UART
462  action = true; // action has been performed
463  led_toggle(); // toggle LED
464  c = usart_getchar(); // store receive character
465  char_flag = true; // notify character has been received
466  }
467  while (cdcacm_received) { // data received over USB
468  action = true; // action has been performed
469  led_toggle(); // toggle LED
470  c = cdcacm_getchar(); // store receive character
471  char_flag = true; // notify character has been received
472  }
473  while (char_flag) { // user data received
474  char_flag = false; // reset flag
475  action = true; // action has been performed
476  printf("%c",c); // echo receive character
477  if (c=='\n') { // end of command received
478  if (command_i>0) { // there is a command to process
479  command[command_i] = 0; // end string
480  command_i = 0; // prepare for next command
481  process_command(command); // process user command
482  }
483  } else if (c!='\r') { // user command input
484  command[command_i] = c; // save command input
485  if (command_i<LENGTH(command)-2) { // verify if there is place to save next character
486  command_i++; // save next character
487  }
488  }
489  }
490  while (button_flag) { // user pressed button
491  button_flag = false; // reset flag
492  action = true; // action has been performed
493  led_toggle(); // toggle LED
494  }
495  while (time_flag) { // time passed
496  time_flag = false; // reset flag
497  action = true; // action has been performed
498  if ((rtc_get_counter_val()%(ticks_second/10))==0) { // one tenth of a second passed
499  adc_start_conversion_regular(ADC1); // start measuring ambient luminosity
500  }
501  if ((rtc_get_counter_val()%ticks_second)==0) { // one second passed
502  //led_toggle(); // don't use the LED, this confuses the 32.768 kHz oscillator
503  }
504  if ((rtc_get_counter_val()%ticks_minute)==0) { // one minute passed
505  printf("%02lu:%02lu:%02lu\n", rtc_get_counter_val()/ticks_hour, (rtc_get_counter_val()%ticks_hour)/ticks_minute, (rtc_get_counter_val()%ticks_minute)/ticks_second); // display time
506  }
507  if ((rtc_get_counter_val()%ticks_hour)==0) { // one hours passed
508  clock_hours(); // show hour markers
509  }
510  if (rtc_get_counter_val()>=ticks_midday*2) { // one day passed
511  rtc_set_counter_val(rtc_get_counter_val()%ticks_midday); // reset time counter
512  }
513  clock_set_time(rtc_get_counter_val()); // set time
514  }
515  while (photoresistor_flag) { // new photo-resistor value has been measured
516  photoresistor_flag = false; // reset flag
517  action = true; // action has been performed
518  float photoresistor_voltage = photoresistor_value*1.2/ref_value; // calculate voltage from value
519  float new_clock_brightness = 0; // to calculate new brightness
520  if (photoresistor_voltage<PHOTORESISTOR_MAX) { // high ambient luminosity
521  new_clock_brightness = BRIGHTNESS_MAX; // set highest brightness
522  } else if (photoresistor_voltage>PHOTORESISTOR_MIN) { // low ambient luminosity
523  new_clock_brightness = BRIGHTNESS_MIN; // set low brightness
524  } else { // intermediate ambient luminosity
525  new_clock_brightness = BRIGHTNESS_MIN+(BRIGHTNESS_MAX-BRIGHTNESS_MIN)*(1-(photoresistor_voltage-PHOTORESISTOR_MAX)/(PHOTORESISTOR_MIN-PHOTORESISTOR_MAX)); // set variable brightness
526  }
527  clock_brightness = clock_brightness*(1-BRIGHTNESS_FACTOR)+new_clock_brightness*BRIGHTNESS_FACTOR; // calculate new brightness based on factor
528  //printf("photo-resistor voltage: %f, clock brightness: %f\n", photoresistor_voltage, clock_brightness);
529  }
530  if (action) { // go to sleep if nothing had to be done, else recheck for activity
531  action = false;
532  } else {
533  __WFI(); // go to sleep
534  }
535  }
536 
537  return 0;
538 }
539 
540 #if defined(BUTTON_ISR) && defined(BUTTON_EXTI)
541 
542 void BUTTON_ISR(void)
543 {
544  exti_reset_request(BUTTON_EXTI); // reset interrupt
545  button_flag = true; // perform button action
546 }
547 #endif
548 
550 void rtc_isr(void)
551 {
552  rtc_clear_flag(RTC_SEC); // clear flag
553  time_flag = true; // notify to show new time
554 }
555 
557 void adc1_2_isr(void)
558 {
559  photoresistor_value = adc_read_regular(ADC1); // read measured photo-resistor value (clears interrupt flag)
560  photoresistor_flag = true; // notify new ambient luminosity has been measured
561 }
float clock_brightness
Definition: main.c:105
char * b2s(uint32_t binary, uint8_t rjust)
get binary representation of a number
Definition: main.c:132
static void clock_clear(void)
switch off all clock LEDs
Definition: main.c:157
const uint32_t ticks_second
Definition: main.c:63
#define BATTERY_PIN
Definition: main.c:78
void ws2812b_setup(void)
setup WS2812b LED driver
Definition: led_ws2812b.c:125
void cdcacm_putchar(char c)
send character over USB (non-blocking)
Definition: usb_cdcacm.c:392
char command[32]
Definition: main.c:93
const uint32_t ticks_midday
Definition: main.c:69
void led_off(void)
switch off board LED
Definition: global.h:73
#define PHOTORESISTOR_ADC_CHANNEL
Definition: main.c:83
static void clock_set_time(uint32_t time)
set the time on the LEDs
Definition: main.c:257
static void process_command(char *str)
process user command
Definition: main.c:313
#define BRIGHTNESS_MIN
Definition: main.c:107
#define BATTERY_ADC_CHANNEL
Definition: main.c:75
static void clock_show_time(uint32_t time)
show time on LED clock
Definition: main.c:170
static void clock_hours(void)
show animation with fading hours mark on clock LEDs
Definition: main.c:291
global definitions and methods
volatile uint8_t usart_received
Definition: usart.c:58
#define PHOTORESISTOR_MIN
Definition: main.c:101
volatile uint16_t photoresistor_value
Definition: main.c:99
void led_on(void)
switch on board LED
Definition: global.h:64
void cdcacm_setup(void)
setup USB CDC ACM peripheral
Definition: usb_cdcacm.c:358
void adc1_2_isr(void)
interrupt service routine called when ADC conversion completed
Definition: main.c:557
void led_toggle(void)
toggle board LED
Definition: global.h:82
#define PHOTORESISTOR_PIN
Definition: main.c:86
uint8_t gamma_correction_lut[256]
Definition: main.c:97
volatile uint8_t cdcacm_received
Definition: usb_cdcacm.c:211
static void clock_leds_set(void)
set the LEDs
Definition: main.c:247
uint8_t command_i
Definition: main.c:95
#define BATTERY_PORT
Definition: main.c:76
void rtc_isr(void)
interrupt service routine called when tick passed on RTC
Definition: main.c:550
void usart_putchar_nonblocking(char c)
send character over USART (non-blocking)
Definition: usart.c:117
#define BRIGHTNESS_MAX
Definition: main.c:109
library for USART communication (API)
volatile bool photoresistor_flag
Definition: main.c:52
#define WS2812B_LEDS
Definition: led_ws2812b.h:24
bool ws2812b_transmit(void)
transmit color values to WS2812b LEDs
Definition: led_ws2812b.c:107
#define BRIGHTNESS_FACTOR
Definition: main.c:111
#define PHOTORESISTOR_MAX
Definition: main.c:103
char usart_getchar(void)
get character received over USART (blocking)
Definition: usart.c:103
library for USB CDC ACM communication (API)
volatile bool button_flag
Definition: main.c:50
#define TICKS_PER_SECOND
Definition: main.c:61
#define LENGTH(x)
Definition: global.h:26
uint8_t clock_leds[WS2812B_LEDS *3]
Definition: main.c:91
int _write(int file, char *ptr, int len)
default printf output
Definition: main.c:113
volatile bool time_flag
Definition: main.c:51
static void clock_animate_time(uint32_t time)
incrementally set the time on the LEDs
Definition: main.c:268
#define PHOTORESISTOR_PORT
Definition: main.c:84
int main(void)
program entry point this is the firmware function started by the micro-controller ...
Definition: main.c:347
void usart_setup(void)
setup USART peripheral
Definition: usart.c:60
#define BATTERY_PORT_RCC
Definition: main.c:77
#define PHOTORESISTOR_PORT_RCC
Definition: main.c:85
library to drive a WS2812b LED chain (API)
void ws2812b_set_rgb(uint16_t led, uint8_t red, uint8_t green, uint8_t blue)
set color of a single LED
Definition: led_ws2812b.c:81
char cdcacm_getchar(void)
get character received over USB (blocking)
Definition: usb_cdcacm.c:380
const uint32_t ticks_hour
Definition: main.c:67
const uint32_t ticks_minute
Definition: main.c:65