diff --git a/main.c b/main.c index f8abe79..c29aad7 100644 --- a/main.c +++ b/main.c @@ -38,6 +38,7 @@ #include // interrupt utilities #include // external interrupt utilities #include // timer utilities +#include // ADC utilities /* own libraries */ #include "global.h" // board definitions @@ -85,6 +86,17 @@ const uint32_t ticks_midday = 12*60*60*TICKS_PER_SECOND; #define SQUARE_WAVE_GPIO_PIN GPIO_TIM2_CH1_ETR /**< timer pin input, connect to RTC IC square wave output (TIM2_CH1 on PA0) */ /** @} */ +/** @defgroup battery_adc ADC used to measure battery voltage + * @{ + */ +#define BATTERY_ADC ADC1 /**< ADC used to measure battery voltage */ +#define BATTERY_ADC_RCC RCC_ADC1 /**< ADC clock peripheral */ +#define BATTERY_ADC_CHANNEL ADC_CHANNEL1 /**< ADC channel */ +#define BATTERY_PORT GPIOA /**< port on which the battery is connected */ +#define BATTERY_PORT_RCC RCC_GPIOA /**< timer port peripheral clock */ +#define BATTERY_PIN GPIO1 /**< pin of the port on which the battery is connected */ +/** @} */ + /** RGB values for the WS2812b clock LEDs */ uint8_t clock_leds[WS2812B_LEDS*3] = {0}; /** current time in tick */ @@ -423,6 +435,23 @@ int main(void) nvic_enable_irq(SQUARE_WAVE_TIMER_IRQ); // allow interrupt for timer timer_enable_counter(SQUARE_WAVE_TIMER); // enable timer to count ticks + // setup ADC to ready battery voltage (single conversion of a regular channel without interrupt) + rcc_periph_clock_enable(BATTERY_PORT_RCC); // enable clock for GPIO peripheral + gpio_set_mode(BATTERY_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG, BATTERY_PIN); // set GPIO as analogue input for the ADC + rcc_periph_clock_enable(BATTERY_ADC_RCC); // enable clock for ADC peripheral + adc_off(BATTERY_ADC); // switch off ADC while configuring it + // configuration is correct per default + adc_set_single_conversion_mode(BATTERY_ADC); // we just want one measurement + adc_set_sample_time(BATTERY_ADC, BATTERY_ADC_CHANNEL, ADC_SMPR_SMP_28DOT5CYC); // use 28.5 cycles to sample (long enough to be stable) + adc_enable_temperature_sensor(BATTERY_ADC); // enable internal voltage reference + adc_set_sample_time(BATTERY_ADC, ADC_CHANNEL17, ADC_SMPR_SMP_28DOT5CYC); // use 28.5 cycles to sample internal voltage reference + adc_power_on(BATTERY_ADC); // switch on ADC + for (uint32_t i = 0; i < 800000; i++) { // wait t_stab for the ADC to stabilize + __asm__("nop"); + } + adc_reset_calibration(BATTERY_ADC); // remove previous non-calibration + adc_calibration(BATTERY_ADC); // calibrate ADC for less accuracy errors + printf("welcome to the CuVoodoo LED clock\n"); // print welcome message led_on(); // switch on LED to indicate setup completed @@ -431,6 +460,24 @@ int main(void) printf("/!\\ RTC oscillator is disabled\n"); } + // read internal reference 1.2V voltage + uint8_t channels[] = {ADC_CHANNEL17}; // voltages to convert + adc_set_regular_sequence(BATTERY_ADC, LENGTH(channels), channels); // set channels to convert + adc_start_conversion_direct(BATTERY_ADC); // start conversion to get voltages + while (!adc_eoc(BATTERY_ADC)); // wait until conversion finished + uint16_t ref_value = adc_read_regular(BATTERY_ADC); // read internal reference 1.2V voltage value + // check RTC battery voltage + channels[0] = BATTERY_ADC_CHANNEL; // voltage to convert + adc_set_regular_sequence(BATTERY_ADC, LENGTH(channels), channels); // set channels to convert + adc_start_conversion_direct(BATTERY_ADC); // start conversion to get voltages + while (!adc_eoc(BATTERY_ADC)); // wait until conversion finished + uint16_t battery_value = adc_read_regular(BATTERY_ADC); // read converted battery voltage + float battery_voltage = battery_value*1.2/ref_value; // calculate battery voltage + if (battery_voltage<2.4) { + printf("/!\\ low "); + } + printf("battery voltage: %.2fV\n", battery_voltage); + // get date and time uint16_t* rtc_time = rtc_read_time(); // get RTC time/date current_time = rtc_time[2]*ticks_hour+rtc_time[1]*ticks_minute+rtc_time[0]*ticks_second; // the current time