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

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