]> git.donarmstrong.com Git - tmk_firmware.git/blob - keyboard/hhkb_rn42/rn42/battery.c
Monitor battery and alert low voltage
[tmk_firmware.git] / keyboard / hhkb_rn42 / rn42 / battery.c
1 #include <avr/io.h>
2 #include <util/delay.h>
3 #include "battery.h"
4
5
6 /*
7  * Battery
8  */
9 void battery_init(void)
10 {
11     // blink 
12     battery_led(LED_ON);  _delay_ms(500);
13     battery_led(LED_OFF); _delay_ms(500);
14     battery_led(LED_ON);  _delay_ms(500);
15     battery_led(LED_OFF); _delay_ms(500);
16     // LED indicates charger status
17     battery_led(LED_CHARGER);
18
19     // ADC setting for voltage monitor
20     // Ref:2.56V band-gap, Input:ADC0(PF0), Prescale:128(16MHz/128=125KHz)
21     ADMUX = (1<<REFS1) | (1<<REFS0);
22     ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
23     ADCSRA |= (1<<ADEN);
24 }
25
26 // Indicator for battery
27 void battery_led(battery_led_t val)
28 {
29     if (val == LED_TOGGLE) {
30         // Toggle LED
31         DDRF  |=  (1<<5);
32         PINF  |=  (1<<5);
33     } else if (val == LED_ON) {
34         // On overriding charger status
35         DDRF  |=  (1<<5);
36         PORTF &= ~(1<<5);
37     } else if (val == LED_OFF) {
38         // Off overriding charger status
39         DDRF  |=  (1<<5);
40         PORTF |=  (1<<5);
41     } else {
42         // Display charger status
43         DDRF  &= ~(1<<5);
44         PORTF &= ~(1<<5);
45     }
46 }
47
48 bool battery_charging(void)
49 {
50     if (!(USBSTA&(1<<VBUS))) return false;
51
52     // Charger Status:
53     //   MCP73831   MCP73832   LTC4054  Status
54     //   Hi-Z       Hi-Z       Hi-Z     Shutdown/No Battery
55     //   Low        Low        Low      Charging
56     //   Hi         Hi-Z       Hi-Z     Charged
57
58     // preserve last register status
59     uint8_t ddrf_prev  = DDRF;
60     uint8_t portf_prev = PORTF;
61
62     // Input with pullup
63     DDRF  &= ~(1<<5);
64     PORTF |=  (1<<5);
65     _delay_ms(1);
66     bool charging = PINF&(1<<5) ? false : true;
67
68     // restore last register status
69     DDRF  = (DDRF&~(1<<5))  | (ddrf_prev&(1<<5));
70     PORTF = (PORTF&~(1<<5)) | (portf_prev&(1<<5));
71
72     // TODO: With MCP73831 this can not get stable status when charging.
73     // LED is powered from PSEL line(USB or Lipo)
74     // due to weak low output of STAT pin?
75     // due to pull-up'd via resitor and LED?
76     return charging;
77 }
78
79 // Returns voltage in mV
80 uint16_t battery_voltage(void)
81 {
82     volatile uint16_t bat;
83     //ADCSRA |= (1<<ADEN);
84
85     // discard first result
86     ADCSRA |= (1<<ADSC);
87     while (ADCSRA & (1<<ADSC)) ;
88     bat = ADC;
89
90     // discard second result
91     ADCSRA |= (1<<ADSC);
92     while (ADCSRA & (1<<ADSC)) ;
93     bat = ADC;
94
95     ADCSRA |= (1<<ADSC);
96     while (ADCSRA & (1<<ADSC)) ;
97     bat = ADC;
98
99     //ADCSRA &= ~(1<<ADEN);
100
101     return (bat - BATTERY_ADC_OFFSET) * BATTERY_ADC_RESOLUTION;
102 }
103
104 static bool low_voltage(void) {
105     static bool low = false;
106     uint16_t v = battery_voltage();
107     if (v < BATTERY_VOLTAGE_LOW_LIMIT) {
108         low = true;
109     } else if (v > BATTERY_VOLTAGE_LOW_RECOVERY) {
110         low = false;
111     }
112     return low;
113 }
114
115 battery_status_t battery_status(void)
116 {
117     if (USBSTA&(1<<VBUS)) {
118         /* powered */
119         return battery_charging() ? CHARGING : FULL_CHARGED;
120     } else {
121         /* not powered */
122         return low_voltage() ? LOW_VOLTAGE : DISCHARGING;
123     }
124 }