diff options
-rw-r--r-- | keyboard/hhkb_rn42/rn42.mk | 1 | ||||
-rw-r--r-- | keyboard/hhkb_rn42/rn42/battery.c | 119 | ||||
-rw-r--r-- | keyboard/hhkb_rn42/rn42/battery.h | 34 | ||||
-rw-r--r-- | keyboard/hhkb_rn42/rn42/rn42_task.c | 71 |
4 files changed, 165 insertions, 60 deletions
diff --git a/keyboard/hhkb_rn42/rn42.mk b/keyboard/hhkb_rn42/rn42.mk index 653a809242..fd6f7db1a8 100644 --- a/keyboard/hhkb_rn42/rn42.mk +++ b/keyboard/hhkb_rn42/rn42.mk @@ -4,6 +4,7 @@ SRC += serial_uart.c \ rn42/suart.S \ rn42/rn42.c \ rn42/rn42_task.c \ + rn42/battery.c \ rn42/main.c OPT_DEFS += -DPROTOCOL_RN42 diff --git a/keyboard/hhkb_rn42/rn42/battery.c b/keyboard/hhkb_rn42/rn42/battery.c new file mode 100644 index 0000000000..32de864481 --- /dev/null +++ b/keyboard/hhkb_rn42/rn42/battery.c @@ -0,0 +1,119 @@ +#include <avr/io.h> +#include <util/delay.h> +#include "battery.h" + + +/* + * Battery + */ +void battery_init(void) +{ + // blink + battery_led(LED_ON); _delay_ms(500); + battery_led(LED_OFF); _delay_ms(500); + battery_led(LED_ON); _delay_ms(500); + battery_led(LED_OFF); _delay_ms(500); + // LED indicates charger status + battery_led(LED_CHARGER); + + // ADC setting for voltage monitor + // Ref:2.56V band-gap, Input:ADC0(PF0), Prescale:128(16MHz/128=125KHz) + ADMUX = (1<<REFS1) | (1<<REFS0); + ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); + ADCSRA |= (1<<ADEN); +} + +// Indicator for battery +void battery_led(battery_led_t val) +{ + if (val == LED_TOGGLE) { + // Toggle LED + DDRF |= (1<<5); + PINF |= (1<<5); + } else if (val == LED_ON) { + // On overriding charger status + DDRF |= (1<<5); + PORTF &= ~(1<<5); + } else if (val == LED_OFF) { + // Off overriding charger status + DDRF |= (1<<5); + PORTF |= (1<<5); + } else { + // Display charger status + DDRF &= ~(1<<5); + PORTF &= ~(1<<5); + } +} + +bool battery_charging(void) +{ + if (!(USBSTA&(1<<VBUS))) return false; + + // MCP73831:STAT + // HiZ: Shutdown/No Battery + // Low: Charging + // Hi: Charged + + // preserve last register status + uint8_t ddrf_prev = DDRF; + uint8_t portf_prev = PORTF; + + // Input with pullup + DDRF &= ~(1<<5); + PORTF |= (1<<5); + _delay_ms(1); + bool charging = PINF&(1<<5) ? false : true; + + // restore last register status + DDRF = (DDRF&~(1<<5)) | (ddrf_prev&(1<<5)); + PORTF = (PORTF&~(1<<5)) | (portf_prev&(1<<5)); + + return charging; +} + +// Returns voltage in mV +uint16_t battery_voltage(void) +{ + volatile uint16_t bat; + //ADCSRA |= (1<<ADEN); + + // discard first result + ADCSRA |= (1<<ADSC); + while (ADCSRA & (1<<ADSC)) ; + bat = ADC; + + // discard second result + ADCSRA |= (1<<ADSC); + while (ADCSRA & (1<<ADSC)) ; + bat = ADC; + + ADCSRA |= (1<<ADSC); + while (ADCSRA & (1<<ADSC)) ; + bat = ADC; + + //ADCSRA &= ~(1<<ADEN); + + return (bat - BATTERY_ADC_OFFSET) * BATTERY_ADC_RESOLUTION; +} + +static bool low_voltage(void) { + static bool low = false; + uint16_t v = battery_voltage(); + if (v < BATTERY_VOLTAGE_LOW_LIMIT) { + low = true; + } else if (v > BATTERY_VOLTAGE_LOW_RECOVERY) { + low = false; + } + return low; +} + +battery_status_t battery_status(void) +{ + if (USBSTA&(1<<VBUS)) { + /* powered */ + return battery_charging() ? CHARGING : FULL_CHARGED; + } else { + /* not powered */ + return low_voltage() ? LOW_VOLTAGE : DISCHARGING; + } +} diff --git a/keyboard/hhkb_rn42/rn42/battery.h b/keyboard/hhkb_rn42/rn42/battery.h new file mode 100644 index 0000000000..60fc8adfcb --- /dev/null +++ b/keyboard/hhkb_rn42/rn42/battery.h @@ -0,0 +1,34 @@ +#ifndef POWER_H +#define POWER_H + +#include <stdint.h> +#include <stdbool.h> + +typedef enum { + FULL_CHARGED, + CHARGING, + DISCHARGING, + LOW_VOLTAGE, +} battery_status_t; + +typedef enum { + LED_CHARGER = 0, + LED_ON, + LED_OFF, + LED_TOGGLE, +} battery_led_t; + +/* Battery API */ +void battery_init(void); +void battery_led(battery_led_t val); +bool battery_charging(void); +uint16_t battery_voltage(void); +battery_status_t battery_status(void); + +#define BATTERY_VOLTAGE_LOW_LIMIT 3500 +#define BATTERY_VOLTAGE_LOW_RECOVERY 3700 +// ADC offset:16, resolution:5mV +#define BATTERY_ADC_OFFSET 16 +#define BATTERY_ADC_RESOLUTION 5 + +#endif diff --git a/keyboard/hhkb_rn42/rn42/rn42_task.c b/keyboard/hhkb_rn42/rn42/rn42_task.c index 2813b1c5ff..07b34e111a 100644 --- a/keyboard/hhkb_rn42/rn42/rn42_task.c +++ b/keyboard/hhkb_rn42/rn42/rn42_task.c @@ -9,6 +9,7 @@ #include "print.h" #include "timer.h" #include "command.h" +#include "battery.h" static bool config_mode = false; static bool force_usb = false; @@ -24,65 +25,9 @@ static void status_led(bool on) } } -static void battery_adc_init(void) -{ - ADMUX = (1<<REFS1) | (1<<REFS0); // Ref:2.56V band-gap, Input:ADC0(PF0) - ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // Prescale:128 16MHz/128=125KHz - ADCSRA |= (1<<ADEN); // enable ADC -} - -static uint16_t battery_adc(void) -{ - volatile uint16_t bat; - ADCSRA |= (1<<ADEN); - - // discard first result - ADCSRA |= (1<<ADSC); - while (ADCSRA & (1<<ADSC)) ; - bat = ADC; - - // discard second result - ADCSRA |= (1<<ADSC); - while (ADCSRA & (1<<ADSC)) ; - bat = ADC; - - ADCSRA |= (1<<ADSC); - while (ADCSRA & (1<<ADSC)) ; - bat = ADC; - - ADCSRA &= ~(1<<ADEN); - return bat; -} - -static void battery_led(bool on) -{ - if (on) { - DDRF |= (1<<5); - PORTF &= ~(1<<5); // Low - } else { - DDRF &= ~(1<<5); - PORTF &= ~(1<<5); // HiZ - } -} - -static bool battery_charging(void) -{ - // MCP73831:STAT - // Hi-Z: Shutdown/No Battery - // Low: Charging - // Hi: Charged - DDRF &= ~(1<<5); - PORTF |= (1<<5); - return PINF&(1<<5) ? false : true; -} - void rn42_task_init(void) { - battery_adc_init(); - - // battery charging(HiZ) - DDRF &= ~(1<<5); - PORTF &= ~(1<<5); + battery_init(); } void rn42_task(void) @@ -136,7 +81,12 @@ void rn42_task(void) } } - /* Battery monitor */ + /* Low voltage alert */ + if (battery_status() == LOW_VOLTAGE) { + battery_led(LED_ON); + } else { + battery_led(LED_CHARGER); + } /* Connection monitor */ if (rn42_linked()) { @@ -214,12 +164,13 @@ bool command_extra(uint8_t code) xprintf("config_mode: %X\n", config_mode); xprintf("VBUS: %X\n", USBSTA&(1<<VBUS)); xprintf("battery_charging: %X\n", battery_charging()); + xprintf("battery_status: %X\n", battery_status()); return true; case KC_B: // battery monitor t = timer_read32()/1000; - b = battery_adc(); - xprintf("BAT: %umV(%04X)\t", (b-16)*5, b); + b = battery_voltage(); + xprintf("BAT: %umV\t", b); xprintf("%02u:", t/3600); xprintf("%02u:", t%3600/60); xprintf("%02u\n", t%60); |