diff options
Diffstat (limited to 'keyboards/hhkb/rn42/battery.c')
| -rw-r--r-- | keyboards/hhkb/rn42/battery.c | 130 |
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 | */ | ||
| 9 | void 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 | ||
| 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 | _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 | |||
| 110 | static 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 | |||
| 121 | battery_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 | } | ||
