31 #include <libopencm3/stm32/rcc.h>
32 #include <libopencm3/stm32/gpio.h>
33 #include <libopencm3/cm3/scb.h>
34 #include <libopencmsis/core_cm3.h>
35 #include <libopencm3/cm3/nvic.h>
36 #include <libopencm3/stm32/exti.h>
37 #include <libopencm3/stm32/adc.h>
38 #include <libopencm3/stm32/rtc.h>
49 #define EXTERNAL_RTC false
56 #if defined(EXTERNAL_RTC) && EXTERNAL_RTC
68 #if defined(EXTERNAL_RTC) && EXTERNAL_RTC
69 #define TICKS_PER_SECOND (RTC_DS1307_SQUARE_WAVE_FREQUENCY/RTC_DS1307_SQUARE_WAVE_TICKS)
71 #define TICKS_PER_SECOND 256
86 #define PHOTORESISTOR_ADC_CHANNEL ADC_CHANNEL1
87 #define PHOTORESISTOR_PORT GPIOA
88 #define PHOTORESISTOR_PORT_RCC RCC_GPIOA
89 #define PHOTORESISTOR_PIN GPIO1
94 uint8_t clock_leds[LED_WS2812B_LEDS*3] = {0};
104 #define PHOTORESISTOR_MIN 2.7
106 #define PHOTORESISTOR_MAX 1.7
110 #define BRIGHTNESS_MIN 0.2
112 #define BRIGHTNESS_MAX 1.0
114 #define BRIGHTNESS_FACTOR 0.1
119 static char newline = 0;
121 if (file == STDOUT_FILENO || file == STDERR_FILENO) {
122 for (i = 0; i < len; i++) {
123 if (ptr[i] ==
'\r' || ptr[i] ==
'\n') {
124 if (newline==0 || (newline==ptr[i])) {
131 if (ptr[i] ==
'\n') {
146 char*
b2s(uint64_t binary, uint8_t rjust)
148 static char string[64+1] = {0};
149 int8_t bit =
LENGTH(
string)-1;
161 while (64-bit-1<rjust && bit>=0) {
165 return &
string[bit+1];
192 if (led_hour>led_minute) {
197 if (led_hour>=0xff) {
205 for (uint16_t led=0; led<LED_WS2812B_LEDS && led_minute>0; led++) {
207 if (led_minute>=0xff) {
219 if (led_minute>=0xff) {
228 for (uint16_t led=0; led<LED_WS2812B_LEDS && led_hour>0; led++) {
231 if (led_hour>=0xff) {
244 uint8_t brightness_second = led_second%256;
247 clock_leds[second_led*3+0] = brightness_second;
252 clock_leds[second_led*3+0] = 0xff-brightness_second;
284 static uint32_t display_time = 0;
285 while (display_time<time) {
297 for (uint32_t i=0; i<400000; i++) {
307 for (uint16_t i=0; i<512; i++) {
308 uint8_t brightness = (i>255 ? 512-i-1 : i);
309 for (uint8_t hour=0; hour<12; hour++) {
318 for (uint32_t j=0; j<40000; j++) {
330 const char* delimiter =
" ";
331 char* word = strtok(str,delimiter);
336 if (0==strcmp(word,
"help")) {
337 printf(
"available commands:\n");
338 printf(
"DCF77 on|off\n");
339 printf(
"time [HH:MM:SS]\n");
340 #if defined(EXTERNAL_RTC) && EXTERNAL_RTC
341 printf(
"date [YYYY-MM-DD]\n");
343 }
else if (0==strcmp(word,
"DCF77")) {
344 word = strtok(NULL,delimiter);
347 }
else if (0==strcmp(word,
"on")) {
349 printf(
"DCF77 receiver switched on\n");
350 }
else if (0==strcmp(word,
"off")) {
352 printf(
"DCF77 receiver switched off\n");
356 }
else if (0==strcmp(word,
"time")) {
357 word = strtok(NULL,delimiter);
359 #if defined(EXTERNAL_RTC) && EXTERNAL_RTC
364 }
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') {
367 #if defined(EXTERNAL_RTC) && EXTERNAL_RTC
369 printf(
"setting hours failed\n");
371 printf(
"setting minutes failed\n");
373 printf(
"setting seconds failed\n");
377 printf(
"time set\n");
381 printf(
"time set\n");
384 #if defined(EXTERNAL_RTC) && EXTERNAL_RTC
385 }
else if (0==strcmp(word,
"date")) {
386 word = strtok(NULL,delimiter);
389 }
else if (strlen(word)!=10 || word[0]!=
'2' || word[1]!=
'0' || word[2]<
'0' || word[2]>
'9' || word[3]<
'0' || word[3]>
'9' || word[5]<
'0' || word[5]>
'1' || word[6]<
'0' || word[6]>
'9' || word[8]<
'0' || word[8]>
'3' || word[9]<
'0' || word[9]>
'9') {
393 printf(
"setting year failed\n");
395 printf(
"setting month failed\n");
397 printf(
"setting day failed\n");
399 printf(
"date set\n");
409 printf(
"command not recognized. enter help to list commands\n");
417 rcc_clock_setup_in_hse_8mhz_out_72mhz();
420 rcc_periph_clock_enable(LED_RCC);
421 gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, LED_PIN);
427 setbuf(stdout, NULL);
428 setbuf(stderr, NULL);
431 printf(
"welcome to the CuVoodoo LED clock\n");
434 #if defined(BUTTON_RCC) && defined(BUTTON_PORT) && defined(BUTTON_PIN) && defined(BUTTON_EXTI) && defined(BUTTON_IRQ)
435 rcc_periph_clock_enable(BUTTON_RCC);
436 gpio_set_mode(BUTTON_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, BUTTON_PIN);
437 gpio_clear(BUTTON_PORT, BUTTON_PIN);
438 rcc_periph_clock_enable(RCC_AFIO);
439 exti_select_source(BUTTON_EXTI, BUTTON_PORT);
440 exti_set_trigger(BUTTON_EXTI, EXTI_TRIGGER_RISING);
441 exti_enable_request(BUTTON_EXTI);
442 nvic_enable_irq(BUTTON_IRQ);
446 #if defined(EXTERNAL_RTC) && EXTERNAL_RTC
447 printf(
"setup external RTC: ");
450 printf(
"setup internal RTC: ");
452 rtc_interrupt_enable(RTC_SEC);
453 nvic_enable_irq(NVIC_RTC_IRQ);
458 printf(
"setup DCF77 receiver: ");
462 printf(
"DCF77 receiver switched on\n");
465 printf(
"setup LEDs: ");
476 printf(
"setup brightness sensor: ");
479 rcc_periph_clock_enable(RCC_ADC1);
482 adc_set_single_conversion_mode(ADC1);
483 adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_28DOT5CYC);
484 adc_enable_temperature_sensor(ADC1);
485 adc_enable_discontinuous_mode_regular(ADC1, 1);
486 adc_enable_external_trigger_regular(ADC1, ADC_CR2_EXTSEL_SWSTART);
488 for (uint32_t i=0; i<800000; i++) {
491 adc_reset_calibration(ADC1);
492 adc_calibration(ADC1);
494 uint8_t channels[] = {ADC_CHANNEL17};
495 adc_set_regular_sequence(ADC1,
LENGTH(channels), channels);
496 adc_start_conversion_regular(ADC1);
497 while (!adc_eoc(ADC1));
498 uint16_t ref_value = adc_read_regular(ADC1);
501 adc_set_regular_sequence(ADC1, 1, channels);
502 adc_enable_eoc_interrupt(ADC1);
503 nvic_enable_irq(NVIC_ADC1_2_IRQ);
507 #if defined(EXTERNAL_RTC) && EXTERNAL_RTC
509 printf(
"/!\\ RTC oscillator is disabled: the battery may be empty\n");
514 uint32_t ticks_time = 0;
515 #if defined(EXTERNAL_RTC) && EXTERNAL_RTC
519 printf(
"current date: 20%02u-%02u-%02u\n", rtc_ds1307_time[6], rtc_ds1307_time[5], rtc_ds1307_time[4]);
521 ticks_time = rtc_get_counter_val();
527 printf(
"command input: ready\n");
531 bool char_flag =
false;
549 if (c==
'\r' || c==
'\n') {
564 printf(
"time incremented by 1 second\n");
565 rtc_set_counter_val(rtc_get_counter_val()+ticks_second);
567 for (uint32_t i=0; i<1000000; i++) {
577 ticks_time = dcf77_time[1]*ticks_hour+dcf77_time[0]*
ticks_minute;
578 #if defined(EXTERNAL_RTC) && EXTERNAL_RTC
580 rtc_ds1307_write_time(0, dcf77_time[0], dcf77_time[1], ((dcf77_time[3]+1)%8)+1, dcf77_time[2], dcf77_time[4], dcf77_time[5]);
583 rtc_set_counter_val(ticks_time);
585 printf(
"DCF77 time: 20%02u-%02u-%02u %02u:%02u:00\n", dcf77_time[5], dcf77_time[4], dcf77_time[2], dcf77_time[1], dcf77_time[0]);
587 printf(
"DCF77 receiver switched off\n");
589 printf(
"DCF77 time: error\n");
592 #if defined(EXTERNAL_RTC) && EXTERNAL_RTC
599 ticks_time = rtc_get_counter_val();
602 if ((ticks_time%(ticks_second/10))==0) {
603 adc_start_conversion_regular(ADC1);
605 if ((ticks_time%ticks_second)==0) {
608 if ((ticks_time%ticks_minute)==0) {
609 printf(
"%02lu:%02lu:%02lu\n", ticks_time/ticks_hour, (ticks_time%ticks_hour)/ticks_minute, (ticks_time%ticks_minute)/ticks_second);
611 if ((ticks_time%ticks_hour)==0) {
614 printf(
"DCF77 receiver switched on\n");
617 #if defined(EXTERNAL_RTC) && EXTERNAL_RTC
620 rtc_set_counter_val(rtc_get_counter_val()%
ticks_midday);
629 float new_clock_brightness = 0;
650 #if defined(BUTTON_ISR) && defined(BUTTON_EXTI)
652 void BUTTON_ISR(
void)
654 exti_reset_request(BUTTON_EXTI);
666 #if defined(EXTERNAL_RTC) && EXTERNAL_RTC
671 rtc_clear_flag(RTC_SEC);
void led_ws2812b_setup(void)
setup WS2812B LED driver
float clock_brightness
factor to dim LED of the clock, depending on the ambient luminosity
bool rtc_ds1307_write_date(uint8_t date)
write date into RTC IC
static void clock_clear(void)
switch off all clock LEDs
const uint32_t ticks_second
number of ticks in one second
void rtc_ds1307_setup(void)
setup communication with RTC IC configure the I2C port defined in the sources
bool rtc_ds1307_write_time(uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t day, uint8_t date, uint8_t month, uint8_t year)
write time into RTC IC
bool led_ws2812b_transmit(void)
transmit color values to WS2812B LEDs
void cdcacm_putchar(char c)
send character over USB (non-blocking)
char command[32]
user input command
bool rtc_ds1307_write_year(uint8_t year)
write year into RTC IC
const uint32_t ticks_midday
number of ticks in one midday (12 hours)
void led_off(void)
switch off board LED
bool rtc_ds1307_oscillator_enable(void)
enable RTC IC oscillator
#define PHOTORESISTOR_ADC_CHANNEL
ADC channel.
bool rtc_ds1307_write_month(uint8_t month)
write month into RTC IC
bool rtc_ds1307_write_minutes(uint8_t minutes)
write minutes into RTC IC
static void clock_set_time(uint32_t time)
set the time on the LEDs
volatile bool rtc_ds1307_tick_flag
set on SQUARE_WAVE_TICS square wave ticks
volatile bool rtc_internal_tick_flag
flag set when internal RTC ticked
void rtc_dcf77_setup(void)
setup DCF77 time receiver module
static void process_command(char *str)
process user command
#define BRIGHTNESS_MIN
minimum LED brightness
char * b2s(uint64_t binary, uint8_t rjust)
get binary representation of a number
static void clock_show_time(uint32_t time)
show time on LED clock
static void clock_hours(void)
show animation with fading hours mark on clock LEDs
global definitions and methods
uint8_t clock_leds[LED_WS2812B_LEDS *3]
RGB values for the WS2812B clock LEDs.
volatile uint8_t usart_received
how many bytes available in the received buffer since last read
#define PHOTORESISTOR_MIN
photo-resistor voltage for the minimum brightness
void rtc_dcf77_off(void)
switch off DCF77 time receiver module
volatile uint16_t photoresistor_value
photo-resistor measurement of ambient luminosity
void cdcacm_setup(void)
setup USB CDC ACM peripheral
uint8_t rtc_ds1307_read_month(void)
read month from RTC IC
void adc1_2_isr(void)
interrupt service routine called when ADC conversion completed
void led_toggle(void)
toggle board LED
#define PHOTORESISTOR_PIN
pin of the port on which the battery is connected
uint8_t rtc_ds1307_read_year(void)
read year from RTC IC
uint8_t * rtc_ds1307_read_time(void)
read time from RTC IC
uint8_t rtc_ds1307_read_seconds(void)
read seconds from RTC IC
uint8_t gamma_correction_lut[256]
gamma correction lookup table (common for all colors)
volatile uint8_t cdcacm_received
how many bytes available in the received buffer since last read
static void clock_leds_set(void)
set the LEDs
uint8_t command_i
user input command index
bool rtc_ds1307_write_hours(uint8_t hours)
write hours into RTC IC
volatile bool rtc_dcf77_time_flag
set when time information has been received
void led_ws2812b_set_rgb(uint16_t led, uint8_t red, uint8_t green, uint8_t blue)
set color of a single LED
uint8_t rtc_ds1307_read_date(void)
read date from RTC IC
bool rtc_ds1307_write_seconds(uint8_t seconds)
write seconds into RTC IC
void rtc_isr(void)
interrupt service routine called when tick passed on RTC
void usart_putchar_nonblocking(char c)
send character over USART (non-blocking)
#define BRIGHTNESS_MAX
maximum LED brightness
library for USART communication (API)
volatile bool photoresistor_flag
flag set when ambient luminosity is measured
#define BRIGHTNESS_FACTOR
the factor to change the brightness
#define LED_WS2812B_LEDS
number of LEDs on the WS2812B strip
#define PHOTORESISTOR_MAX
photo-resistor voltage for the maximum brightness
char usart_getchar(void)
get character received over USART (blocking)
volatile uint32_t rtc_ds1307_ticks
increment on SQUARE_WAVE_TICS square wave ticks
library for USB CDC ACM communication (API)
uint8_t * rtc_dcf77_time(void)
get last received DCF77 time
volatile bool button_flag
flag set when board user button has been pressed/released
#define TICKS_PER_SECOND
the number of ticks in one second (32768 divisor greater than 256*LED_WS2812B_LEDS/60) ...
#define LENGTH(x)
get the length of an array
int _write(int file, char *ptr, int len)
default printf output
library to get time from a DCF77 module (API)
static void clock_animate_time(uint32_t time)
incrementally set the time on the LEDs
#define PHOTORESISTOR_PORT
port on which the battery is connected
bool rtc_ds1307_oscillator_disabled(void)
verify if oscillator is disabled
library to communicate with the Maxim DS1307 I2C RTC IC (API)
int main(void)
program entry point this is the firmware function started by the micro-controller ...
void usart_setup(void)
setup USART peripheral
uint8_t rtc_ds1307_read_hours(void)
read hours from RTC IC
#define PHOTORESISTOR_PORT_RCC
timer port peripheral clock
void rtc_dcf77_on(void)
switch on DCF77 time receiver module
library to drive a WS2812B LED chain (API)
char cdcacm_getchar(void)
get character received over USB (blocking)
const uint32_t ticks_hour
number of ticks in one hour
uint8_t rtc_ds1307_read_minutes(void)
read minutes from RTC IC
const uint32_t ticks_minute
number of ticks in one minute