aboutsummaryrefslogtreecommitdiff
path: root/keyboards/hhkb/rn42/battery.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyboards/hhkb/rn42/battery.c')
-rw-r--r--keyboards/hhkb/rn42/battery.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/keyboards/hhkb/rn42/battery.c b/keyboards/hhkb/rn42/battery.c
new file mode 100644
index 000000000..c0c82bb80
--- /dev/null
+++ b/keyboards/hhkb/rn42/battery.c
@@ -0,0 +1,130 @@
1#include <avr/io.h>
2#include <util/delay.h>
3#include "battery.h"
4
5
6/*
7 * Battery
8 */
9void battery_init(void)
10{
11 // blink
12 battery_led(LED_ON); _delay_ms(100);
13 battery_led(LED_OFF); _delay_ms(100);
14 battery_led(LED_ON); _delay_ms(100);
15 battery_led(LED_OFF); _delay_ms(100);
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
34void 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
55bool 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
87uint16_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 _delay_ms(1); // wait for charging S/H capacitance
96
97 ADCSRA |= (1<<ADSC);
98 while (ADCSRA & (1<<ADSC)) ;
99 bat = ADC;
100
101 ADCSRA &= ~(1<<ADEN);
102
103 // ADC disable voltate divider(PF4)
104 DDRF |= (1<<4);
105 PORTF &= ~(1<<4);
106
107 return (bat - BATTERY_ADC_OFFSET) * BATTERY_ADC_RESOLUTION;
108}
109
110static bool low_voltage(void) {
111 static bool low = false;
112 uint16_t v = battery_voltage();
113 if (v < BATTERY_VOLTAGE_LOW_LIMIT) {
114 low = true;
115 } else if (v > BATTERY_VOLTAGE_LOW_RECOVERY) {
116 low = false;
117 }
118 return low;
119}
120
121battery_status_t battery_status(void)
122{
123 if (USBSTA&(1<<VBUS)) {
124 /* powered */
125 return battery_charging() ? CHARGING : FULL_CHARGED;
126 } else {
127 /* not powered */
128 return low_voltage() ? LOW_VOLTAGE : DISCHARGING;
129 }
130}