Keyboard firmwares for Atmel AVR and Cortex-M
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

battery.c 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. #include <avr/io.h>
  2. #include <util/delay.h>
  3. #include "battery.h"
  4. /*
  5. * Battery
  6. */
  7. void battery_init(void)
  8. {
  9. // blink
  10. battery_led(LED_ON); _delay_ms(500);
  11. battery_led(LED_OFF); _delay_ms(500);
  12. battery_led(LED_ON); _delay_ms(500);
  13. battery_led(LED_OFF); _delay_ms(500);
  14. // LED indicates charger status
  15. battery_led(LED_CHARGER);
  16. // ADC setting for voltage monitor
  17. // Ref:2.56V band-gap, Input:ADC0(PF0), Prescale:128(16MHz/128=125KHz)
  18. ADMUX = (1<<REFS1) | (1<<REFS0);
  19. ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
  20. ADCSRA |= (1<<ADEN);
  21. }
  22. // Indicator for battery
  23. void battery_led(battery_led_t val)
  24. {
  25. if (val == LED_TOGGLE) {
  26. // Toggle LED
  27. DDRF |= (1<<5);
  28. PINF |= (1<<5);
  29. } else if (val == LED_ON) {
  30. // On overriding charger status
  31. DDRF |= (1<<5);
  32. PORTF &= ~(1<<5);
  33. } else if (val == LED_OFF) {
  34. // Off overriding charger status
  35. DDRF |= (1<<5);
  36. PORTF |= (1<<5);
  37. } else {
  38. // Display charger status
  39. DDRF &= ~(1<<5);
  40. PORTF &= ~(1<<5);
  41. }
  42. }
  43. bool battery_charging(void)
  44. {
  45. if (!(USBSTA&(1<<VBUS))) return false;
  46. // Charger Status:
  47. // MCP73831 MCP73832 LTC4054 Status
  48. // Hi-Z Hi-Z Hi-Z Shutdown/No Battery
  49. // Low Low Low Charging
  50. // Hi Hi-Z Hi-Z Charged
  51. // preserve last register status
  52. uint8_t ddrf_prev = DDRF;
  53. uint8_t portf_prev = PORTF;
  54. // Input with pullup
  55. DDRF &= ~(1<<5);
  56. PORTF |= (1<<5);
  57. _delay_ms(1);
  58. bool charging = PINF&(1<<5) ? false : true;
  59. // restore last register status
  60. DDRF = (DDRF&~(1<<5)) | (ddrf_prev&(1<<5));
  61. PORTF = (PORTF&~(1<<5)) | (portf_prev&(1<<5));
  62. // TODO: With MCP73831 this can not get stable status when charging.
  63. // LED is powered from PSEL line(USB or Lipo)
  64. // due to weak low output of STAT pin?
  65. // due to pull-up'd via resitor and LED?
  66. return charging;
  67. }
  68. // Returns voltage in mV
  69. uint16_t battery_voltage(void)
  70. {
  71. volatile uint16_t bat;
  72. //ADCSRA |= (1<<ADEN);
  73. // discard first result
  74. ADCSRA |= (1<<ADSC);
  75. while (ADCSRA & (1<<ADSC)) ;
  76. bat = ADC;
  77. // discard second result
  78. ADCSRA |= (1<<ADSC);
  79. while (ADCSRA & (1<<ADSC)) ;
  80. bat = ADC;
  81. ADCSRA |= (1<<ADSC);
  82. while (ADCSRA & (1<<ADSC)) ;
  83. bat = ADC;
  84. //ADCSRA &= ~(1<<ADEN);
  85. return (bat - BATTERY_ADC_OFFSET) * BATTERY_ADC_RESOLUTION;
  86. }
  87. static bool low_voltage(void) {
  88. static bool low = false;
  89. uint16_t v = battery_voltage();
  90. if (v < BATTERY_VOLTAGE_LOW_LIMIT) {
  91. low = true;
  92. } else if (v > BATTERY_VOLTAGE_LOW_RECOVERY) {
  93. low = false;
  94. }
  95. return low;
  96. }
  97. battery_status_t battery_status(void)
  98. {
  99. if (USBSTA&(1<<VBUS)) {
  100. /* powered */
  101. return battery_charging() ? CHARGING : FULL_CHARGED;
  102. } else {
  103. /* not powered */
  104. return low_voltage() ? LOW_VOLTAGE : DISCHARGING;
  105. }
  106. }