Compare commits

...

1 Commits

Author SHA1 Message Date
Olaf Rempel cd560f4268 tiny24 version 2008-03-25 19:41:51 +01:00
2 changed files with 89 additions and 257 deletions

View File

@ -1,6 +1,6 @@
PRG = lipo-charger
OBJ = lipo-charger.o
MCU_TARGET = atmega8
MCU_TARGET = attiny24
OPTIMIZE = -Os
DEFS =
@ -47,5 +47,5 @@ bin: $(PRG).bin
$(OBJCOPY) -j .text -j .data -O binary $< $@
install: text
uisp -dprog=avr910 -dserial=/dev/ttyS0 -dspeed=115200 -dpart=M8 --erase --upload if=$(PRG).hex
# avrdude -p m8 -c butterfly -b 19200 -P /dev/ttyUSB0 -u -e -U flash:w:$(PRG).hex
# uisp -dprog=avr910 -dserial=/dev/ttyS0 -dspeed=115200 -dpart=M8 --erase --upload if=$(PRG).hex
avrdude -p t24 -c butterfly -b 115200 -P /dev/ttyUSB0 -u -e -U flash:w:$(PRG).hex

View File

@ -22,37 +22,21 @@
#define F_CPU 8000000
#include <util/delay.h>
#include <stdio.h>
#define ADC_REF PORTA0
#define ADC_U PORTA1
#define ADC_IM PORTA2
#define ADC_IP PORTA3
#define SUMMER PORTA7
#define BAUDRATE 19200
#define UART_CALC_BAUDRATE(baudRate) ((uint32_t)(F_CPU) / ((uint32_t)(baudRate)*16) -1)
#define LEDRT PORTB0
#define LEDGN PORTB1
#define PWM PORTB2
/*
* LCD:
* - CS Chip Select
* - RS Register Select
* - RW Read/Write
*/
#define RS PORTB6
#define CS PORTB7
#define RW PORTD3
#define LCD_D4 PORTD4
#define LCD_D5 PORTD5
#define LCD_D6 PORTD6
#define LCD_D7 PORTD7
#define LCD_DATA_MASK ((1<<LCD_D4) | (1<<LCD_D5) | (1<<LCD_D6) | (1<<LCD_D7))
/* ADC_U vs GND: voltage with prescaler (12V -> 2V; 15mV -> 2.5mV/bit), ref 2.56V */
#define CH_U ((1<<REFS0) | 0x01)
/*
* power supply:
* - CH0 - voltage with prescaler (12V -> 2V; 15mV -> 2.5mV/bit)
* - CH1 - current with (1A -> 1000mV; 2.5mA -> 2.5mV/bit)
* - PWM - high-active output to buckconverter
*/
#define CH0 PORTC0
#define CH1 PORTC1
#define PWM PORTB1
#define NOP asm volatile ("nop")
/* ADC_IP vs ADC_IM: current sense (1A -> 100mV; ??mA -> ?mV/bit), gain x20, ref 5V */
#define CH_I ((0<<REFS0) | 0x31)
#define MOD_WAITING 0x00
#define MOD_CHARGING 0x01
@ -60,173 +44,37 @@
#define VOLTAGE_CONNECT 9000
#define VOLTAGE_CHARGE 12450
#define CURRENT_CHARGE 16000
#define CURRENT_CHARGE 17500
#define CURRENT_READY 2000
#define VOLTAGE_REMOVE 1000
static void lcd_wait_busy(void)
{
uint8_t status;
DDRD &= ~(LCD_DATA_MASK);
PORTD |= (1<<RW);
do {
PORTB |= (1<<CS);
NOP;
NOP;
status = (PIND & LCD_DATA_MASK);
PORTB &= ~(1<<CS);
PORTB |= (1<<CS);
NOP;
NOP;
status |= ((PIND & LCD_DATA_MASK) >> 4);
PORTB &= ~(1<<CS);
} while (status & 0x80);
DDRD |= LCD_DATA_MASK;
PORTD &= ~(1<<RW);
}
static void lcd_write_ctrl(uint8_t val)
{
PORTD &= ~(LCD_DATA_MASK);
PORTD |= (val & 0xF0);
PORTB |= (1<<CS);
NOP;
NOP;
PORTB &= ~(1<<CS);
PORTD &= ~(LCD_DATA_MASK);
PORTD |= ((val<<4) & 0xF0);
PORTB |= (1<<CS);
NOP;
NOP;
PORTB &= ~(1<<CS);
lcd_wait_busy();
}
static void lcd_write_data(uint8_t val)
{
PORTD &= ~(LCD_DATA_MASK);
PORTD |= (val & 0xF0);
PORTB |= (1<<RS);
PORTB |= (1<<CS);
NOP;
NOP;
PORTB &= ~(1<<CS);
PORTD &= ~(LCD_DATA_MASK);
PORTD |= ((val<<4) & 0xF0);
PORTB |= (1<<CS);
NOP;
NOP;
PORTB &= ~(1<<CS);
PORTB &= ~(1<<RS);
lcd_wait_busy();
}
/* heartbeat chars */
static const uint8_t mychars[] = {
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00,
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00,
};
static void lcd_init(void)
{
_delay_ms(25);
lcd_wait_busy();
/* 4bit, 2lines, 5x7 font */
lcd_write_ctrl(0x28);
/* display on, cursor off, blink off */
lcd_write_ctrl(0x0C);
/* cursor increments */
lcd_write_ctrl(0x06);
lcd_write_ctrl(0x40 | 0x00);
uint8_t i;
for (i = 0; i < sizeof(mychars); i++)
lcd_write_data(mychars[i]);
/* clear & home pos */
lcd_write_ctrl(0x01);
}
static int uart_putchar(char c, FILE *stream)
{
if (c == '\n')
uart_putchar('\r', stream);
loop_until_bit_is_set(UCSRA, UDRE);
UDR = c;
return 0;
}
static int lcd_putchar(char c, FILE *stream)
{
lcd_write_data(c);
return 0;
}
static FILE lcd = FDEV_SETUP_STREAM(lcd_putchar, NULL, _FDEV_SETUP_WRITE);
static FILE log = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
static uint16_t voltage;
static uint16_t current;
ISR(ADC_vect)
{
if (ADMUX & 0x01) {
if (ADMUX == CH_I) {
current = ADCW * 25;
ADMUX = CH0;
ADMUX = CH_U;
} else {
voltage = ADCW * 15;
ADMUX = CH1;
ADMUX = CH_I;
}
}
ISR(TIM1_OVF_vect)
{
/* Come back in 1ms */
TCNT1 = 0xFFFF - 8000;
/* start ADC again */
ADCSRA |= (1<<ADSC);
}
static uint8_t lcd_update;
static uint8_t mode = MOD_WAITING;
static uint8_t pwm;
static uint8_t pwm;
static uint8_t mode = MOD_WAITING;
ISR(TIMER0_OVF_vect)
{
static uint8_t cnt;
/* Come back in 1ms */
TCNT0 = 0xFF - 125;
/* update LCD every 250ms */
cnt++;
if (cnt == 250) {
cnt = 0;
lcd_update = 1;
}
/*
* charge with constant voltage of 12.45V
* and a current limit of 1.6A
*/
/* charge with constant voltage and current limit */
if (mode == MOD_CHARGING) {
if (voltage < (VOLTAGE_CHARGE -25) && current < (CURRENT_CHARGE -500))
if (pwm < 0xff)
@ -236,27 +84,71 @@ ISR(TIMER0_OVF_vect)
if (pwm > 0x00)
pwm--;
OCR1A = pwm;
TCCR1A |= (1<<COM1A1);
OCR0A = pwm;
TCCR0A |= (1<<COM1A1);
} else {
pwm = 0;
TCCR1A &= ~(1<<COM1A1);
TCCR0A &= ~(1<<COM1A1);
}
static uint16_t led_timer;
led_timer = (led_timer +1) & 0x3FF;
switch (mode) {
case MOD_WAITING:
/* green flashing, red off */
if (led_timer < 0x3F)
PORTB &= ~(1<<LEDGN);
else
PORTB |= (1<<LEDGN) | (1<<LEDRT);
PORTA |= (1<<SUMMER);
/* start charging when a voltage > 9V is detected (lipo connected) */
if (voltage > VOLTAGE_CONNECT)
mode = MOD_CHARGING;
break;
case MOD_CHARGING:
/* current limit */
if (voltage < (VOLTAGE_CHARGE -50)) {
/* green on, red fast blinking */
if (led_timer & 0x80)
PORTB &= ~((1<<LEDGN) | (1<<LEDRT));
else
PORTB |= (1<<LEDRT);
/* voltage limit */
} else {
/* green on, red slow blinking */
if (led_timer & 0x200)
PORTB &= ~((1<<LEDGN) | (1<<LEDRT));
else
PORTB |= (1<<LEDRT);
}
PORTA |= (1<<SUMMER);
/* end charging if voltage > 12.45V and current < 200mA */
if (voltage >= VOLTAGE_CHARGE && current < CURRENT_READY)
mode = MOD_READY;
break;
case MOD_READY:
/* green on, red flashing */
if (led_timer < 0x3F)
PORTB &= ~((1<<LEDGN) | (1<<LEDRT));
else
PORTB |= (1<<LEDRT);
/* beeping */
if (led_timer < 0x07)
PORTA &= ~(1<<SUMMER);
else
PORTA |= (1<<SUMMER);
/* wait for lipo disconnect */
if (voltage < VOLTAGE_REMOVE)
mode = MOD_WAITING;
@ -266,89 +158,29 @@ ISR(TIMER0_OVF_vect)
int main(void)
{
DDRB = (1<<CS) | (1<<RS) | (1<<PWM);
DDRD = (LCD_DATA_MASK) | (1<<RW);
/* digital outputs */
DDRA = (1<<SUMMER);
DDRB = (1<<LEDGN) | (1<<LEDRT) | (1<<PWM);
/* Set baud rate 19200 */
UBRRH = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF;
UBRRL = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF);
/* analog inputs */
DIDR0 = (1<<ADC_REF) | (1<<ADC_U) | (1<<ADC_IM) | (1<<ADC_IP);
/* USART: rx/tx enable, 19200, 8n1 */
UCSRB = (1<<TXEN) | (1<<RXEN);
UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
/* timer0: running with F_CPU, 8bit Fast PWM (32khz) */
TCCR0A = (1<<WGM00) | (1<<WGM01);
TCCR0B = (1<<CS00);
/* timer0: running with F_CPU/64 (125kHz) */
TCCR0 = (1<<CS01) | (1<<CS00);
/* timer1: running with F_CPU */
TCCR1B = (1<<CS00);
/* timer1: running with F_CPU, 8bit Phase Correct PWM (16kHz) */
TCCR1A = (1<<WGM10);
TCCR1B = (1<<CS10) | (1<<WGM12);
/* enable Timer0 OVF Interrupt */
TIMSK = (1<<TOIE0);
/* external 2.56V reference, channel 0 */
ADMUX = CH0;
/* enable iimer1 OVF Interrupt */
TIMSK1 = (1<<TOIE1);
/* enable ADC with interrupts, 125kHz clk */
ADMUX = CH_I;
ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1);
sei();
lcd_init();
uint8_t step = 0;
uint8_t hours = 0, minutes = 0, seconds = 0;
while (1) {
if (lcd_update) {
/* first line, first char */
lcd_write_ctrl(0x80 | 0x00);
fprintf(&lcd, "%2d.%03dV ", voltage / 1000, voltage % 1000);
fprintf(&lcd, "%1d.%04dA ", current / 10000, current % 10000);
fprintf(&lcd, "0x%02x", pwm);
step = (step +1) & 0x03;
if (step == 0 && mode == MOD_CHARGING) {
seconds++;
if (seconds == 60) {
seconds = 0;
minutes++;
if (minutes == 60) {
minutes = 0;
hours++;
}
}
fprintf(&log, "%02d:%02d:%02d %05d %05d %03d\n",
hours, minutes, seconds, voltage, current, pwm);
}
/* second line, first char */
lcd_write_ctrl(0x80 | 0x40);
fprintf(&lcd, "%02d:%02d:%02d ", hours, minutes, seconds);
switch (mode) {
case MOD_WAITING:
fprintf(&lcd, " waiting ");
hours = minutes = seconds = 0;
break;
case MOD_CHARGING:
fprintf(&lcd, " charging");
break;
case MOD_READY:
fprintf(&lcd, " ready ");
break;
}
/* second line, last char */
lcd_write_ctrl(0x80 | 0x40 | 19);
lcd_write_data(step);
lcd_update = 0;
}
}
while (1);
return 0;
}