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/timer.h>
38 #include <libopencm3/stm32/adc.h>
39 #include <libopencm3/stm32/rtc.h>
61 #define TICKS_PER_SECOND 256
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};
101 #define PHOTORESISTOR_MIN 2.7
103 #define PHOTORESISTOR_MAX 1.7
107 #define BRIGHTNESS_MIN 0.2
109 #define BRIGHTNESS_MAX 1.0
111 #define BRIGHTNESS_FACTOR 0.1
117 if (file == STDOUT_FILENO || file == STDERR_FILENO) {
118 for (i = 0; i < len; i++) {
119 if (ptr[i] ==
'\n') {
132 char*
b2s(uint32_t binary, uint8_t rjust)
134 static char string[32+1] = {0};
135 int16_t bit =
LENGTH(
string)-1;
147 while (32-bit-1<rjust && bit>=0) {
151 return &
string[bit+1];
178 if (led_hour>led_minute) {
183 if (led_hour>=0xff) {
191 for (uint16_t led=0; led<WS2812B_LEDS && led_minute>0; led++) {
193 if (led_minute>=0xff) {
205 if (led_minute>=0xff) {
214 for (uint16_t led=0; led<WS2812B_LEDS && led_hour>0; led++) {
217 if (led_hour>=0xff) {
230 uint8_t brightness_second = led_second%256;
233 clock_leds[second_led*3+0] = brightness_second;
237 second_led = ((second_led==0) ?
WS2812B_LEDS-1 : second_led-1);
238 clock_leds[second_led*3+0] = 0xff-brightness_second;
270 static uint32_t display_time = 0;
271 while (display_time<time) {
283 for (uint32_t i=0; i<400000; i++) {
293 for (uint16_t i=0; i<512; i++) {
294 uint8_t brightness = (i>255 ? 512-i-1 : i);
295 for (uint8_t hour=0; hour<12; hour++) {
304 for (uint32_t j=0; j<40000; j++) {
316 const char* delimiter =
" ";
317 char* word = strtok(str,delimiter);
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);
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') {
333 printf(
"time set\n");
341 puts(
"command not recognized. enter help to list commands");
349 rcc_clock_setup_in_hse_8mhz_out_72mhz();
352 setbuf(stdout, NULL);
353 setbuf(stderr, NULL);
356 rcc_periph_clock_enable(LED_RCC);
357 gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, LED_PIN);
361 #if defined(BUTTON_RCC) && defined(BUTTON_PORT) && defined(BUTTON_PIN) && defined(BUTTON_EXTI) && defined(BUTTON_IRQ)
362 rcc_periph_clock_enable(BUTTON_RCC);
363 gpio_set_mode(BUTTON_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, BUTTON_PIN);
364 rcc_periph_clock_enable(RCC_AFIO);
365 exti_select_source(BUTTON_EXTI, BUTTON_PORT);
366 exti_set_trigger(BUTTON_EXTI, EXTI_TRIGGER_BOTH);
367 exti_enable_request(BUTTON_EXTI);
368 nvic_enable_irq(BUTTON_IRQ);
373 rtc_interrupt_enable(RTC_SEC);
374 nvic_enable_irq(NVIC_RTC_IRQ);
392 rcc_periph_clock_enable(RCC_ADC1);
395 adc_set_single_conversion_mode(ADC1);
396 adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_28DOT5CYC);
397 adc_enable_temperature_sensor(ADC1);
398 adc_enable_discontinuous_mode_regular(ADC1, 1);
399 adc_enable_external_trigger_regular(ADC1, ADC_CR2_EXTSEL_SWSTART);
401 for (uint32_t i=0; i<800000; i++) {
404 adc_reset_calibration(ADC1);
405 adc_calibration(ADC1);
407 printf(
"welcome to the CuVoodoo LED clock\n");
412 adc_set_regular_sequence(ADC1,
LENGTH(channels), channels);
413 adc_start_conversion_regular(ADC1);
414 while (!adc_eoc(ADC1));
415 uint16_t ref_value = adc_read_regular(ADC1);
416 adc_start_conversion_regular(ADC1);
417 while (!adc_eoc(ADC1));
418 uint16_t battery_value = adc_read_regular(ADC1);
419 float battery_voltage = battery_value*1.2/ref_value;
420 if (battery_voltage<1.0) {
421 printf(
"no battery detected\n");
423 if (battery_voltage<2.4) {
425 for (uint16_t led=0; led<2; led++) {
428 }
else if (battery_voltage>3.0) {
433 for (uint16_t led=0; led<(uint8_t)(
WS2812B_LEDS*(battery_voltage-2.4)/0.6); led++) {
437 printf(
"battery voltage: %.2fV\n", battery_voltage);
440 for (uint32_t i=0; i<10000000; i++) {
447 adc_set_regular_sequence(ADC1, 1, channels);
448 adc_enable_eoc_interrupt(ADC1);
449 nvic_enable_irq(NVIC_ADC1_2_IRQ);
455 printf(
"input commands\n");
459 bool char_flag =
false;
483 }
else if (c!=
'\r') {
499 adc_start_conversion_regular(ADC1);
511 rtc_set_counter_val(rtc_get_counter_val()%
ticks_midday);
519 float new_clock_brightness = 0;
540 #if defined(BUTTON_ISR) && defined(BUTTON_EXTI)
542 void BUTTON_ISR(
void)
544 exti_reset_request(BUTTON_EXTI);
552 rtc_clear_flag(RTC_SEC);
char * b2s(uint32_t binary, uint8_t rjust)
get binary representation of a number
static void clock_clear(void)
switch off all clock LEDs
const uint32_t ticks_second
void ws2812b_setup(void)
setup WS2812b LED driver
void cdcacm_putchar(char c)
send character over USB (non-blocking)
const uint32_t ticks_midday
void led_off(void)
switch off board LED
#define PHOTORESISTOR_ADC_CHANNEL
static void clock_set_time(uint32_t time)
set the time on the LEDs
static void process_command(char *str)
process user command
#define BATTERY_ADC_CHANNEL
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
volatile uint8_t usart_received
#define PHOTORESISTOR_MIN
volatile uint16_t photoresistor_value
void led_on(void)
switch on board LED
void cdcacm_setup(void)
setup USB CDC ACM peripheral
void adc1_2_isr(void)
interrupt service routine called when ADC conversion completed
void led_toggle(void)
toggle board LED
#define PHOTORESISTOR_PIN
uint8_t gamma_correction_lut[256]
volatile uint8_t cdcacm_received
static void clock_leds_set(void)
set the LEDs
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)
library for USART communication (API)
volatile bool photoresistor_flag
bool ws2812b_transmit(void)
transmit color values to WS2812b LEDs
#define BRIGHTNESS_FACTOR
#define PHOTORESISTOR_MAX
char usart_getchar(void)
get character received over USART (blocking)
library for USB CDC ACM communication (API)
volatile bool button_flag
uint8_t clock_leds[WS2812B_LEDS *3]
int _write(int file, char *ptr, int len)
default printf output
static void clock_animate_time(uint32_t time)
incrementally set the time on the LEDs
#define PHOTORESISTOR_PORT
int main(void)
program entry point this is the firmware function started by the micro-controller ...
void usart_setup(void)
setup USART peripheral
#define PHOTORESISTOR_PORT_RCC
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
char cdcacm_getchar(void)
get character received over USB (blocking)
const uint32_t ticks_hour
const uint32_t ticks_minute