|
|
|
#include "twi.h"
|
|
|
|
#include "ssd1306.h"
|
|
|
|
#include "sevenseg.h"
|
|
|
|
#include "adc.h"
|
|
|
|
#include "iopins.h"
|
|
|
|
#include <avr/interrupt.h>
|
|
|
|
|
|
|
|
const uint16_t adc_target16_acceptable = 900;
|
|
|
|
const uint16_t adc_target16 = 972;
|
|
|
|
//const uint8_t adc_target8 = 243;
|
|
|
|
|
|
|
|
static bool g_pwm_on = false;
|
|
|
|
|
|
|
|
static volatile uint16_t tick_counter = 0;
|
|
|
|
static volatile bool tick_counter_changed = false;
|
|
|
|
|
|
|
|
// Tick
|
|
|
|
ISR(INT0_vect)
|
|
|
|
{
|
|
|
|
tick_counter++;
|
|
|
|
tick_counter_changed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void init_isr() {
|
|
|
|
as_input(D2);
|
|
|
|
|
|
|
|
// using INT0 - arduino pin D2
|
|
|
|
EICRA = _BV(ISC01) | _BV(ISC00); // rising edge
|
|
|
|
EIMSK = _BV(INT0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void init_pwm_out() {
|
|
|
|
// Output is OC0A
|
|
|
|
as_output(D5);
|
|
|
|
|
|
|
|
// initialize the timer
|
|
|
|
// Fast PWM mode, Output to OC0A
|
|
|
|
|
|
|
|
// clock is 16MHz, presc /64, counting to 80 -> freq 3125Hz
|
|
|
|
// Duty cycle = appx. 60%
|
|
|
|
|
|
|
|
OCR0A = 80;
|
|
|
|
OCR0B = 46;
|
|
|
|
TCCR0A = _BV(WGM00) | _BV(WGM01);
|
|
|
|
TCCR0B = _BV(CS01) | _BV(CS00) | _BV(WGM02);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pwm_on() {
|
|
|
|
TCCR0A |= _BV(COM0B1);
|
|
|
|
g_pwm_on = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pwm_off() {
|
|
|
|
TCCR0A &= ~_BV(COM0B1);
|
|
|
|
g_pwm_on = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
TWI_Init();
|
|
|
|
adc_init();
|
|
|
|
|
|
|
|
init_pwm_out();
|
|
|
|
|
|
|
|
ssd1306_128x32_i2c_init();
|
|
|
|
ssd1306_clearScreen();
|
|
|
|
|
|
|
|
struct SevenSeg sseg = {
|
|
|
|
.x0 = 0,
|
|
|
|
.y0 = 0,
|
|
|
|
.charwidth = 17,
|
|
|
|
.thick = 3,
|
|
|
|
//.charwidth = 16,
|
|
|
|
//.thick = 1,
|
|
|
|
.spacing = 4,
|
|
|
|
};
|
|
|
|
|
|
|
|
init_isr();
|
|
|
|
sei();
|
|
|
|
|
|
|
|
// TODO show loading icon
|
|
|
|
sseg_number(&sseg, 0, 5, 0);
|
|
|
|
|
|
|
|
// request ADC meas
|
|
|
|
adc_async_start_measure_word(0);
|
|
|
|
|
|
|
|
// uint16_t cnt = 0;
|
|
|
|
uint16_t analog;
|
|
|
|
uint16_t count_boost_fail = 0;
|
|
|
|
for (;;) {
|
|
|
|
if (adc_async_ready()) {
|
|
|
|
analog = adc_async_get_result_word();
|
|
|
|
adc_async_start_measure_word(0);
|
|
|
|
|
|
|
|
bool good_voltage = analog >= adc_target16;
|
|
|
|
|
|
|
|
if (g_pwm_on) {
|
|
|
|
if (good_voltage) {
|
|
|
|
pwm_off();
|
|
|
|
count_boost_fail = 0;
|
|
|
|
} else {
|
|
|
|
count_boost_fail++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!good_voltage) {
|
|
|
|
pwm_on();
|
|
|
|
}
|
|
|
|
|
|
|
|
// If fail to reach target voltage in reasonable time,
|
|
|
|
// show weak battery icon and stop trying.
|
|
|
|
if (count_boost_fail > 50000 && analog < adc_target16_acceptable) {
|
|
|
|
// TODO weak battery icon
|
|
|
|
sseg_number(&sseg, 9999, 5, 0);
|
|
|
|
pwm_off();
|
|
|
|
|
|
|
|
for(;;) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO synchronization?
|
|
|
|
if (tick_counter_changed) {
|
|
|
|
tick_counter_changed = false;
|
|
|
|
sseg_number(&sseg, tick_counter, 5, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// if (++cnt > 10000) {
|
|
|
|
// sseg_number(&sseg, analog, 5, 0);
|
|
|
|
// cnt = 0;
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|