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