]> git.donarmstrong.com Git - tmk_firmware.git/blob - keyboard/hhkb_rn42/rn42/battery.c
Add FET swtich for battery ADC
[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     // ADC disable voltate divider(PF4)
26     DDRF  |=  (1<<4);
27     PORTF &= ~(1<<4);
28 }
29
30 // Indicator for battery
31 void battery_led(battery_led_t val)
32 {
33     if (val == LED_TOGGLE) {
34         // Toggle LED
35         DDRF  |=  (1<<5);
36         PINF  |=  (1<<5);
37     } else if (val == LED_ON) {
38         // On overriding charger status
39         DDRF  |=  (1<<5);
40         PORTF &= ~(1<<5);
41     } else if (val == LED_OFF) {
42         // Off overriding charger status
43         DDRF  |=  (1<<5);
44         PORTF |=  (1<<5);
45     } else {
46         // Display charger status
47         DDRF  &= ~(1<<5);
48         PORTF &= ~(1<<5);
49     }
50 }
51
52 bool battery_charging(void)
53 {
54     if (!(USBSTA&(1<<VBUS))) return false;
55
56     // Charger Status:
57     //   MCP73831   MCP73832   LTC4054  Status
58     //   Hi-Z       Hi-Z       Hi-Z     Shutdown/No Battery
59     //   Low        Low        Low      Charging
60     //   Hi         Hi-Z       Hi-Z     Charged
61
62     // preserve last register status
63     uint8_t ddrf_prev  = DDRF;
64     uint8_t portf_prev = PORTF;
65
66     // Input with pullup
67     DDRF  &= ~(1<<5);
68     PORTF |=  (1<<5);
69     _delay_ms(1);
70     bool charging = PINF&(1<<5) ? false : true;
71
72     // restore last register status
73     DDRF  = (DDRF&~(1<<5))  | (ddrf_prev&(1<<5));
74     PORTF = (PORTF&~(1<<5)) | (portf_prev&(1<<5));
75
76     // TODO: With MCP73831 this can not get stable status when charging.
77     // LED is powered from PSEL line(USB or Lipo)
78     // due to weak low output of STAT pin?
79     // due to pull-up'd via resitor and LED?
80     return charging;
81 }
82
83 // Returns voltage in mV
84 uint16_t battery_voltage(void)
85 {
86     // ADC disable voltate divider(PF4)
87     DDRF  |=  (1<<4);
88     PORTF |=  (1<<4);
89
90     volatile uint16_t bat;
91     //ADCSRA |= (1<<ADEN);
92
93     // discard first result
94     ADCSRA |= (1<<ADSC);
95     while (ADCSRA & (1<<ADSC)) ;
96     bat = ADC;
97
98     // discard second result
99     ADCSRA |= (1<<ADSC);
100     while (ADCSRA & (1<<ADSC)) ;
101     bat = ADC;
102
103     ADCSRA |= (1<<ADSC);
104     while (ADCSRA & (1<<ADSC)) ;
105     bat = ADC;
106
107     //ADCSRA &= ~(1<<ADEN);
108
109     // ADC disable voltate divider(PF4)
110     DDRF  |=  (1<<4);
111     PORTF &= ~(1<<4);
112
113     return (bat - BATTERY_ADC_OFFSET) * BATTERY_ADC_RESOLUTION;
114 }
115
116 static bool low_voltage(void) {
117     static bool low = false;
118     uint16_t v = battery_voltage();
119     if (v < BATTERY_VOLTAGE_LOW_LIMIT) {
120         low = true;
121     } else if (v > BATTERY_VOLTAGE_LOW_RECOVERY) {
122         low = false;
123     }
124     return low;
125 }
126
127 battery_status_t battery_status(void)
128 {
129     if (USBSTA&(1<<VBUS)) {
130         /* powered */
131         return battery_charging() ? CHARGING : FULL_CHARGED;
132     } else {
133         /* not powered */
134         return low_voltage() ? LOW_VOLTAGE : DISCHARGING;
135     }
136 }