Add FET swtich for battery ADC
[tmk_keyboard.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 }
Imprint / Impressum