]> git.friedersdorff.com Git - max/tmk_keyboard.git/commitdiff
Add battery management
authortmk <nobody@nowhere>
Wed, 3 Sep 2014 20:30:00 +0000 (05:30 +0900)
committertmk <nobody@nowhere>
Wed, 3 Sep 2014 20:30:00 +0000 (05:30 +0900)
keyboard/hhkb_rn42/rn42.mk
keyboard/hhkb_rn42/rn42/battery.c [new file with mode: 0644]
keyboard/hhkb_rn42/rn42/battery.h [new file with mode: 0644]
keyboard/hhkb_rn42/rn42/rn42_task.c

index 653a8092426a6dce53e1b5c351e6f29689b5cf23..fd6f7db1a8e3a9ad455e8195591f7e34a18d8abe 100644 (file)
@@ -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 (file)
index 0000000..32de864
--- /dev/null
@@ -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 (file)
index 0000000..60fc8ad
--- /dev/null
@@ -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
index 2813b1c5ff4490c1666ae305cb74f98b4d6a36a1..07b34e111a4317f8b15382fb1f77cdc9d479f4ce 100644 (file)
@@ -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);