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.
		
		
		
		
		
			
		
			
				
					131 lines
				
				3.2 KiB
			
		
		
			
		
	
	
					131 lines
				
				3.2 KiB
			|   
											11 years ago
										 | #include <avr/io.h>
 | ||
|  | #include <util/delay.h>
 | ||
|  | #include "battery.h"
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * Battery | ||
|  |  */ | ||
|  | void battery_init(void) | ||
|  | { | ||
|  |     // blink 
 | ||
|  |     battery_led(LED_ON);  _delay_ms(500); | ||
|  |     battery_led(LED_OFF); _delay_ms(500); | ||
|  |     battery_led(LED_ON);  _delay_ms(500); | ||
|  |     battery_led(LED_OFF); _delay_ms(500); | ||
|  |     // LED indicates charger status
 | ||
|  |     battery_led(LED_CHARGER); | ||
|  | 
 | ||
|  |     // ADC setting for voltage monitor
 | ||
|  |     // Ref:2.56V band-gap, Input:ADC0(PF0), Prescale:128(16MHz/128=125KHz)
 | ||
|  |     ADMUX = (1<<REFS1) | (1<<REFS0); | ||
|  |     ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); | ||
|   
											11 years ago
										 |     // digital input buffer disable(24.9.5)
 | ||
|   
											11 years ago
										 |     DIDR0 = (1<<ADC0D) | (1<<ADC4D) | (1<<ADC7D); | ||
|   
											11 years ago
										 |     DIDR1 = (1<<AIN0D); | ||
|  |     DIDR2 = (1<<ADC8D) | (1<<ADC9D) | (1<<ADC11D) | (1<<ADC12D) | (1<<ADC13D); | ||
|   
											11 years ago
										 | 
 | ||
|  |     // ADC disable voltate divider(PF4)
 | ||
|  |     DDRF  |=  (1<<4); | ||
|  |     PORTF &= ~(1<<4); | ||
|   
											11 years ago
										 | } | ||
|  | 
 | ||
|  | // Indicator for battery
 | ||
|  | void battery_led(battery_led_t val) | ||
|  | { | ||
|  |     if (val == LED_TOGGLE) { | ||
|  |         // Toggle LED
 | ||
|  |         DDRF  |=  (1<<5); | ||
|  |         PINF  |=  (1<<5); | ||
|  |     } else if (val == LED_ON) { | ||
|  |         // On overriding charger status
 | ||
|  |         DDRF  |=  (1<<5); | ||
|  |         PORTF &= ~(1<<5); | ||
|  |     } else if (val == LED_OFF) { | ||
|  |         // Off overriding charger status
 | ||
|  |         DDRF  |=  (1<<5); | ||
|  |         PORTF |=  (1<<5); | ||
|  |     } else { | ||
|  |         // Display charger status
 | ||
|  |         DDRF  &= ~(1<<5); | ||
|  |         PORTF &= ~(1<<5); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | bool battery_charging(void) | ||
|  | { | ||
|  |     if (!(USBSTA&(1<<VBUS))) return false; | ||
|  | 
 | ||
|   
											11 years ago
										 |     // Charger Status:
 | ||
|  |     //   MCP73831   MCP73832   LTC4054  Status
 | ||
|  |     //   Hi-Z       Hi-Z       Hi-Z     Shutdown/No Battery
 | ||
|  |     //   Low        Low        Low      Charging
 | ||
|  |     //   Hi         Hi-Z       Hi-Z     Charged
 | ||
|   
											11 years ago
										 | 
 | ||
|  |     // preserve last register status
 | ||
|  |     uint8_t ddrf_prev  = DDRF; | ||
|  |     uint8_t portf_prev = PORTF; | ||
|  | 
 | ||
|  |     // Input with pullup
 | ||
|  |     DDRF  &= ~(1<<5); | ||
|  |     PORTF |=  (1<<5); | ||
|  |     _delay_ms(1); | ||
|  |     bool charging = PINF&(1<<5) ? false : true; | ||
|  | 
 | ||
|  |     // restore last register status
 | ||
|  |     DDRF  = (DDRF&~(1<<5))  | (ddrf_prev&(1<<5)); | ||
|  |     PORTF = (PORTF&~(1<<5)) | (portf_prev&(1<<5)); | ||
|  | 
 | ||
|   
											11 years ago
										 |     // TODO: With MCP73831 this can not get stable status when charging.
 | ||
|  |     // LED is powered from PSEL line(USB or Lipo)
 | ||
|  |     // due to weak low output of STAT pin?
 | ||
|  |     // due to pull-up'd via resitor and LED?
 | ||
|   
											11 years ago
										 |     return charging; | ||
|  | } | ||
|  | 
 | ||
|  | // Returns voltage in mV
 | ||
|  | uint16_t battery_voltage(void) | ||
|  | { | ||
|   
											11 years ago
										 |     // ADC disable voltate divider(PF4)
 | ||
|  |     DDRF  |=  (1<<4); | ||
|  |     PORTF |=  (1<<4); | ||
|  | 
 | ||
|   
											11 years ago
										 |     volatile uint16_t bat; | ||
|   
											11 years ago
										 |     ADCSRA |= (1<<ADEN); | ||
|   
											11 years ago
										 |     _delay_ms(1);   // wait for charging S/H capacitance
 | ||
|   
											11 years ago
										 | 
 | ||
|  |     ADCSRA |= (1<<ADSC); | ||
|  |     while (ADCSRA & (1<<ADSC)) ; | ||
|  |     bat = ADC; | ||
|  | 
 | ||
|   
											11 years ago
										 |     ADCSRA &= ~(1<<ADEN); | ||
|   
											11 years ago
										 | 
 | ||
|   
											11 years ago
										 |     // ADC disable voltate divider(PF4)
 | ||
|  |     DDRF  |=  (1<<4); | ||
|  |     PORTF &= ~(1<<4); | ||
|  | 
 | ||
|   
											11 years ago
										 |     return (bat - BATTERY_ADC_OFFSET) * BATTERY_ADC_RESOLUTION; | ||
|  | } | ||
|  | 
 | ||
|  | static bool low_voltage(void) { | ||
|  |     static bool low = false; | ||
|  |     uint16_t v = battery_voltage(); | ||
|  |     if (v < BATTERY_VOLTAGE_LOW_LIMIT) { | ||
|  |         low = true; | ||
|  |     } else if (v > BATTERY_VOLTAGE_LOW_RECOVERY) { | ||
|  |         low = false; | ||
|  |     } | ||
|  |     return low; | ||
|  | } | ||
|  | 
 | ||
|  | battery_status_t battery_status(void) | ||
|  | { | ||
|  |     if (USBSTA&(1<<VBUS)) { | ||
|  |         /* powered */ | ||
|  |         return battery_charging() ? CHARGING : FULL_CHARGED; | ||
|  |     } else { | ||
|  |         /* not powered */ | ||
|  |         return low_voltage() ? LOW_VOLTAGE : DISCHARGING; | ||
|  |     } | ||
|  | } |