initial commit

This commit is contained in:
Olaf Rempel 2007-10-03 01:07:05 +02:00
commit 18cb2f29c7
3 changed files with 411 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
*.o
*.elf
*.bin
*.hex
*.lst
*.map

51
Makefile Normal file
View File

@ -0,0 +1,51 @@
PRG = lipo-charger
OBJ = lipo-charger.o
MCU_TARGET = atmega8
OPTIMIZE = -Os
DEFS =
LIBS =
# You should not have to change anything below here.
CC = avr-gcc
# Override is only needed by avr-lib build system.
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS)
override LDFLAGS = -Wl,-Map,$(PRG).map
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size
all: $(PRG).elf lst text
$(SIZE) -x -A $(PRG).elf
$(PRG).elf: $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
clean:
rm -rf *.o *.lst *.map $(PRG).elf *.hex *.bin
lst: $(PRG).lst
%.lst: %.elf
$(OBJDUMP) -h -S $< > $@
# Rules for building the .text rom images
text: hex bin
hex: $(PRG).hex
bin: $(PRG).bin
%.hex: %.elf
$(OBJCOPY) -j .text -j .data -O ihex $< $@
%.bin: %.elf
$(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

354
lipo-charger.c Normal file
View File

@ -0,0 +1,354 @@
/***************************************************************************
* Copyright (C) 09/2007 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; version 2 of the License, *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 8000000
#include <util/delay.h>
#include <stdio.h>
#define BAUDRATE 19200
#define UART_CALC_BAUDRATE(baudRate) ((uint32_t)(F_CPU) / ((uint32_t)(baudRate)*16) -1)
/*
* 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))
/*
* power supply:
* - CH0 - voltage with 10:1 prescaler
* - CH1 - current with 10mA -> 1mA
* - PWM - high-active output to buckconverter
*/
#define CH0 PORTC0
#define CH1 PORTC1
#define PWM PORTB1
#define NOP asm volatile ("nop")
#define MOD_WAITING 0x00
#define MOD_CHARGING 0x01
#define MOD_READY 0x02
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) {
current = ADCW * 25;
ADMUX = CH0;
} else {
voltage = ADCW * 15;
ADMUX = CH1;
}
ADCSRA |= (1<<ADSC);
}
static uint8_t lcd_update;
static uint8_t mode = MOD_WAITING;
static uint8_t pwm;
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.6V
*/
if (mode == MOD_CHARGING) {
if (voltage < 12425 && current < 15500)
if (pwm < 0xff)
pwm++;
if (voltage > 12450 || current > 16000)
if (pwm > 0x00)
pwm--;
} else {
pwm = 0;
}
if (pwm > 0) {
OCR1A = pwm;
TCCR1A |= (1<<COM1A1);
} else {
TCCR1A &= ~(1<<COM1A1);
}
switch (mode) {
case MOD_WAITING:
/*
* start charging when a voltage > 9V is detected (lipo connected)
*/
if (voltage > 9000)
mode = MOD_CHARGING;
break;
case MOD_CHARGING:
/*
* end charging if voltage > 12.42V and current < 200mA
*/
if (voltage > 12425 && current < 2000)
mode = MOD_READY;
break;
case MOD_READY:
/* wait for lipo disconnect */
if (voltage < 1000)
mode = MOD_WAITING;
break;
}
}
int main(void)
{
DDRB = (1<<CS) | (1<<RS) | (1<<PWM);
DDRD = (LCD_DATA_MASK) | (1<<RW);
/* Set baud rate 19200 */
UBRRH = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF;
UBRRL = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF);
/* USART: rx/tx enable, 19200, 8n1 */
UCSRB = (1<<TXEN) | (1<<RXEN);
UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
/* timer0: running with F_CPU/64 (125kHz) */
TCCR0 = (1<<CS01) | (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 ADC with interrupts, 125kHz clk */
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;
}
}
return 0;
}