From 89173ec9cd6f33843bf27c45be0f2f9be3f5f0ce Mon Sep 17 00:00:00 2001 From: Kevin Rosenberg Date: Mon, 7 Apr 2008 11:02:56 -0600 Subject: [PATCH] 4008-04-07 Release 2008-04-07 Kevin Rosenberg * BaseTinyFirmware/IAR: Port Martin's changes from 2008-04-03 to IAR 2008-04-03 Martin Thomas * BaseMegaFirmware/GCC: Experimental Master Code for the ATmega644 with basic "drivers" for - keys incl. power-off with debounceing - 74HC595 low-level "software-SPI" - LEDs though 74HC595 - Power-off and Slave-Reset control though 74HC595 - hardware SPI for comm. with slave - simple test-function for communication with slave * BaseTinyFirmware/GCC/statefunc.c: - prevent unneeded writes to eeprom if init fails - prevent slave from entering sleep-mode standby if "MASTER_INT" is low (so SPI communication with master is possible even during the "8-second watchdog delay") --- BaseMegaFirmware/GCC/bc100_master.aps | 1 + BaseMegaFirmware/GCC/bc100_master.aws | 1 + BaseMegaFirmware/GCC/bc100_slave.c | 105 +++++ BaseMegaFirmware/GCC/bc100_slave.h | 23 + BaseMegaFirmware/GCC/default/Makefile | 96 +++++ BaseMegaFirmware/GCC/key_io.c | 76 ++++ BaseMegaFirmware/GCC/key_io.h | 101 +++++ BaseMegaFirmware/GCC/main.c | 250 +++++++++++ BaseMegaFirmware/GCC/mystdio.c | 22 + BaseMegaFirmware/GCC/mystdio.h | 13 + BaseMegaFirmware/GCC/port_ext.c | 126 ++++++ BaseMegaFirmware/GCC/port_ext.h | 32 ++ BaseMegaFirmware/GCC/spi.c | 43 ++ BaseMegaFirmware/GCC/spi.h | 25 ++ BaseMegaFirmware/GCC/timebase.c | 87 ++++ BaseMegaFirmware/GCC/timebase.h | 11 + BaseMegaFirmware/GCC/uart.c | 585 ++++++++++++++++++++++++++ BaseMegaFirmware/GCC/uart.h | 178 ++++++++ BaseTinyFirmware/GCC/ChangeLog | 32 -- BaseTinyFirmware/GCC/PWM.c | 42 +- BaseTinyFirmware/GCC/avr458/Makefile | 4 +- BaseTinyFirmware/GCC/statefunc.c | 101 +++-- BaseTinyFirmware/GCC/structs.h | 2 +- BaseTinyFirmware/IAR/statefunc.c | 108 +++-- ChangeLog | 52 +++ 25 files changed, 1991 insertions(+), 125 deletions(-) create mode 100644 BaseMegaFirmware/GCC/bc100_master.aps create mode 100644 BaseMegaFirmware/GCC/bc100_master.aws create mode 100644 BaseMegaFirmware/GCC/bc100_slave.c create mode 100644 BaseMegaFirmware/GCC/bc100_slave.h create mode 100644 BaseMegaFirmware/GCC/default/Makefile create mode 100644 BaseMegaFirmware/GCC/key_io.c create mode 100644 BaseMegaFirmware/GCC/key_io.h create mode 100644 BaseMegaFirmware/GCC/main.c create mode 100644 BaseMegaFirmware/GCC/mystdio.c create mode 100644 BaseMegaFirmware/GCC/mystdio.h create mode 100644 BaseMegaFirmware/GCC/port_ext.c create mode 100644 BaseMegaFirmware/GCC/port_ext.h create mode 100644 BaseMegaFirmware/GCC/spi.c create mode 100644 BaseMegaFirmware/GCC/spi.h create mode 100644 BaseMegaFirmware/GCC/timebase.c create mode 100644 BaseMegaFirmware/GCC/timebase.h create mode 100644 BaseMegaFirmware/GCC/uart.c create mode 100644 BaseMegaFirmware/GCC/uart.h delete mode 100644 BaseTinyFirmware/GCC/ChangeLog create mode 100644 ChangeLog diff --git a/BaseMegaFirmware/GCC/bc100_master.aps b/BaseMegaFirmware/GCC/bc100_master.aps new file mode 100644 index 0000000..da05a21 --- /dev/null +++ b/BaseMegaFirmware/GCC/bc100_master.aps @@ -0,0 +1 @@ +bc100_master28-Mar-2008 10:14:1002-Apr-2008 16:36:02241028-Mar-2008 10:14:1044, 13, 0, 557AVR GCCdefault\bc100_master.elfD:\EigenMT\develop\uProz\bc100\bcc100_gcc\BaseMegaFirmware\GCC\JTAGICE mkIIATmega644.xmlfalseR00R01R02R03R04R05R06R07R08R09R10R11R12R13R14R15R16R17R18R19R20R21R22R23R24R25R26R27R28R29R30R31Auto000uart.cmain.cmystdio.cspi.cbc100_slave.cport_ext.ctimebase.ckey_io.cuart.hmystdio.hspi.hbc100_slave.hD:\EigenMT\develop\uProz\bc100\bcc100_gcc\BaseTinyFirmware\GCC\enums.hD:\EigenMT\develop\uProz\bc100\bcc100_gcc\BaseTinyFirmware\GCC\structs.hport_ext.htimebase.hkey_io.hdefault\bc100_master.lssdefault\bc100_master.mapdefaultNOatmega644111bc100_master.elfdefault\1-Wall -gdwarf-2 -std=gnu99 -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums-Wl,-u,vfprintf -lprintf_flt -Wl,-u,vfscanf -lscanf_flt -lmdefault1C:\WinAVR\bin\avr-gcc.exeC:\WinAVR\utils\bin\make.exe diff --git a/BaseMegaFirmware/GCC/bc100_master.aws b/BaseMegaFirmware/GCC/bc100_master.aws new file mode 100644 index 0000000..93a72f1 --- /dev/null +++ b/BaseMegaFirmware/GCC/bc100_master.aws @@ -0,0 +1 @@ + diff --git a/BaseMegaFirmware/GCC/bc100_slave.c b/BaseMegaFirmware/GCC/bc100_slave.c new file mode 100644 index 0000000..a03a334 --- /dev/null +++ b/BaseMegaFirmware/GCC/bc100_slave.c @@ -0,0 +1,105 @@ +// Martin Thomas 3/2008 + +#include +#include +#include + +#include "../../BaseTinyFirmware/GCC/enums.h" +#include "../../BaseTinyFirmware/GCC/structs.h" + +#include "spi.h" +#include "bc100_slave.h" + +#ifdef BC100_SLAVE_TEST +#include "mystdio.h" +#endif + +#define dummy 0x00 + +void bc100_slave_init( void ) +{ +} + +uint8_t bc100_slave_read( uint8_t cmd, size_t size, void *buf ) +{ + uint8_t err = 0; + + return err; +} + +#ifdef BC100_SLAVE_TEST + +uint8_t bc100_slave_test(void) +{ + uint8_t err = 0; + uint8_t in, out, i; + uint32_t timevals[TIMERS]; + + SPI_init(); + + SPI_rw( dummy ); + myprintf_P("Timers:\n"); + out = BC100_SLAVE_READ | BC100_SLAVE_SRAM | sizeof(timevals); + SPI_rw( out ); + out = ADR_TIMERS; + in = SPI_rw( out ); + myprintf_P("In1 : 0x%02x (expected 0xcc)\n", in ); + in = SPI_rw( dummy ); + myprintf_P("In2 : 0x%02x (expected 0xbb)\n", in ); +#if 0 + uint8_t tmp + for ( i = TIMERS; i > 0; i-- ) { + tmp = (uint32_t)(SPI_rw(dummy)) << 24; + tmp |= (uint32_t)(SPI_rw(dummy)) << 16; + tmp |= (uint32_t)(SPI_rw(dummy)) << 8; + tmp |= (uint32_t)(SPI_rw(dummy)) << 0; + timevals[i-1] = tmp; + } +#else + i = sizeof(timevals); + while ( i-- > 0 ) { + *( (unsigned char*)&timevals + i ) = SPI_rw(dummy); + } +#endif + for ( i=0; i 0 ) { + *( (unsigned char*)&ADCS + i ) = SPI_rw(dummy); + } + myprintf_P("ADC-MUX %d\n", ADCS.MUX ); + myprintf_P("Cycle complete %d\n", ADCS.Flag); + myprintf_P("Mains OK %d\n", ADCS.Mains); + myprintf_P("A/D halt %d\n", ADCS.Halt); + myprintf_P("Offs ADC3 g20 %d\n", ADCS.ADC3_G20_OS); + myprintf_P("Offs ADC5 g20 %d\n", ADCS.ADC5_G20_OS); + myprintf_P("rawRID %d\n", ADCS.rawRID); + myprintf_P("rawNTC %d\n", ADCS.rawNTC); + myprintf_P("rawVBAT %d\n", ADCS.rawVBAT); + myprintf_P("Supply %d [mV]\n", ADCS.VIN); + myprintf_P("Batt. Voltage %d [mV]\n", ADCS.VBAT); + myprintf_P("Batt. Current %d [mA]\n", ADCS.IBAT); + for ( i=0; i<4; i++ ) { + myprintf_P("DiscIBAT[%d] %d [mA]\n", i, ADCS.discIBAT[i] ); + } + myprintf_P("average IBAT %d [mA]\n", ADCS.avgIBAT); + + SPI_release(); + + return err; +} + +#endif /* BC100_SLAVE_TEST */ + diff --git a/BaseMegaFirmware/GCC/bc100_slave.h b/BaseMegaFirmware/GCC/bc100_slave.h new file mode 100644 index 0000000..63450b7 --- /dev/null +++ b/BaseMegaFirmware/GCC/bc100_slave.h @@ -0,0 +1,23 @@ +// Martin Thomas 3/2008 +#ifndef BC100_SLAVE_H +#define BC100_SLAVE_H + +#define BC100_SLAVE_TEST + +#include +#include + +#define BC100_SLAVE_READ 0x00 +#define BC100_SLAVE_WRITE 0x40 +#define BC100_SLAVE_EEPROM 0x80 +#define BC100_SLAVE_SRAM 0x00 + + +void bc100_slave_init( void ); +uint8_t bc100_slave_read( uint8_t cmd, size_t size, void *buf ); + +#ifdef BC100_SLAVE_TEST +uint8_t bc100_slave_test(void); +#endif + +#endif diff --git a/BaseMegaFirmware/GCC/default/Makefile b/BaseMegaFirmware/GCC/default/Makefile new file mode 100644 index 0000000..f1333e5 --- /dev/null +++ b/BaseMegaFirmware/GCC/default/Makefile @@ -0,0 +1,96 @@ +############################################################################### +# Makefile for the project bc100_master +############################################################################### + +## General Flags +PROJECT = bc100_master +MCU = atmega644 +TARGET = bc100_master.elf +CC = avr-gcc.exe + +## Options common to compile, link and assembly rules +COMMON = -mmcu=$(MCU) + +## Compile options common for all C compilation units. +CFLAGS = $(COMMON) +CFLAGS += -Wall -gdwarf-2 -std=gnu99 -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d + +## Assembly specific flags +ASMFLAGS = $(COMMON) +ASMFLAGS += $(CFLAGS) +ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2 + +## Linker flags +LDFLAGS = $(COMMON) +LDFLAGS += -Wl,-u,vfprintf -lprintf_flt -Wl,-u,vfscanf -lscanf_flt -lm -Wl,-Map=bc100_master.map + + +## Intel Hex file production flags +HEX_FLASH_FLAGS = -R .eeprom + +HEX_EEPROM_FLAGS = -j .eeprom +HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load" +HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings + + +## Objects that must be built in order to link +OBJECTS = uart.o main.o mystdio.o spi.o bc100_slave.o port_ext.o timebase.o key_io.o + +## Objects explicitly added by the user +LINKONLYOBJECTS = + +## Build +all: $(TARGET) bc100_master.hex bc100_master.eep bc100_master.lss size + +## Compile +uart.o: ../uart.c + $(CC) $(INCLUDES) $(CFLAGS) -c $< + +main.o: ../main.c + $(CC) $(INCLUDES) $(CFLAGS) -c $< + +mystdio.o: ../mystdio.c + $(CC) $(INCLUDES) $(CFLAGS) -c $< + +spi.o: ../spi.c + $(CC) $(INCLUDES) $(CFLAGS) -c $< + +bc100_slave.o: ../bc100_slave.c + $(CC) $(INCLUDES) $(CFLAGS) -c $< + +port_ext.o: ../port_ext.c + $(CC) $(INCLUDES) $(CFLAGS) -c $< + +timebase.o: ../timebase.c + $(CC) $(INCLUDES) $(CFLAGS) -c $< + +key_io.o: ../key_io.c + $(CC) $(INCLUDES) $(CFLAGS) -c $< + +##Link +$(TARGET): $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) $(LINKONLYOBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET) + +%.hex: $(TARGET) + avr-objcopy -O ihex $(HEX_FLASH_FLAGS) $< $@ + +%.eep: $(TARGET) + -avr-objcopy $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0 + +%.lss: $(TARGET) + avr-objdump -h -S $< > $@ + +size: ${TARGET} + @echo + @avr-size -C --mcu=${MCU} ${TARGET} + +## Clean target +.PHONY: clean +clean: + -rm -rf $(OBJECTS) bc100_master.elf dep/* bc100_master.hex bc100_master.eep bc100_master.lss bc100_master.map + + +## Other dependencies +-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*) + diff --git a/BaseMegaFirmware/GCC/key_io.c b/BaseMegaFirmware/GCC/key_io.c new file mode 100644 index 0000000..3c8eaa7 --- /dev/null +++ b/BaseMegaFirmware/GCC/key_io.c @@ -0,0 +1,76 @@ +// M. Thomas 11/2007 + +#include +#include +#include "key_io.h" + +/* define externs */ +// debounced and inverted key state, bit = 1: key pressed +volatile uint8_t key_io_state; +// key press detect +volatile uint8_t key_io_press; +// key long press and repeat +volatile uint8_t key_io_rpt; + +void key_io_init(void) +{ + KEY_IO_KEYSA_DDR &= ~( + (1< no init here + key_io_state = key_io_state_hardware(); +} + +uint8_t key_io_get_press( uint8_t key_mask ) +{ + uint8_t sreg; + + sreg = SREG; + cli(); + + key_mask &= key_io_press; // read key(s) + key_io_press ^= key_mask; // clear key(s) + + SREG = sreg; + + return key_mask; +} + +uint8_t key_io_get_rpt( uint8_t key_mask ) +{ + uint8_t sreg; + + sreg = SREG; + cli(); + + key_mask &= key_io_rpt; // read key(s) + key_io_rpt ^= key_mask; // clear key(s) + + SREG = sreg; + + return key_mask; +} + +uint8_t key_io_get_was_short( uint8_t key_mask ) +{ + uint8_t sreg, ret; + + sreg=SREG; + // read key state and key press atomic ! + cli(); + + ret = key_io_get_press( ~key_io_state & key_mask ); + + SREG = sreg; + + return ret; + +} + +uint8_t key_io_get_longpress( uint8_t key_mask ) +{ + return key_io_get_press( key_io_get_rpt( key_mask )); +} + + diff --git a/BaseMegaFirmware/GCC/key_io.h b/BaseMegaFirmware/GCC/key_io.h new file mode 100644 index 0000000..8c0891f --- /dev/null +++ b/BaseMegaFirmware/GCC/key_io.h @@ -0,0 +1,101 @@ +/* Copyright (c)2007, 2008 Martin Thomas, BSD license */ + +#ifndef KEY_IO_H_ +#define KEY_IO_H_ + +#include +#include + +#include "timebase.h" /* for TIMEBASE_DELTAT_MS */ + +#define KEY_IO_KEYSA_DDR DDRC +#define KEY_IO_KEYSA_PORT PORTC +#define KEY_IO_KEYSA_PIN PINC +#define KEY_IO_KEYA1_BIT PC0 /* SW0 */ +#define KEY_IO_KEYA2_BIT PC1 /* SW1 */ +#define KEY_IO_KEYA3_BIT PC6 /* SW2 */ +#define KEY_IO_KEYA4_BIT PC7 /* SW3 */ +#define KEY_IO_KEYSB_DDR DDRD +#define KEY_IO_KEYSB_PORT PORTD +#define KEY_IO_KEYSB_PIN PIND +#define KEY_IO_KEYB1_BIT PD5 /* Power button */ + +#define KEY_IO_KEY_SW0 (1<<0) +#define KEY_IO_KEY_SW1 (1<<1) +#define KEY_IO_KEY_SW2 (1<<2) +#define KEY_IO_KEY_SW3 (1<<3) +#define KEY_IO_KEY_POWER (1<<4) +#define KEY_IO_KEY_ALL \ + ( KEY_IO_KEY_SW0 | \ + KEY_IO_KEY_SW1 | \ + KEY_IO_KEY_SW2 | \ + KEY_IO_KEY_SW3 | \ + KEY_IO_KEY_POWER ) + + +static inline uint8_t key_io_state_hardware(void) +{ + uint8_t tmp1, tmp2, tmp3; + tmp1 = KEY_IO_KEYSA_PIN & ( (1<>= 4; + tmp3 = KEY_IO_KEYSB_PIN & (1<>= 1; + return ( tmp1 | tmp2 | tmp3 ); +} + +/* debounce/repeat code based on an example from Peter Dannegger, + modified for better integration and volatiles added */ + +//#define KEY_IO_REPEAT_MASK ( KEY_IO_KEY_DOWN | KEY_IO_KEY_UP ) +#define KEY_IO_REPEAT_MASK ( KEY_IO_KEY_ALL ) +#define KEY_IO_REPEAT_START ( 500/*ms*/ / TIMEBASE_DELTAT_MS ) +#define KEY_IO_REPEAT_NEXT ( 100/*ms*/ / TIMEBASE_DELTAT_MS ) + +// debounced and inverted key state, bit = 1: key pressed +extern volatile uint8_t key_io_state; +// key press detect +extern volatile uint8_t key_io_press; +// key long press and repeat +extern volatile uint8_t key_io_rpt; + +/* The following callback-function has to be + called frequently from timer-ISR. Implemented + in this header-file as static inline to + indicate to the compiler that the function + should be inlined into the ISR-code. Tested with + avr-gcc 4.2.1: inlined - o.k. */ +static inline void key_io_callback(void) +{ + static uint8_t ct0, ct1, rpt; + uint8_t i, mystate; + + mystate = key_io_state; + + i = mystate ^ ~( key_io_state_hardware() ); // keys changed ? + ct0 = ~(ct0 & i); // reset or count ct0 + ct1 = ct0 ^ (ct1 & i); // reset or count ct1 + i &= ct0 & ct1; // count until roll over ? + mystate ^= i; // then toggle debounced state + key_io_press |= mystate & i; // 0->1: key press detect + + if( (mystate & KEY_IO_REPEAT_MASK) == 0 ) { // check repeat function + rpt = KEY_IO_REPEAT_START; // start delay + } + if( --rpt == 0 ) { + rpt = KEY_IO_REPEAT_NEXT; // repeat delay + key_io_rpt |= mystate & KEY_IO_REPEAT_MASK; + } + + key_io_state = mystate; +} + +void key_io_init(void); + +uint8_t key_io_get_press( uint8_t key_mask ); +uint8_t key_io_get_rpt( uint8_t key_mask ); +uint8_t key_io_get_longpress( uint8_t key_mask ); +/* only returns "true" after key has been released: */ +uint8_t key_io_get_was_short( uint8_t key_mask ); + +#endif diff --git a/BaseMegaFirmware/GCC/main.c b/BaseMegaFirmware/GCC/main.c new file mode 100644 index 0000000..f467b4b --- /dev/null +++ b/BaseMegaFirmware/GCC/main.c @@ -0,0 +1,250 @@ +/* Copyright (c) 2008 Martin Thomas + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#define VERSION_STRING "V0.1 4/2008" + +#include +#include +#include +#include +#include +#include +#include + +#include "uart.h" +#include "mystdio.h" +#include "bc100_slave.h" +#include "port_ext.h" +#include "timebase.h" +#include "key_io.h" + +#ifndef F_CPU +#warning "F_CPU not defined - will do now" +#define F_CPU 7372800UL +#endif + +#define UART_BAUD_RATE 115200 + +static void fun_delay() +{ + uint8_t i; + for (i=0;i<10;i++) _delay_ms(10); +} + +static void fun(void) +{ + uint8_t i, j; + + for ( i=0; i<5; i++) { + port_ext_set( 1, 0x0f ); + port_ext_update(); + fun_delay(); + port_ext_set( 1, 0xf0 ); + port_ext_update(); + fun_delay(); + } + port_ext_set( 1, 0x00 ); + port_ext_update(); + + for ( i=0; i<2; i++) { + for ( j=0; j<4; j++ ) { + port_ext_bit_set( 1, j ); + port_ext_bit_set( 1, j+4 ); + port_ext_update(); + fun_delay(); + } + for ( j=4; j>0; j-- ) { + port_ext_bit_clear( 1, j-1 ); + port_ext_bit_clear( 1, j-1+4 ); + port_ext_update(); + fun_delay(); + } + } + port_ext_set( 1, 0x00 ); + port_ext_update(); +} + +static void slave_run(void) +{ + port_ext_bit_set( 0, 0 ); + port_ext_bit_set( 0, 1 ); + port_ext_update(); +} + +static void slave_stop(void) +{ + port_ext_bit_clear( 0, 0 ); + port_ext_bit_clear( 0, 1 ); + port_ext_update(); +} + +int main(void) +{ + uint16_t ui_input, tick_local, tick_now; + uint8_t c, show_menu; + + // wait for power-button release (paranoia?) + while ( !( PIND & ( 1 << PD5 ) ) ) { ; } + key_io_init(); + + uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); + mystdio_init(); + + timebase_init(); + + sei(); + + myprintf_P("\n\nBC100 Master Firmware, (C) Martin Thomas " VERSION_STRING "\n"); + + + bc100_slave_init(); + + port_ext_init(); + fun(); + slave_run(); + + show_menu = 1; + tick_local = timebase_get_tick(); + + while ( 1 ) { + if ( show_menu ) { + myprintf_P("(1) 0x55 to LEDs\n"); + myprintf_P("(2) 0xAA to LEDs\n"); + myprintf_P("(3) MASTER_INT low\n"); + myprintf_P("(4) MASTER_INT high\n"); + myprintf_P("(f) Power Off\n"); + myprintf_P("(t) Test Slave Comm\n"); + myprintf_P("(r) Reset Slave\n"); + myprintf_P("(h) Show this again\n"); + myprintf_P("Select > "); + show_menu = 0; + } + + ui_input = uart_getc(); + if ( ui_input & UART_NO_DATA ) { + /* not data */ + } + else { + if ( ui_input & UART_FRAME_ERROR ) { + uart_puts_P("UART Frame Error: "); + } + if ( ui_input & UART_OVERRUN_ERROR ) { + uart_puts_P("UART Overrun Error: "); + } + if ( ui_input & UART_BUFFER_OVERFLOW ) { + uart_puts_P("Buffer overflow error: "); + } + + c = (uint8_t)ui_input; + myprintf_P("%c\n", c); + switch ( c ) { +#ifdef BC100_SLAVE_TEST + case 't' : + if ( ( PORTD & (1< "); + } + } /* key detected */ + + tick_now = timebase_get_tick(); + if ( (uint16_t)( tick_now - tick_local ) > 200 ) { + // myprintf_P("Keys: %02x", key_io_state_hardware() ); + tick_local = tick_now; + } + + if ( key_io_get_press( KEY_IO_KEY_SW0 ) ) { + myprintf_P("SW0 press\n"); + } + if( key_io_get_longpress( KEY_IO_KEY_SW1 ) ) { + myprintf_P("SW1 long\n"); + } + if( key_io_get_was_short( KEY_IO_KEY_SW2 ) ) { + myprintf_P("SW2 was short\n"); + } + if( key_io_get_rpt( KEY_IO_KEY_SW2 ) ) { + myprintf_P("SW2 repeat/long\n"); + } + if ( key_io_get_press( KEY_IO_KEY_SW3 ) ) { + myprintf_P("SW3 pres\n"); + } + + if( key_io_get_press( KEY_IO_KEY_POWER ) ) { + myprintf_P("POWER Key hit -> Power off\n"); + while ( !( PIND & (1 << PD5) ) ) { ; } + slave_stop(); + port_ext_bit_clear( 0, 2 ); + port_ext_update(); + } + + + } /* main-loop */ +} diff --git a/BaseMegaFirmware/GCC/mystdio.c b/BaseMegaFirmware/GCC/mystdio.c new file mode 100644 index 0000000..9fe8a24 --- /dev/null +++ b/BaseMegaFirmware/GCC/mystdio.c @@ -0,0 +1,22 @@ +// Martin Thomas 3/2008 + +#include +#include "uart.h" +#include "mystdio.h" + +static int uart_putchar( char c, FILE *stream ) +{ + if ( c == '\n' ) { + uart_putc( '\r' ); + } + uart_putc( c ); + + return 0; +} + +static FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); + +void mystdio_init(void) +{ + stdout = &uart_stream; +} diff --git a/BaseMegaFirmware/GCC/mystdio.h b/BaseMegaFirmware/GCC/mystdio.h new file mode 100644 index 0000000..7c3eaa0 --- /dev/null +++ b/BaseMegaFirmware/GCC/mystdio.h @@ -0,0 +1,13 @@ +#ifndef MYSTDIO_H +#define MYSTDIO_H + +#include +#include +#include + + +#define myprintf_P( printf_ctrl_, args_...) printf_P( PSTR(printf_ctrl_), ## args_ ) + +void mystdio_init(void); + +#endif /* MYSTDIO_H */ diff --git a/BaseMegaFirmware/GCC/port_ext.c b/BaseMegaFirmware/GCC/port_ext.c new file mode 100644 index 0000000..40ff4ab --- /dev/null +++ b/BaseMegaFirmware/GCC/port_ext.c @@ -0,0 +1,126 @@ +// Martin Thomas 4/2008 + +#include +#include +#include +#include "port_ext.h" + +// #include "mystdio.h" + +static uint8_t virtports[PORT_EXT_OUTPORTS] = { + PORT_EXT_INIT0, + PORT_EXT_INIT1, + PORT_EXT_INIT2 +}; + +static inline void strobe_delay(void) +{ +#if 0 + // delay ca. 100ns @ 2V for 74x595, 1us for tests + _delay_us(1); +#else + // 1 cycle ca 130ns at 7,3MHz + asm volatile("nop"::); +#endif +} + +static inline void output_disable(void) +{ + PORT_EXT_PORT |= ( 1 << PORT_EXT_PIN_OE ); +} + +static inline void output_enable(void) +{ + PORT_EXT_PORT &= ~( 1 << PORT_EXT_PIN_OE ); +} + +static inline void pulse_latch(void) +{ + PORT_EXT_PORT |= ( 1 << PORT_EXT_PIN_LATCH ); + strobe_delay(); + PORT_EXT_PORT &= ~( 1 << PORT_EXT_PIN_LATCH ); + strobe_delay(); +} + +static inline void pulse_clock(void) +{ + PORT_EXT_PORT |= ( 1 << PORT_EXT_PIN_CLK ); + strobe_delay(); + PORT_EXT_PORT &= ~( 1 << PORT_EXT_PIN_CLK ); + strobe_delay(); +} + +static void shift_out(void) +{ + uint8_t i, bit; + + // first bit shifted out is bit7 in virtports[PORT_EXT_OUTPORTS-1] + // - on BC100 this is for U205 Q7 + // last bit shifted out is bit 0 in virtports[0] + // - on BC100 this is for U202 Q0 + for ( i = PORT_EXT_OUTPORTS; i > 0; i-- ) { + // myprintf_P("Port %d = %d\n", i-1, virtports[i-1] ); + for ( bit = 8; bit > 0; bit-- ) { + if ( virtports[i-1] & ( 1 << (bit-1) ) ) { + PORT_EXT_PORT |= ( 1 << PORT_EXT_PIN_DIN ); + } + else { + PORT_EXT_PORT &= ~( 1 << PORT_EXT_PIN_DIN ); + } + pulse_clock(); + } + } + pulse_latch(); +} + +void port_ext_init(void) +{ + PORT_EXT_PORT &= ~( + ( 1 << PORT_EXT_PIN_CLK ) | + ( 1 << PORT_EXT_PIN_DIN) | + ( 1 << PORT_EXT_PIN_LATCH ) ); + PORT_EXT_PORT |= ( 1 << PORT_EXT_PIN_OE ); + PORT_EXT_DDR |= ( + ( 1 << PORT_EXT_PIN_OE) | + ( 1 << PORT_EXT_PIN_CLK ) | + ( 1 << PORT_EXT_PIN_DIN) | + ( 1 << PORT_EXT_PIN_LATCH ) ); + // set inititial values before enabling outputs + // - on BC100 this is just for U202 since it's + // the only 74x595 with switchable /OE + shift_out(); + output_enable(); + // since Q7' is low while output is disabled (low) + // (Philips 74HC(T)595 datasheet) another shift- + // out has to be done to set the cascaded outputs + // - on BC100 this will set U201, U202 and U205 outputs + shift_out(); +} + +void port_ext_update(void) +{ + shift_out(); +} + +void port_ext_bit_clear( uint8_t port, uint8_t bit ) +{ + if ( ( port < PORT_EXT_OUTPORTS ) && ( bit < 8 ) ) { + virtports[port] &= ~( 1 << bit ); + } +} + +void port_ext_bit_set( uint8_t port, uint8_t bit ) +{ + if ( ( port < PORT_EXT_OUTPORTS ) && ( bit < 8 ) ) { + virtports[port] |= ( 1 << bit ); + } +} + +void port_ext_set( uint8_t port, uint8_t val ) +{ + if ( port < PORT_EXT_OUTPORTS ) { + virtports[port] = val; + } +} + + diff --git a/BaseMegaFirmware/GCC/port_ext.h b/BaseMegaFirmware/GCC/port_ext.h new file mode 100644 index 0000000..aa25da9 --- /dev/null +++ b/BaseMegaFirmware/GCC/port_ext.h @@ -0,0 +1,32 @@ +// Martin Thomas 4/2008 + +#ifndef PORT_EXT_H +#define PORT_EXT_H + +#define PORT_EXT_OUTPORTS 3 /* num. of 74x595 */ + +/* BC100 U202: + reset ATtinyx61 (Q0) + reset ATtinyx5 (Q1) + power-off = 1 = disabled (Q2) + electronic load- off (Q4) + electronic load+ off (Q6) */ +#define PORT_EXT_INIT0 ( (1<<0)|(1<<1)|(1<<2)|(1<<4)|(1<<6) ) +#define PORT_EXT_INIT1 0x00 +#define PORT_EXT_INIT2 0x00 + +#define PORT_EXT_PORT PORTB +#define PORT_EXT_DDR DDRB +#define PORT_EXT_PIN PINB +#define PORT_EXT_PIN_OE PB0 /* = /OE */ +#define PORT_EXT_PIN_LATCH PB1 /* = ST_CP */ +#define PORT_EXT_PIN_DIN PB2 /* = DS */ +#define PORT_EXT_PIN_CLK PB3 /* = SH_CP */ + +void port_ext_init(void); +void port_ext_update(void); +void port_ext_bit_clear( uint8_t port, uint8_t bit ); +void port_ext_bit_set( uint8_t port, uint8_t bit ); +void port_ext_set( uint8_t port, uint8_t val ); + +#endif diff --git a/BaseMegaFirmware/GCC/spi.c b/BaseMegaFirmware/GCC/spi.c new file mode 100644 index 0000000..a69e4e7 --- /dev/null +++ b/BaseMegaFirmware/GCC/spi.c @@ -0,0 +1,43 @@ +// Martin Thomas 3/2008 + +#include +#include +#include + +#include "spi.h" + +void SPI_init( void ) +{ + SPI_PORT |= (1< + +#if defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) +#define SPI_PORT PORTB +#define SPI_DDR DDRB +#define SPI_PIN PINB +#define SPI_SS_BIT PB4 +#define SPI_MOSI_BIT PB5 +#define SPI_MISO_BIT PB6 +#define SPI_SCK_BIT PB7 +#else +#error "no SPI definitions for this device" +#endif + +void SPI_init( void ); +void SPI_release( void ); +uint8_t SPI_rw( uint8_t output ); + +#endif /* SPI_H */ + diff --git a/BaseMegaFirmware/GCC/timebase.c b/BaseMegaFirmware/GCC/timebase.c new file mode 100644 index 0000000..92bf015 --- /dev/null +++ b/BaseMegaFirmware/GCC/timebase.c @@ -0,0 +1,87 @@ +// Copyright (c) 2007, 2008 Martin Thomas - BSD-license +// 10 ms timebase with +// 8bit timer-counter #0 in CTC-mode on ATmega644 + +#include +#include +#include +#include "timebase.h" + +#include "key_io.h" /* keys callback/debouce */ + +#define COUNTER_IS_16BIT 0 +#define PRESCALER 1024UL + +#if TIMEBASE_DELTAT_MS != 10 +#warning "code prepared for 10ms tick" +#endif + +#define TIMERFREQ (1000/TIMEBASE_DELTAT_MS) /* Hz */ +#define OCRMATCHVAL ( (F_CPU*10/PRESCALER/TIMERFREQ+5)/10 - 1 ) + +#if COUNTER_IS_16BIT + /* 16 bit counter */ +#define OCR_MATCH_MAX 0xfffe +#else +/* 8 bit counter */ +#define OCR_MATCH_MAX 0xfe +#endif /* COUNTER_IS_16BIT */ +#define OCR_MATCH_MIN 0x02 + +#if ( OCRMATCHVAL > OCR_MATCH_MAX ) +#error "PRESCALER too small or F_CPU too high" +#endif +#if ( OCRMATCHVAL < 2 ) +#error "PRESCALER too large or F_CPU too low" +#endif + +volatile uint16_t timebase_tick; + +ISR(TIMER0_COMPA_vect) +{ + timebase_tick++; + + key_io_callback(); +} + +void timebase_init(void) +{ + uint8_t sreg; + + sreg=SREG; + cli(); + + // init Timer 0 Mode 4 - CTC with interrupt on compare-match + + TCCR0A = (1< + +#define TIMEBASE_DELTAT_MS 10 /* ms */ + +void timebase_init(void); +uint16_t timebase_get_tick(void); + +#endif diff --git a/BaseMegaFirmware/GCC/uart.c b/BaseMegaFirmware/GCC/uart.c new file mode 100644 index 0000000..48d2c9a --- /dev/null +++ b/BaseMegaFirmware/GCC/uart.c @@ -0,0 +1,585 @@ +/************************************************************************* +Title: Interrupt UART library with receive/transmit circular buffers +Author: Peter Fleury http://jump.to/fleury +File: $Id: uart.c,v 1.5.2.10 2005/11/15 19:49:12 peter Exp $ +Software: AVR-GCC 3.3 +Hardware: any AVR with built-in UART, + tested on AT90S8515 at 4 Mhz and ATmega at 1Mhz + +DESCRIPTION: + An interrupt is generated when the UART has finished transmitting or + receiving a byte. The interrupt handling routines use circular buffers + for buffering received and transmitted data. + + The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE variables define + the buffer size in bytes. Note that these variables must be a + power of 2. + +USAGE: + Refere to the header file uart.h for a description of the routines. + See also example test_uart.c. + +NOTES: + Based on Atmel Application Note AVR306 + +*************************************************************************/ +#include +#include +// #include +#include +#include "uart.h" + + +/* + * constants and macros + */ + +/* size of RX/TX buffers */ +#define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1) +#define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1) + +#if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK ) +#error RX buffer size is not a power of 2 +#endif +#if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK ) +#error TX buffer size is not a power of 2 +#endif + +#if defined(__AVR_AT90S2313__) \ + || defined(__AVR_AT90S4414__) || defined(__AVR_AT90S4434__) \ + || defined(__AVR_AT90S8515__) || defined(__AVR_AT90S8535__) \ + || defined(__AVR_ATmega103__) + /* old AVR classic or ATmega103 with one UART */ + #define AT90_UART + #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA + #define UART0_STATUS USR + #define UART0_CONTROL UCR + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_AT90S2333__) || defined(__AVR_AT90S4433__) + /* old AVR classic with one UART */ + #define AT90_UART + #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \ + || defined(__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) \ + || defined(__AVR_ATmega323__) + /* ATmega with one USART */ + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega163__) + /* ATmega163 with one UART */ + #define ATMEGA_UART + #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega162__) + /* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT SIG_USART0_RECV + #define UART1_RECEIVE_INTERRUPT SIG_USART1_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_USART0_DATA + #define UART1_TRANSMIT_INTERRUPT SIG_USART1_DATA + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) + /* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT SIG_UART0_RECV + #define UART1_RECEIVE_INTERRUPT SIG_UART1_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_UART0_DATA + #define UART1_TRANSMIT_INTERRUPT SIG_UART1_DATA + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega161__) + /* ATmega with UART */ + #error "AVR ATmega161 currently not supported by this libaray !" +#elif defined(__AVR_ATmega169__) + /* ATmega with one USART */ + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT SIG_USART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_USART_DATA + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega48__) ||defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega644__) + #define ATMEGA_USART0 + #define UART0_RECEIVE_INTERRUPT SIG_USART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_USART_DATA + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATtiny2313__) + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT SIG_USART0_RX + #define UART0_TRANSMIT_INTERRUPT SIG_USART0_UDRE + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#else + #error "no UART definition for MCU available" +#endif + + +/* + * module global variables + */ +static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE]; +static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE]; +static volatile unsigned char UART_TxHead; +static volatile unsigned char UART_TxTail; +static volatile unsigned char UART_RxHead; +static volatile unsigned char UART_RxTail; +static volatile unsigned char UART_LastRxError; + +#if defined( ATMEGA_USART1 ) +static volatile unsigned char UART1_TxBuf[UART_TX_BUFFER_SIZE]; +static volatile unsigned char UART1_RxBuf[UART_RX_BUFFER_SIZE]; +static volatile unsigned char UART1_TxHead; +static volatile unsigned char UART1_TxTail; +static volatile unsigned char UART1_RxHead; +static volatile unsigned char UART1_RxTail; +static volatile unsigned char UART1_LastRxError; +#endif + + + +SIGNAL(UART0_RECEIVE_INTERRUPT) +/************************************************************************* +Function: UART Receive Complete interrupt +Purpose: called when the UART has received a character +**************************************************************************/ +{ + unsigned char tmphead; + unsigned char data; + unsigned char usr; + unsigned char lastRxError; + + + /* read UART status register and UART data register */ + usr = UART0_STATUS; + data = UART0_DATA; + + /* */ +#if defined( AT90_UART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#elif defined( ATMEGA_USART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#elif defined( ATMEGA_USART0 ) + lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) ); +#elif defined ( ATMEGA_UART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#endif + + /* calculate buffer index */ + tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK; + + if ( tmphead == UART_RxTail ) { + /* error: receive buffer overflow */ + lastRxError = UART_BUFFER_OVERFLOW >> 8; + }else{ + /* store new index */ + UART_RxHead = tmphead; + /* store received data in buffer */ + UART_RxBuf[tmphead] = data; + } + UART_LastRxError = lastRxError; +} + + +SIGNAL(UART0_TRANSMIT_INTERRUPT) +/************************************************************************* +Function: UART Data Register Empty interrupt +Purpose: called when the UART is ready to transmit the next byte +**************************************************************************/ +{ + unsigned char tmptail; + + + if ( UART_TxHead != UART_TxTail) { + /* calculate and store new buffer index */ + tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK; + UART_TxTail = tmptail; + /* get one byte from buffer and write it to UART */ + UART0_DATA = UART_TxBuf[tmptail]; /* start transmission */ + }else{ + /* tx buffer empty, disable UDRE interrupt */ + UART0_CONTROL &= ~_BV(UART0_UDRIE); + } +} + + +/************************************************************************* +Function: uart_init() +Purpose: initialize UART and set baudrate +Input: baudrate using macro UART_BAUD_SELECT() +Returns: none +**************************************************************************/ +void uart_init(unsigned int baudrate) +{ + UART_TxHead = 0; + UART_TxTail = 0; + UART_RxHead = 0; + UART_RxTail = 0; + +#if defined( AT90_UART ) + /* set baud rate */ + UBRR = (unsigned char)baudrate; + + /* enable UART receiver and transmmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE)|_BV(RXEN)|_BV(TXEN); + +#elif defined (ATMEGA_USART) + /* Set baud rate */ + if ( baudrate & 0x8000 ) + { + UART0_STATUS = (1<>8); + UBRRL = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE)|(1<>8); + UBRR0L = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE0)|(1<>8); + UBRR = (unsigned char) baudrate; + + /* Enable UART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE)|(1<> 8; + }else{ + /* store new index */ + UART1_RxHead = tmphead; + /* store received data in buffer */ + UART1_RxBuf[tmphead] = data; + } + UART1_LastRxError = lastRxError; +} + + +SIGNAL(UART1_TRANSMIT_INTERRUPT) +/************************************************************************* +Function: UART1 Data Register Empty interrupt +Purpose: called when the UART1 is ready to transmit the next byte +**************************************************************************/ +{ + unsigned char tmptail; + + + if ( UART1_TxHead != UART1_TxTail) { + /* calculate and store new buffer index */ + tmptail = (UART1_TxTail + 1) & UART_TX_BUFFER_MASK; + UART1_TxTail = tmptail; + /* get one byte from buffer and write it to UART */ + UART1_DATA = UART1_TxBuf[tmptail]; /* start transmission */ + }else{ + /* tx buffer empty, disable UDRE interrupt */ + UART1_CONTROL &= ~_BV(UART1_UDRIE); + } +} + + +/************************************************************************* +Function: uart1_init() +Purpose: initialize UART1 and set baudrate +Input: baudrate using macro UART_BAUD_SELECT() +Returns: none +**************************************************************************/ +void uart1_init(unsigned int baudrate) +{ + UART1_TxHead = 0; + UART1_TxTail = 0; + UART1_RxHead = 0; + UART1_RxTail = 0; + + + /* Set baud rate */ + if ( baudrate & 0x8000 ) + { + UART1_STATUS = (1<>8); + UBRR1L = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART1_CONTROL = _BV(RXCIE1)|(1< http://jump.to/fleury +File: $Id: uart.h,v 1.7.2.5 2005/08/14 11:25:41 Peter Exp $ +Software: AVR-GCC 3.3 +Hardware: any AVR with built-in UART, tested on AT90S8515 at 4 Mhz +Usage: see Doxygen manual +************************************************************************/ + +/** + * @defgroup pfleury_uart UART Library + * @code #include @endcode + * + * @brief Interrupt UART library using the built-in UART with transmit and receive circular buffers. + * + * This library can be used to transmit and receive data through the built in UART. + * + * An interrupt is generated when the UART has finished transmitting or + * receiving a byte. The interrupt handling routines use circular buffers + * for buffering received and transmitted data. + * + * The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE constants define + * the size of the circular buffers in bytes. Note that these constants must be a power of 2. + * You may need to adapt this constants to your target and your application by adding + * CDEFS += -DUART_RX_BUFFER_SIZE=nn -DUART_RX_BUFFER_SIZE=nn to your Makefile. + * + * @note Based on Atmel Application Note AVR306 + * @author Peter Fleury pfleury@gmx.ch http://jump.to/fleury + */ + +/**@{*/ + + +#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304 +#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !" +#endif + + +/* +** constants and macros +*/ + +/** @brief UART Baudrate Expression + * @param xtalcpu system clock in Mhz, e.g. 4000000L for 4Mhz + * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600 + */ +#define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu)/((baudRate)*16l)-1) + +/** @brief UART Baudrate Expression for ATmega double speed mode + * @param xtalcpu system clock in Mhz, e.g. 4000000L for 4Mhz + * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600 + */ +#define UART_BAUD_SELECT_DOUBLE_SPEED(baudRate,xtalCpu) (((xtalCpu)/((baudRate)*8l)-1)|0x8000) + + +/** Size of the circular receive buffer, must be power of 2 */ +#ifndef UART_RX_BUFFER_SIZE +#define UART_RX_BUFFER_SIZE 32 +#endif +/** Size of the circular transmit buffer, must be power of 2 */ +#ifndef UART_TX_BUFFER_SIZE +#define UART_TX_BUFFER_SIZE 32 +#endif + +/* test if the size of the circular buffers fits into SRAM */ +#if ( (UART_RX_BUFFER_SIZE+UART_TX_BUFFER_SIZE) >= (RAMEND-0x60 ) ) +#error "size of UART_RX_BUFFER_SIZE + UART_TX_BUFFER_SIZE larger than size of SRAM" +#endif + +/* +** high byte error return code of uart_getc() +*/ +#define UART_FRAME_ERROR 0x0800 /* Framing Error by UART */ +#define UART_OVERRUN_ERROR 0x0400 /* Overrun condition by UART */ +#define UART_BUFFER_OVERFLOW 0x0200 /* receive ringbuffer overflow */ +#define UART_NO_DATA 0x0100 /* no receive data available */ + + +/* +** function prototypes +*/ + +/** + @brief Initialize UART and set baudrate + @param baudrate Specify baudrate using macro UART_BAUD_SELECT() + @return none +*/ +extern void uart_init(unsigned int baudrate); + + +/** + * @brief Get received byte from ringbuffer + * + * Returns in the lower byte the received character and in the + * higher byte the last receive error. + * UART_NO_DATA is returned when no data is available. + * + * @param void + * @return lower byte: received byte from ringbuffer + * @return higher byte: last receive status + * - \b 0 successfully received data from UART + * - \b UART_NO_DATA + *
no receive data available + * - \b UART_BUFFER_OVERFLOW + *
Receive ringbuffer overflow. + * We are not reading the receive buffer fast enough, + * one or more received character have been dropped + * - \b UART_OVERRUN_ERROR + *
Overrun condition by UART. + * A character already present in the UART UDR register was + * not read by the interrupt handler before the next character arrived, + * one or more received characters have been dropped. + * - \b UART_FRAME_ERROR + *
Framing Error by UART + */ +extern unsigned int uart_getc(void); + + +/** + * @brief Put byte to ringbuffer for transmitting via UART + * @param data byte to be transmitted + * @return none + */ +extern void uart_putc(unsigned char data); + + +/** + * @brief Put string to ringbuffer for transmitting via UART + * + * The string is buffered by the uart library in a circular buffer + * and one character at a time is transmitted to the UART using interrupts. + * Blocks if it can not write the whole string into the circular buffer. + * + * @param s string to be transmitted + * @return none + */ +extern void uart_puts(const char *s ); + + +/** + * @brief Put string from program memory to ringbuffer for transmitting via UART. + * + * The string is buffered by the uart library in a circular buffer + * and one character at a time is transmitted to the UART using interrupts. + * Blocks if it can not write the whole string into the circular buffer. + * + * @param s program memory string to be transmitted + * @return none + * @see uart_puts_P + */ +extern void uart_puts_p(const char *s ); + +/** + * @brief Macro to automatically put a string constant into program memory + */ +#define uart_puts_P(__s) uart_puts_p(PSTR(__s)) + + + +/** @brief Initialize USART1 (only available on selected ATmegas) @see uart_init */ +extern void uart1_init(unsigned int baudrate); +/** @brief Get received byte of USART1 from ringbuffer. (only available on selected ATmega) @see uart_getc */ +extern unsigned int uart1_getc(void); +/** @brief Put byte to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_putc */ +extern void uart1_putc(unsigned char data); +/** @brief Put string to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts */ +extern void uart1_puts(const char *s ); +/** @brief Put string from program memory to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts_p */ +extern void uart1_puts_p(const char *s ); +/** @brief Macro to automatically put a string constant into program memory */ +#define uart1_puts_P(__s) uart1_puts_p(PSTR(__s)) + +/**@}*/ + +#endif // UART_H + diff --git a/BaseTinyFirmware/GCC/ChangeLog b/BaseTinyFirmware/GCC/ChangeLog deleted file mode 100644 index 9c5d2d5..0000000 --- a/BaseTinyFirmware/GCC/ChangeLog +++ /dev/null @@ -1,32 +0,0 @@ -2008-03-30 Kevin Rosenberg - * GCC Makefile's improved with more listing output as well as - added -Wl,-gc-sections option which stops crashes using linker - relaxation [thanks to Eric Weddington] - -2008-03-28 Kevin Rosenberg - * BaseTinyFirmware/GCC/avr463/Makefile: Added -Wl,-relax to linker - flags. On my system this crashes avr-ld.exe, but others have reported - a large reduction in firmware size with this option. I added this - option for others to try. - * BaseTinyFirmware/GCC/avr458/Makefile: Added missing file - -2008-03-14 Martin Thomas - * added "volatile" to structure object and array declarations for - objects sed in main-thread and ISRs. I'm not sure about the - current state of implicitly "guaranteed" accesses in (avr-)gcc but - it should be a "better safe than sorry" extension. - * enveloped access to timer-values in timer.c to make them - "atomic" since they are unsigned long - * "atomic" access to singned int and unsigned int members of ADCS - * it maybe better to have one place to globally enable - interrupts ("sei"). Done in "initialize" now and not several - times in the driver init-functions. - * changed some space to tab as in the original code - * added header files to the AVR-Studio project workspace - * added -lm to the linker-options in the AVR Studio gcc-plugin, - not important for the basic application but might be good if - someone uses the ode as a base for own developments - -2008-03-12 Kevin Rosenberg - * Initial GCC port performed and compiles without error - * Warning: Not yet tested on BC100 hardware! diff --git a/BaseTinyFirmware/GCC/PWM.c b/BaseTinyFirmware/GCC/PWM.c index 9d205fc..a84a357 100644 --- a/BaseTinyFirmware/GCC/PWM.c +++ b/BaseTinyFirmware/GCC/PWM.c @@ -11,14 +11,14 @@ * AVR463: Charging NiMH Batteries with BC100 * * \par Documentation - * For comprehensive code documentation, supported compilers, compiler + * For comprehensive code documentation, supported compilers, compiler * settings and supported devices see readme.html * * \author * Atmel Corporation: http://www.atmel.com \n * Support email: avr@atmel.com * - * + * * $Name$ * $Revision: 2299 $ * $RCSfile$ @@ -67,52 +67,52 @@ void PWM_Start(void) { // Clear OC1B on compare match, enable PWM on comparator OCR1B. TCCR1A = (1< 0) { +unsigned char PWM_DecrementDutyCycle(void) { + + if (OCR1B > 0) { OCR1B -= 1; return(TRUE); } else { diff --git a/BaseTinyFirmware/GCC/avr458/Makefile b/BaseTinyFirmware/GCC/avr458/Makefile index 412aa8d..c2d1462 100644 --- a/BaseTinyFirmware/GCC/avr458/Makefile +++ b/BaseTinyFirmware/GCC/avr458/Makefile @@ -13,7 +13,7 @@ COMMON = -mmcu=$(MCU) ## Compile options common for all C compilation units. CFLAGS = $(COMMON) -CFLAGS += -gdwarf-2 -std=gnu99 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -ffunction-sections +CFLAGS += -gdwarf-2 -std=gnu99 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums CFLAGS += -Wall -Wstrict-prototypes -Wundef -Wa,-adhlns=./$(*F).lst CFLAGS += -MMD -MP -MF dep/$(@F).d CFLAGS += -DLIION @@ -25,7 +25,7 @@ ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2 ## Linker flags LDFLAGS = $(COMMON) -LDFLAGS += -Wl,-Map=$(PROJECT).map,--cref -Wl,-gc-sections -Wl,-relax +LDFLAGS += -Wl,-Map=$(PROJECT).map,--cref -Wl,-relax ## Intel Hex file production flags HEX_FLASH_FLAGS = -R .eeprom diff --git a/BaseTinyFirmware/GCC/statefunc.c b/BaseTinyFirmware/GCC/statefunc.c index ef1464d..9fc0ae5 100644 --- a/BaseTinyFirmware/GCC/statefunc.c +++ b/BaseTinyFirmware/GCC/statefunc.c @@ -16,14 +16,14 @@ * AVR463: Charging NiMH Batteries with BC100 * * \par Documentation - * For comprehensive code documentation, supported compilers, compiler + * For comprehensive code documentation, supported compilers, compiler * settings and supported devices see readme.html * * \author * Atmel Corporation: http://www.atmel.com \n * Support email: avr@atmel.com * - * + * * $Name$ * $Revision: 2299 $ * $RCSfile$ @@ -65,6 +65,9 @@ unsigned char ErrorFlags; //!< \brief Holds error flags. //! \note See menu.h for definitions of states. unsigned char ErrorState; +//! \brief Set to 1 by the watchdog-timeout-ISR +//! \note added by Martin Thomas +volatile unsigned char WatchdogFlag; //****************************************************************************** // Functions @@ -93,17 +96,20 @@ unsigned char Initialize(unsigned char inp) // Disable interrupts while setting prescaler. cli(); - + CLKPR = (1< 8 MHz clock frequency. - + // Init 1-Wire(R) interface. OWI_Init(OWIBUS); - + // Clear on-chip EEPROM. - for (page = 0; page < 4; page++) { + for (page = 0; page < 4; page++) { for (i = 0; i < 32; i++) { - eeprom_write_byte(&BattEEPROM[page][i], 0); + // mthomas: avoid unneeded writes + if ( eeprom_read_byte( &BattEEPROM[page][i] ) != 0 ) { + eeprom_write_byte( &BattEEPROM[page][i], 0 ); + } } } @@ -124,10 +130,10 @@ unsigned char Initialize(unsigned char inp) } DisableBatteries(); - + BattActive = 0; // We have to start somewhere.. ErrorFlags = 0; - + // Init complete! Go to ST_BATCON next. return(ST_BATCON); } @@ -153,16 +159,16 @@ unsigned char Initialize(unsigned char inp) unsigned char BatteryControl(unsigned char inp) { unsigned char i; - + // Make sure ADC inputs are configured properly! (Will disables batteries.) if (!JumperCheck()) { return(ST_ERROR); // Error. Exit before damage is done! } - + // If neither battery is valid, flag error and go to error state if (!(eeprom_read_byte(&BattControl[0]) & BIT_BATTERY_ENABLED) && (!eeprom_read_byte(&BattControl[1]) & BIT_BATTERY_ENABLED)) { SetErrorFlag(ERR_NO_BATTERIES_ENABLED); - + return(ST_ERROR); } @@ -229,43 +235,72 @@ unsigned char Sleep(unsigned char inp) return(ST_BATCON); } } - + DisableBatteries(); // Disable both batteries before Doze()! } while (TRUE); } +/*! \brief Watchdog interrupt-service-routine + * + * Called on watchdog timeout, added by Martin Thomas + */ +ISR(WDT_vect) +{ + WatchdogFlag = 1; +} + /*! \brief Doze off for approx. 8 seconds (Vcc = 5 V) * * Waits for ADC-cycles to complete, disables the ADC, then sleeps for * approx. 8 seconds (Vcc = 5 V) using the watchdog timer. * On wakeup, ADC is re-enabled. + * Modification by Martin Thomas: + * Do not enter standby mode if PB6 is low (MASTER_INT on BC100) + * so SPI communication with the master-controller is still possible + * during "doze". */ void Doze(void) { + uint8_t sreg_saved; // Wait for this ADC cycle to complete, then halt after the next one. ADC_Wait(); ADCS.Halt = TRUE; ADCS.Flag = FALSE; - + do { } while (ADCS.Flag == FALSE); - + WDTCR = (1< 8 MHz clock frequency. - + // Init 1-Wire(R) interface. OWI_Init(OWIBUS); - + // Clear on-chip EEPROM. - for (page = 0; page < 4; page++) { + for (page = 0; page < 4; page++) { for (i = 0; i < 32; i++) { - BattEEPROM[page][i] = 0; + // From mthomas GCC addition + if (BattEEPROM[page][i] != 0) { + BattEEPROM[page][i] = 0; + } } } @@ -114,12 +120,12 @@ unsigned char Initialize(unsigned char inp) ADC_Wait(); BatteryStatusRefresh(); } - + DisableBatteries(); - + BattActive = 0; // We have to start somewhere.. ErrorFlags = 0; - + // Init complete! Go to ST_BATCON next. return(ST_BATCON); } @@ -145,23 +151,23 @@ unsigned char Initialize(unsigned char inp) unsigned char BatteryControl(unsigned char inp) { unsigned char i; - + // Make sure ADC inputs are configured properly! (Will disables batteries.) if (!JumperCheck()) { return(ST_ERROR); // Error. Exit before damage is done! } - + // If neither battery is valid, flag error and go to error state if ((!BattControl[0].Enabled) && (!BattControl[1].Enabled)) { SetErrorFlag(ERR_NO_BATTERIES_ENABLED); - + return(ST_ERROR); } // Get ADC-readings, try to read EPROM, and start prequalification // of any uncharged battery. for (i = 0; i < 2; i++) { - if (BattControl[i].Enabled) { + if (BattControl[i].Enabled) { EnableBattery(i); ADC_Wait(); @@ -169,7 +175,7 @@ unsigned char BatteryControl(unsigned char inp) if (!BattData.Charged) { BatteryDataRefresh(); - return(ST_PREQUAL); + return(ST_PREQUAL); } } } @@ -221,43 +227,73 @@ unsigned char Sleep(unsigned char inp) return(ST_BATCON); } } - + DisableBatteries(); // Disable both batteries before Doze()! } while (TRUE); } +/*! \brief Watchdog interrupt-service-routine + * + * Called on watchdog timeout, added by Martin Thomas + */ +#pragma vector = WDT_vect +__interrupt void WDT_ISR(void) +{ + WatchdogFlag = 1; +} + /*! \brief Doze off for approx. 8 seconds (Vcc = 5 V) * * Waits for ADC-cycles to complete, disables the ADC, then sleeps for * approx. 8 seconds (Vcc = 5 V) using the watchdog timer. * On wakeup, ADC is re-enabled. + * Modification by Martin Thomas: + * Do not enter standby mode if PB6 is low (MASTER_INT on BC100) + * so SPI communication with the master-controller is still possible + * during "doze". */ void Doze(void) { + uint8_t sreg_saved; // Wait for this ADC cycle to complete, then halt after the next one. ADC_Wait(); ADCS.Halt = TRUE; ADCS.Flag = FALSE; - + do { - } while (ADCS.Flag == FALSE); - + } while (ADCS.Flag == FALSE); + WDTCR = (1< + * BaseTinyFirmware/IAR: Port Martin's changes from 2008-04-03 + to IAR + +2008-04-03 Martin Thomas + * BaseMegaFirmware/GCC: Experimental Master Code for the ATmega644 + with basic "drivers" for + - keys incl. power-off with debounceing + - 74HC595 low-level "software-SPI" + - LEDs though 74HC595 + - Power-off and Slave-Reset control though 74HC595 + - hardware SPI for comm. with slave + - simple test-function for communication with slave + * BaseTinyFirmware/GCC/statefunc.c: + - prevent unneeded writes to eeprom if init fails + - prevent slave from entering sleep-mode standby if + "MASTER_INT" is low (so SPI communication with master is + possible even during the "8-second watchdog delay") + +2008-03-30 Kevin Rosenberg + * BaseTinyFirmware/GCC Makefile's improved with more listing + output as well as added -Wl,-gc-sections option which stops + crashes using linker relaxation [thanks to Eric Weddington] + +2008-03-28 Kevin Rosenberg + * BaseTinyFirmware/GCC/avr463/Makefile: Added -Wl,-relax to linker + flags. On my system this crashes avr-ld.exe, but others have + reported a large reduction in firmware size with this option. I + added this option for others to try. * + BaseTinyFirmware/GCC/avr458/Makefile: Added missing file + +2008-03-14 Martin Thomas + Improvements to BaseTinyFirmware: + * added "volatile" to structure object and array declarations for + objects sed in main-thread and ISRs. I'm not sure about the + current state of implicitly "guaranteed" accesses in (avr-)gcc but + it should be a "better safe than sorry" extension. + * enveloped access to timer-values in timer.c to make them + "atomic" since they are unsigned long + * "atomic" access to singned int and unsigned int members of ADCS + * it maybe better to have one place to globally enable + interrupts ("sei"). Done in "initialize" now and not several + times in the driver init-functions. + * changed some space to tab as in the original code + * added header files to the AVR-Studio project workspace + * added -lm to the linker-options in the AVR Studio gcc-plugin, + not important for the basic application but might be good if + someone uses the ode as a base for own developments + +2008-03-12 Kevin Rosenberg + * Initial GCC port performed and compiles without error + * Warning: Not yet tested on BC100 hardware! -- 2.34.1