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.2KB

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