Mercurial > ~darius > hgwebdir.cgi > avr-lib
changeset 0:3879f487b661
Initial commit of routines I copy and paste.
Need work to make them more portable (esp cons)
author | darius@Inchoate |
---|---|
date | Wed, 11 Mar 2009 16:42:27 +1030 |
parents | |
children | f5022e20d550 |
files | 1wire.c 1wire.h Makefile.avr cons.c cons.h ds1307.c ds1307.h |
diffstat | 7 files changed, 1607 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1wire.c Wed Mar 11 16:42:27 2009 +1030 @@ -0,0 +1,648 @@ +/* + * Various 1 wire routines + * Search routine is copied from the Dallas owpd library with mods + * available from here http://www.ibutton.com/software/1wire/wirekit.html + * + * $Id$ + * + * Copyright (c) 2004 + * Daniel O'Connor <darius@dons.net.au>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + */ + +/* + * No user servicable parts inside + * + * Modify 1wire-config.h + */ + +#include <stdio.h> +#include <avr/io.h> +#include <avr/pgmspace.h> +#include <util/delay.h> +#include "1wire.h" +#include "1wire-config.h" +#include "cons.h" + +static uint8_t OW_LastDevice = 0; +static uint8_t OW_LastDiscrepancy = 0; +static uint8_t OW_LastFamilyDiscrepancy = 0; + +const PROGMEM char *OWProgROM_Status[] = { + "OK", + "no HW support", + "Invalid params", + "module missing/broken" +}; + +/*----------------------------------------------------------------------------- + * Configure the IO port as we need + */ +void +OWInit(void) { + OWBUSINIT(); + OWSETBUSHIGH(); +} + +/*----------------------------------------------------------------------------- + * Generate a 1-Wire reset, return 0 if presence pulse was found, 1 if it + * wasn't, or 2 if the line appears to be being held low. + * + * (NOTE: Does not handle alarm presence from DS2404/DS1994) + */ +uint8_t +OWTouchReset(void) { + OWDELAY_G; + + /* Check the bus isn't being held low (ie it's broken) Do it after + * the delay so we guarantee we don't see a slave from a previous + * comms attempt + */ +#if 0 + OWSETREAD(); + if(OWREADBUS() == 0) + return 2; +#endif + + OWSETBUSLOW(); + OWDELAY_H; + OWSETBUSHIGH(); + OWDELAY_I; + + OWSETREAD(); + return(OWREADBUS()); +} + +/*----------------------------------------------------------------------------- + * Send a 1-wire write bit. + */ +void +OWWriteBit(uint8_t bit) { + OWDELAY_I; + + if (bit) { + OWSETBUSLOW(); + OWDELAY_A; + OWSETBUSHIGH(); + OWDELAY_B; + } else { + OWSETBUSLOW(); + OWDELAY_C; + OWSETBUSHIGH(); + OWDELAY_D; + } +} + +/*----------------------------------------------------------------------------- + * Read a bit from the 1-wire bus and return it. + */ +uint8_t +OWReadBit(void) { + OWDELAY_I; + + OWSETBUSLOW(); + OWDELAY_A; + OWSETBUSHIGH(); + OWDELAY_E; + OWSETREAD(); + return(OWREADBUS()); +} + +/*----------------------------------------------------------------------------- + * Write a byte to the 1-wire bus + */ +void +OWWriteByte(uint8_t data) { + uint8_t i; + + /* Send LSB first */ + for (i = 0; i < 8; i++) { + OWWriteBit(data & 0x01); + data >>= 1; + } +} + +/*----------------------------------------------------------------------------- + * Read a byte from the 1-wire bus + */ +uint8_t +OWReadByte(void) { + int i, result = 0; + + for (i = 0; i < 8; i++) { + result >>= 1; + if (OWReadBit()) + result |= 0x80; + } + return(result); +} + +/*----------------------------------------------------------------------------- + * Write a 1-wire data byte and return the sampled result. + */ +uint8_t +OWTouchByte(uint8_t data) { + uint8_t i, result = 0; + + for (i = 0; i < 8; i++) { + result >>= 1; + + /* If sending a 1 then read a bit, otherwise write a 0 */ + if (data & 0x01) { + if (OWReadBit()) + result |= 0x80; + } else + OWWriteBit(0); + + data >>= 1; + } + + return(result); +} + +/*----------------------------------------------------------------------------- + * Write a block of bytes to the 1-wire bus and return the sampled result in + * the same buffer + */ +void +OWBlock(uint8_t *data, int len) { + int i; + + for (i = 0; i < len; i++) + data[i] = OWTouchByte(data[i]); +} + + +/*----------------------------------------------------------------------------- + * Send a 1 wire command to a device, or all if no ROM ID provided + */ +void +OWSendCmd(uint8_t *ROM, uint8_t cmd) { + uint8_t i; + + OWTouchReset(); + + if (ROM == NULL) + OWWriteByte(OW_SKIP_ROM_CMD); + else { + OWWriteByte(OW_MATCH_ROM_CMD); + for (i = 0; i < 8; i++) + OWWriteByte(ROM[i]); + } + OWWriteByte(cmd); +} + +/*----------------------------------------------------------------------------- + * Search algorithm from App note 187 (and 162) + * + * OWFirst/OWNext return.. + * 1 when something is found, + * 0 no more modules + * -1 if no presence pulse, + * -2 if bad CRC, + * -3 if bad wiring. + */ +uint8_t +OWFirst(uint8_t *ROM, uint8_t do_reset, uint8_t alarm_only) { + /* Reset state */ + OW_LastDiscrepancy = 0; + OW_LastDevice = 0; + OW_LastFamilyDiscrepancy = 0; + + /* Go looking */ + return (OWNext(ROM, do_reset, alarm_only)); +} + +/* Returns 1 when something is found, 0 if nothing left */ +uint8_t +OWNext(uint8_t *ROM, uint8_t do_reset, uint8_t alarm_only) { + uint8_t bit_test, search_direction, bit_number; + uint8_t last_zero, rom_byte_number, rom_byte_mask; + uint8_t lastcrc8, crcaccum; + int8_t next_result; + + /* Init for search */ + bit_number = 1; + last_zero = 0; + rom_byte_number = 0; + rom_byte_mask = 1; + next_result = OW_NOMODULES; + lastcrc8 = 0; + crcaccum = 0; + + /* if the last call was not the last one */ + if (!OW_LastDevice) { + /* check if reset first is requested */ + if (do_reset) { + /* reset the 1-wire + * if there are no parts on 1-wire, return 0 */ + OWPUTSP(PSTR("Resetting\r\n")); + switch (OWTouchReset()) { + case 0: + break; + + case 1: + /* reset the search */ + OW_LastDiscrepancy = 0; + OW_LastFamilyDiscrepancy = 0; + OWPUTSP(PSTR("No devices on bus\r\n")); + return OW_NOPRESENCE; + break; + + case 2: + /* reset the search */ + OW_LastDiscrepancy = 0; + OW_LastFamilyDiscrepancy = 0; + OWPUTSP(PSTR("Bus appears to be being held low\r\n")); + return OW_BADWIRE; + break; + + } + } + + /* If finding alarming devices issue a different command */ + if (alarm_only) + OWWriteByte(OW_SEARCH_ALRM_CMD); /* issue the alarming search command */ + else + OWWriteByte(OW_SEARCH_ROM_CMD); /* issue the search command */ + + /* pause before beginning the search */ + OWDELAY_I; + OWDELAY_I; + OWDELAY_I; + + /* loop to do the search */ + do { + /* read a bit and its compliment */ + bit_test = OWReadBit() << 1; + bit_test |= OWReadBit(); + + OWPRINTFP(PSTR("bit_test = %d\r\n"), bit_test); + + /* check for no devices on 1-wire */ + if (bit_test == 3) { + OWPRINTFP(PSTR("bit_test = %d\r\n"), bit_test); + return(OW_BADWIRE); + } + else { + /* all devices coupled have 0 or 1 */ + if (bit_test > 0) + search_direction = !(bit_test & 0x01); /* bit write value for search */ + else { + /* if this discrepancy is before the Last Discrepancy + * on a previous OWNext then pick the same as last time */ + if (bit_number < OW_LastDiscrepancy) + search_direction = ((ROM[rom_byte_number] & rom_byte_mask) > 0); + else + /* if equal to last pick 1, if not then pick 0 */ + search_direction = (bit_number == OW_LastDiscrepancy); + + /* if 0 was picked then record its position in LastZero */ + if (search_direction == 0) { + last_zero = bit_number; + + /* check for Last discrepancy in family */ + if (last_zero < 9) + OW_LastFamilyDiscrepancy = last_zero; + } + } + + /* set or clear the bit in the ROM byte rom_byte_number + * with mask rom_byte_mask */ + if (search_direction == 1) + ROM[rom_byte_number] |= rom_byte_mask; + else + ROM[rom_byte_number] &= ~rom_byte_mask; + + /* serial number search direction write bit */ + OWWriteBit(search_direction); + + /* increment the byte counter bit_number + * and shift the mask rom_byte_mask */ + bit_number++; + rom_byte_mask <<= 1; + + /* if the mask is 0 then go to new ROM byte rom_byte_number + * and reset mask */ + if (rom_byte_mask == 0) { + OWCRC(ROM[rom_byte_number], &crcaccum); /* accumulate the CRC */ + lastcrc8 = crcaccum; + + rom_byte_number++; + rom_byte_mask = 1; + } + } + } while (rom_byte_number < 8); /* loop until through all ROM bytes 0-7 */ + + /* if the search was successful then */ + if (!(bit_number < 65) || lastcrc8) { + if (lastcrc8) { + OWPRINTFP(PSTR("Bad CRC (%d)\r\n"), lastcrc8); + next_result = OW_BADCRC; + } else { + /* search successful so set LastDiscrepancy,LastDevice,next_result */ + OW_LastDiscrepancy = last_zero; + OW_LastDevice = (OW_LastDiscrepancy == 0); + OWPRINTFP(PSTR("Last device = %d\r\n"), OW_LastDevice); + next_result = OW_FOUND; + } + } + } + + /* if no device found then reset counters so next 'next' will be + * like a first */ + if (next_result != OW_FOUND || ROM[0] == 0) { + OW_LastDiscrepancy = 0; + OW_LastDevice = 0; + OW_LastFamilyDiscrepancy = 0; + } + + if (next_result == OW_FOUND && ROM[0] == 0x00) + next_result = OW_BADWIRE; + + return next_result; + +} + +uint8_t PROGMEM dscrc_table[] = { + 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65, + 157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220, + 35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98, + 190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255, + 70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7, + 219, 133,103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154, + 101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36, + 248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185, + 140,210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113,147, 205, + 17, 79, 173, 243, 112, 46, 204, 146, 211,141, 111, 49, 178, 236, 14, 80, + 175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82,176, 238, + 50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115, + 202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139, + 87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22, + 233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168, + 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53 +}; + +/*----------------------------------------------------------------------------- + * Update *crc based on the value of x + */ +void +OWCRC(uint8_t x, uint8_t *crc) { + *crc = pgm_read_byte(&dscrc_table[(*crc) ^ x]); +} + +/*----------------------------------------------------------------------------- + * Program a DS2502's memory + * + * Arguments + * ROM - ROM ID (or NULL to send SKIP_ROM) + * start - Start address (bytes) + * len - Length of data to write + * data - Data to write + * exact - If true, only accept exact matches for programming, + * otherwise only ensure the bits we requested were + * programmed [to 0] + * status - If true program status rather than memory + * + * Returns.. + * 0 if all is OK + * 1 if the programming is not possible + * 2 if the parameters were invalid + * 3 if the DS2502 didn't respond appropriately (also happens if the + * module doesn't exist) + */ +uint8_t +OWProgROM(uint8_t *ROM, uint8_t start, uint8_t len, uint8_t *data, uint8_t exact, uint8_t status) { +#if defined(OWSETVPPON) && defined(OWSETVPPOFF) + uint8_t crc, i, tmp; + + /* Stupid programmer detection */ + if (status) { + if (start + len > 3) + return(2); + } else { + if (start + len > 127) + return(2); + } + + if (len < 1) + return(2); + + OWDELAY_I; + if (OWTouchReset() != 0) { + cons_putsP(PSTR("No presence pulse\r\n")); + return(3); + } + + crc = 0; + + /* Send the command */ + if (status) { + OWSendCmd(ROM, OW_WRITE_STATUS); + OWCRC(OW_WRITE_STATUS, &crc); + } else { + OWSendCmd(ROM, OW_WRITE_MEMORY); + OWCRC(OW_WRITE_MEMORY, &crc); + } + + /* And the start address + * (2 bytes even though one would do) + */ + OWWriteByte(start); + OWCRC(start, &crc); + + OWWriteByte(0x00); + OWCRC(0x00, &crc); + + for (i = 0; i < len; i++) { + cons_putsP(PSTR("Programming ")); + cons_puts_hex(data[i]); + cons_putsP(PSTR(" to ")); + cons_puts_hex(start + i); + cons_putsP(PSTR("\r\n")); + + OWWriteByte(data[i]); + OWCRC(data[i], &crc); + + tmp = OWReadByte(); + + if (crc != tmp) { + cons_putsP(PSTR("CRC mismatch ")); + cons_puts_hex(crc); + cons_putsP(PSTR(" vs ")); + cons_puts_hex(tmp); + cons_putsP(PSTR("\r\n")); + + OWTouchReset(); + return(3); + } + + OWSETVPPON(); + OWDELAY_H; + OWSETVPPOFF(); + + tmp = OWReadByte(); + + /* Check the bits we turned off are off */ +/* + for (i = 0; i < 8; i++) + if (!(data[i] & 1 << i) && (tmp & 1 << i)) + return(-3); +*/ + if ((!data[i] & tmp) != 0) { + cons_putsP(PSTR("Readback mismatch ")); + cons_puts_hex(data[i]); + cons_putsP(PSTR(" vs ")); + cons_puts_hex(data[i]); + cons_putsP(PSTR("\r\n")); + + OWTouchReset(); + return(3); + } + + /* The DS2502 loads it's CRC register with the address of the + * next byte */ + crc = 0; + OWCRC(start + i + 1, &crc); + } + + return(0); +#else + return(1); +#endif +} + +/* + * OWGetTemp + * + * Get the temperature from a 1wire bus module + * + * Returns temperature in hundredths of a degree or OW_TEMP_xxx on + * error. + */ +int16_t +OWGetTemp(uint8_t *ROM) { + int8_t i; + uint8_t crc, buf[9]; + int16_t temp; + int16_t tfrac; + + if (ROM[0] != OW_FAMILY_TEMP) + return OW_TEMP_WRONG_FAM; + + OWSendCmd(ROM, OW_CONVERTT_CMD); + + i = 0; + + /* Wait for the conversion */ + while (OWReadBit() == 0) + i = 1; + + /* Check that we talked to a module and it did something */ + if (i == 0) { + return OW_TEMP_NO_ROM; + } + + OWSendCmd(ROM, OW_RD_SCR_CMD); + crc = 0; + for (i = 0; i < 8; i++) { + buf[i] = OWReadByte(); + OWCRC(buf[i], &crc); + } + buf[i] = OWReadByte(); + if (crc != buf[8]) + return OW_TEMP_CRC_ERR; + temp = buf[0]; + if (buf[1] & 0x80) + temp -= 256; + + /* Chop off 0.5 degree bit */ + temp >>= 1; + + /* Calulate the fractional remainder */ + tfrac = buf[7] - buf[6]; + + /* Work in 100'th of degreess to save on floats */ + tfrac *= (int16_t)100; + + /* Divide by count */ + tfrac /= buf[7]; + + /* Subtract 0.25 deg from temp */ + tfrac += 75; + if (tfrac < 100) + temp--; + else + tfrac -= 100; + + i = temp; + temp *= 100; + temp += tfrac; + + return(temp); +} + +/* + * OWTempStatusStr + * + * Return a string for each OW_TEMP_xxx error code + * + * shrt = 1 returns short strings + * + */ +const char * +OWTempStatusStr(int16_t val, uint8_t shrt) { + if (val > OW_TEMP_BADVAL) { + if (shrt) + return PSTR("OK"); + else + return PSTR("OK"); + } + + switch (val) { + case OW_TEMP_WRONG_FAM: + if (shrt) + return PSTR("WrFam"); + else + return PSTR("Wrong family"); + break; + case OW_TEMP_CRC_ERR: + if (shrt) + return PSTR("CRCErr"); + else + return PSTR("CRC Error"); + break; + case OW_TEMP_NO_ROM: + if (shrt) + return PSTR("NoROM"); + else + return PSTR("ROM did not reply"); + break; + default: + if (shrt) + return PSTR("???"); + else + return PSTR("Unknown error code"); + break; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1wire.h Wed Mar 11 16:42:27 2009 +1030 @@ -0,0 +1,91 @@ +/* + * 1 wire header which defines functions and constants + * + * $Id$ + * + * Copyright (c) 2004 + * Daniel O'Connor <darius@dons.net.au>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + */ + +void OWInit(void); +uint8_t OWTouchReset(void); +void OWWriteBit(uint8_t bit); +uint8_t OWReadBit(void); +void OWWriteByte(uint8_t data); +uint8_t OWReadByte(void); +uint8_t OWTouchByte(uint8_t data); +void OWBlock(uint8_t *data, int len); +uint8_t OWFirst(uint8_t *ROM, uint8_t do_reset, uint8_t alarm_only); +uint8_t OWNext(uint8_t *ROM, uint8_t do_reset, uint8_t alarm_only); +void OWCRC(uint8_t x, uint8_t *crc); +void OWSendCmd(uint8_t *ROM, uint8_t cmd); +uint8_t OWProgROM(uint8_t *ROM, uint8_t start, uint8_t len, uint8_t *data, uint8_t exact, uint8_t status); +int16_t OWGetTemp(uint8_t *ROM); +const PROGMEM char *OWTempStatusStr(int16_t val, uint8_t shrt); +extern const PROGMEM char *OWProgROM_Status[]; + + +/* Return codes for OWFirst()/OWNext() */ +#define OW_BADWIRE -3 +#define OW_BADCRC -2 +#define OW_NOPRESENCE -1 +#define OW_NOMODULES 0 +#define OW_FOUND 1 + +/* General 1 wire commands */ +#define OW_OVRDRV_SKIP_CMD 0x3c +#define OW_SEARCH_ALRM_CMD 0xec +#define OW_SEARCH_ROM_CMD 0xf0 +#define OW_READ_ROM_CMD 0x33 +#define OW_MATCH_ROM_CMD 0x55 +#define OW_SKIP_ROM_CMD 0xcc + +/* DS1820 commands */ +#define OW_CONVERTT_CMD 0x44 +#define OW_RD_SCR_CMD 0xbe +#define OW_WR_SCR_CMD 0x4e +#define OW_CPY_SCR_CMD 0x48 +#define OW_RECALL_CMD 0xb8 +#define OW_RD_PSU_CMD 0xb4 + +/* DS2502 commands */ +#define OW_READ_MEMORY 0xf0 +#define OW_READ_STATUS 0xaa +#define OW_GEN_CRC 0xc3 +#define OW_WRITE_MEMORY 0x0f +#define OW_WRITE_STATUS 0x55 + +/* Family codes */ +#define OW_FAMILY_ROM 0x09 +#define OW_FAMILY_TEMP 0x10 + +/* Return codes for OWGetTemp */ +#define OW_TEMP_BADVAL -6000 +#define OW_TEMP_WRONG_FAM -6001 +#define OW_TEMP_CRC_ERR -6002 +#define OW_TEMP_NO_ROM -6003 + +/* Helpers for OWGetTemp's number system */ +#define GETWHOLE(x) ((x) / 100) +#define GETFRAC(x) abs((x) - (GETWHOLE(x) * 100))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile.avr Wed Mar 11 16:42:27 2009 +1030 @@ -0,0 +1,57 @@ +# +# $Id$ +# + +.SUFFIXES: .hex .out .c .o .elf .dmp .s + +# Otherwise we get -march=foo +NO_CPU_CFLAGS= +_CPUCFLAGS= + +# Programs +AS=avr-as +CC=avr-gcc +OBJCOPY=avr-objcopy +OBJDUMP=avr-objdump + +# Tell as to generate listings +CPPFLAGS+=-Wa,-adhlmsn=${<:S/.c/.lst/} + +MCU?=at90s8515 +CFLAGS+=-mmcu=${MCU} + +LDFLAGS+=-Wl,-Map=${PROG}.map,--cref +LDFLAGS+=${LDADD} + +RM=rm -f + +PROGRAMMER=avrdude +PROGOPTS?=-p ${PART} -c alf -E vcc,noreset -q + +.if !defined(SRCS) +SRCS= ${PROG}.c +.endif + +OBJS+= ${SRCS:N*.h:R:S/$/.o/g} + +all: ${PROG}.hex ${PROG}.dmp + +.c.o: + ${CC} ${CFLAGS} ${CPPFLAGS} -c ${.IMPSRC} -o ${.PREFIX}.o + +${PROG}.elf: ${OBJS} + ${CC} ${CFLAGS} ${LDFLAGS} -g ${OBJS} -o ${PROG}.elf ${LDADD} + +.elf.hex: + ${OBJCOPY} -j .text -j .data -j .bss -j .noinit -O ihex $> $@ + +.elf.dmp: + ${OBJDUMP} -S ${.IMPSRC} > ${.PREFIX}.dmp + +clean: + ${RM} ${PROG}.hex ${PROG}.out ${PROG}.elf ${PROG}.map ${OBJS} ${OBJS:S/.o/.lst/} ${PROG}.dmp + +prog: all + ${PROGRAMMER} -U flash:w:${PROG}.hex ${PROGOPTS} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cons.c Wed Mar 11 16:42:27 2009 +1030 @@ -0,0 +1,179 @@ +/* + * Console code for AVR board + * + * Copyright (c) 2008 + * Daniel O'Connor <darius@dons.net.au>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + */ + +#include <ctype.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <avr/interrupt.h> +#include <avr/pgmspace.h> +#include "cons.h" + +#define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu)/((baudRate)*16l)-1) + +/* Receive buffer storage */ +consbuf_t cmd; + +/* + * Stub to use with fdevopen + * + * We ignore f and always succeed + */ +static int _putc(char c, FILE *f) { + cons_putc(c); + return(0); +} + +/* + * Stub to use with fdevopen + * + * We ignore f and always succeed + */ +static int _getc(FILE *f) { + return(cons_getc()); +} + +void +cons_init(void) { + UBRR0 = UART_BAUD_SELECT(38400, F_CPU); + + /* Enable receiver and transmitter. Turn on rx interrupts */ + UCSR0A = 0; + UCSR0B = _BV(RXEN0) | _BV(TXEN0) | _BV(RXCIE0); + UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); + + fdevopen(_putc, NULL); /* Open stdout */ + fdevopen(NULL, _getc); /* Open stdin */ +} + +int +cons_putc(char c) { + loop_until_bit_is_set(UCSR0A, UDRE0); + UDR0 = c; + + return(0); +} + +void +cons_putsP(const char *addr) { + char c; + + while ((c = pgm_read_byte_near(addr++))) + cons_putc(c); +} + +void +cons_puts(const char *addr) { + while (*addr) + cons_putc(*addr++); +} + +void +cons_puts_dec(uint8_t a, uint8_t l) { + char s[4]; + + if (l && a < 10) + cons_putsP(PSTR("0")); + cons_puts(utoa(a, s, 10)); +} + +void +cons_puts_hex(uint8_t a) { + char s[3]; + + if (a < 0x10) + cons_putc('0'); + + cons_puts(utoa(a, s, 16)); +} + +char +cons_getc(void) { + while (!(UCSR0A & _BV(RXC0))) + ; + + return (UDR0); +} + +/* Rx complete */ +ISR(USART0_RX_vect) { + volatile char pit; + char c; + + while (UCSR0A & _BV(RXC0)) { + /* 255 means we're waiting for main to process the command, + just throw stuff away + */ + if (cmd.state == 255) { + pit = UDR0; + continue; + } + c = UDR0; + + /* End of line? */ + if (c == '\n' || c == '\r') { + cmd.buf[cmd.state] = '\0'; + printf_P(PSTR("\r\n")); + cmd.len = cmd.state; + cmd.state = 255; + continue; + } + + /* Backspace/delete */ + if (c == 0x08 || c == 0x7f) { + if (cmd.state > 0) { + cmd.state--; + printf_P(PSTR("\010\040\010")); + } + continue; + } + + /* Anything unprintable just ignore it */ + if (!isprint(c)) + continue; + + cmd.buf[cmd.state] = tolower(c); + + /* Echo back to the user */ + cons_putc(cmd.buf[cmd.state]); + + cmd.state++; + /* Over flow? */ + if (cmd.state == ((sizeof(cmd.buf) / sizeof(cmd.buf[0])) - 1)) { + printf_P(PSTR("\r\nLine too long")); + cmd.state = 0; + continue; + } + } +} + +/* Tx complete */ +ISR(USART0_TX_vect) { + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cons.h Wed Mar 11 16:42:27 2009 +1030 @@ -0,0 +1,44 @@ +/* + * Console code headers + * + * Copyright (c) 2008 + * Daniel O'Connor <darius@dons.net.au>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + */ + +typedef volatile struct { + char buf[40]; + uint8_t state; + uint8_t len; +} consbuf_t; + +extern consbuf_t cmd; + +void cons_init(void); +void cons_putsP(const char *addr); +void cons_puts(const char *addr); +int cons_putc(char c); +void cons_puts_dec(uint8_t a, uint8_t l); +void cons_puts_hex(uint8_t a); +char cons_getc(void); +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ds1307.c Wed Mar 11 16:42:27 2009 +1030 @@ -0,0 +1,495 @@ +/* + * Interface to a DS1307 + * + * Copyright (c) 2008 + * Daniel O'Connor <darius@dons.net.au>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> +#include <avr/io.h> +#include <avr/pgmspace.h> +#include <util/twi.h> +#include <util/delay.h> + +#include "ds1307.h" + +// #define TWDEBUG + +/* + * ds1307_init + * + * Setup TWI interface + * + */ +int +ds1307_init(void) { + PRR &= _BV(PRTWI); /* Power TWI on - note that the + * datasheet says this is already 0 at + * power on.. */ + TWSR = 0; /* TWI Prescaler = 1 */ +#if F_CPU < 3600000UL + TWBR = 10; /* Smallest valid TWBR */ +#else + TWBR = (F_CPU / 100000UL - 16) / 2; +#endif + + TWCR = _BV(TWEN); + + return(0); +} + +/* + * iic_read + * + * Read len bytes of data from address adr in slave sla into + * data. Presume that the slave auto-increments the address on + * successive reads. + * + * Returns the number of bytes read, or the following on failure. + * IIC_STFAIL Could generate START condition (broken bus or busy). + * IIC_FAILARB Failed bus arbitration. + * IIC_SLNAK Slave NAK'd. + * IIC_NOREPLY No reply (no such slave?) + * IIC_UNKNOWN Unexpected return from TWI reg. + * + * Heaviy cribbed from twitest.c by Joerg Wunsch + */ +int8_t +iic_read(uint8_t *data, uint8_t len, uint8_t adr, uint8_t sla) { + uint8_t twst, twcr, cnt; + + /* Generate START */ + TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); + + /* Spin waiting for START to be generated */ + while ((TWCR & _BV(TWINT)) == 0) + ; + switch (twst = TW_STATUS) { + case TW_REP_START: /* OK but shouldn't happen */ + case TW_START: + break; + + case TW_MT_ARB_LOST: + return IIC_FAILARB; + break; + + default: + /* Not in start condition, bail */ + return IIC_UNKNOWN; + } +#ifdef TWDEBUG + printf_P(PSTR("Sent START\r\n")); +#endif + /* Send SLA+W */ + TWDR = sla | TW_WRITE; + TWCR = _BV(TWINT) | _BV(TWEN); + + /* Spin waiting for a response to be generated */ + while ((TWCR & _BV(TWINT)) == 0) + ; + +#ifdef TWDEBUG + printf_P(PSTR("Sent SLA+W\r\n")); +#endif + switch (twst = TW_STATUS) { + case TW_MT_SLA_ACK: + break; + + case TW_MT_SLA_NACK: + /* Send STOP */ + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); + return IIC_SLNAK; + + case TW_MT_ARB_LOST: + return IIC_FAILARB; + break; + + default: + /* Send STOP */ + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); + return IIC_UNKNOWN; + } + /* Send address */ + TWDR = adr; + TWCR = _BV(TWINT) | _BV(TWEN); + + /* Spin waiting for a response to be generated */ + while ((TWCR & _BV(TWINT)) == 0) + ; +#ifdef TWDEBUG + printf_P(PSTR("Sent address\r\n")); +#endif + switch ((twst = TW_STATUS)) { + case TW_MT_DATA_ACK: + break; + + case TW_MT_DATA_NACK: + /* Send STOP */ + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); + return IIC_SLNAK; + + case TW_MT_ARB_LOST: + return IIC_FAILARB; + + default: + /* Send STOP */ + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); + return IIC_UNKNOWN; + } + + /* Master receive cycle */ + TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); + while ((TWCR & _BV(TWINT)) == 0) /* wait for transmission */ + ; + +#ifdef TWDEBUG + printf_P(PSTR("Sent START\r\n")); +#endif + switch ((twst = TW_STATUS)) { + case TW_REP_START: /* OK but shouldn't happen */ + case TW_START: + break; + + case TW_MT_ARB_LOST: + return IIC_FAILARB; + + default: + /* Send STOP */ + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); + return IIC_UNKNOWN; + } + + /* send SLA+R */ + TWDR = sla | TW_READ; + TWCR = _BV(TWINT) | _BV(TWEN); /* clear interrupt to start transmission */ + + /* Spin waiting for a response to be generated */ + while ((TWCR & _BV(TWINT)) == 0) + ; +#ifdef TWDEBUG + printf_P(PSTR("Sent SLA+R\r\n")); +#endif + switch ((twst = TW_STATUS)) { + case TW_MR_SLA_ACK: + break; + + case TW_MR_SLA_NACK: + /* Send STOP */ + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); + return IIC_SLNAK; + + case TW_MR_ARB_LOST: + return IIC_FAILARB; + + default: + /* Send STOP */ + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); + return IIC_UNKNOWN; + } + + cnt = 0; + for (twcr = _BV(TWINT) | _BV(TWEN) | _BV(TWEA); + len > 0; len--) { + /* Send NAK on last byte */ + if (len == 1) + twcr = _BV(TWINT) | _BV(TWEN); + TWCR = twcr; /* clear int to start transmission */ + /* Spin waiting for a response to be generated */ + while ((TWCR & _BV(TWINT)) == 0) + ; +#ifdef TWDEBUG + printf_P(PSTR("Data request done\r\n")); +#endif + switch ((twst = TW_STATUS)) { + case TW_MR_DATA_NACK: + /* Send STOP */ + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); + //printf_P(PSTR("NACK on byte %d\r\n"), cnt); + return cnt; + + case TW_MR_DATA_ACK: + *data++ = TWDR; + //printf_P(PSTR("ACK on byte %d for 0x%02x\r\n"), cnt, *(data - 1)); + cnt++; + break; + + default: + return IIC_UNKNOWN; + } + } + + /* Send STOP */ + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); + return cnt; +} + +/* + * iic_write + * + * Write len bytes of data from address adr in slave sla into + * data. Presume that the slave auto-increments the address on + * successive writes. + * + * Returns the number of bytes read, or the following on failure. + * IIC_STFAIL Could generate START condition (broken bus or busy). + * IIC_FAILARB Failed bus arbitration. + * IIC_SLNAK Slave NAK'd. + * IIC_NOREPLY No reply (no such slave?) + * IIC_UNKNOWN Unexpected return from TWI reg. + * + * Heaviy cribbed from twitest.c by Joerg Wunsch + */ +int8_t +iic_write(uint8_t *data, uint8_t len, uint8_t adr, uint8_t sla) { + uint8_t twst, cnt; + + /* Generate START */ + TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); + + /* Spin waiting for START to be generated */ + while ((TWCR & _BV(TWINT)) == 0) + ; + switch (twst = TW_STATUS) { + case TW_REP_START: /* OK but shouldn't happen */ + case TW_START: + break; + + case TW_MT_ARB_LOST: + return IIC_FAILARB; + break; + + default: + /* Not in start condition, bail */ + return IIC_UNKNOWN; + } +#ifdef TWDEBUG + printf_P(PSTR("Sent START\r\n")); +#endif + + /* Send SLA+W */ + TWDR = sla | TW_WRITE; + TWCR = _BV(TWINT) | _BV(TWEN); + + /* Spin waiting for a response to be generated */ + while ((TWCR & _BV(TWINT)) == 0) + ; + +#ifdef TWDEBUG + printf_P(PSTR("Sent SLA+W\r\n")); +#endif + switch (twst = TW_STATUS) { + case TW_MT_SLA_ACK: + break; + + case TW_MT_SLA_NACK: + /* Send STOP */ + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); + return IIC_SLNAK; + + case TW_MT_ARB_LOST: + return IIC_FAILARB; + break; + + default: + /* Send STOP */ + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); + return IIC_UNKNOWN; + } + /* Send address */ + TWDR = adr; + TWCR = _BV(TWINT) | _BV(TWEN); + + /* Spin waiting for a response to be generated */ + while ((TWCR & _BV(TWINT)) == 0) + ; +#ifdef TWDEBUG + printf_P(PSTR("Sent address\r\n")); +#endif + switch ((twst = TW_STATUS)) { + case TW_MT_DATA_ACK: + break; + + case TW_MT_DATA_NACK: + /* Send STOP */ + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); + return IIC_SLNAK; + + case TW_MT_ARB_LOST: + return IIC_FAILARB; + + default: + /* Send STOP */ + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); + return IIC_UNKNOWN; + } + + cnt = 0; + for (; len > 0; len--) { + TWDR = *data++; + TWCR = _BV(TWINT) | _BV(TWEN); + + /* Spin waiting for a response to be generated */ + while ((TWCR & _BV(TWINT)) == 0) + ; +#ifdef TWDEBUG + printf_P(PSTR("Data sent\r\n")); +#endif + switch ((twst = TW_STATUS)) { + case TW_MT_DATA_NACK: + /* Send STOP */ + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); + return cnt; + + case TW_MT_DATA_ACK: + cnt++; + break; + + default: + return IIC_UNKNOWN; + } + } + + /* Send STOP */ + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); + return cnt; +} + +/* + * ds1307_gettod + * + * Read time of day from DS1307 into time + * + * Note that we canonify to 24hr mode. + * + */ +int8_t +ds1307_gettod(ds1307raw_t *time) { + int8_t len; + + len = iic_read((uint8_t *)time, sizeof(ds1307raw_t) + 1, 0, DS1307_ADR); + if (len < 0) { + printf_P(PSTR("iic_read failed - %d\r\n"), len); + return(0); + } + +#if 1 + if (len != sizeof(ds1307raw_t)) { + printf_P(PSTR("Only got %d bytes (vs %d)\r\n"), len, sizeof(ds1307raw_t)); + return(0); + } +#endif + +#ifdef TWDEBUG + int i; + + for (i = 0; i < len; i++) + printf_P(PSTR("0x%02x: 0x%02x\r\n"), i, *(((uint8_t *)time) + i)); +#endif + + return(1); +} + +/* + * ds1307_settod + * + * Set the DS1307 with the supplied time, format like so + * sc 2008/10/29 23:45:30 + * + */ +int8_t +ds1307_settod(char *date) { + ds1307raw_t rtime; + uint16_t year; + uint8_t i, month, day, hour, min, sec; + + if ((i = sscanf_P(date, PSTR("%hu/%hhd/%hhd %hhd:%hhd:%hhd"), &year, &month, &day, &hour, &min, &sec)) != 6) { + printf_P(PSTR("Can't parse date\r\n")); + return(0); + } + + if (year > 1900) + year -= 1900; + + rtime.split.year10 = year / 10; + rtime.split.year = year % 10; + rtime.split.month10 = month / 10; + rtime.split.month = month % 10; + rtime.split.day10 = day / 10; + rtime.split.day = day % 10; + rtime.split.pmam = ((hour / 10) & 0x02) >> 1; + rtime.split.hour10 = (hour / 10) & 0x01; + rtime.split.hour = hour % 10; + rtime.split.min10 = min / 10; + rtime.split.min = min % 10; + rtime.split.sec10 = sec / 10; + rtime.split.sec = sec % 10; + + rtime.split.ch = 0; // Enable clock + rtime.split.s1224 = 0; // 24 hour mode + rtime.split.dow = 0; // XXX: unused + rtime.split.out = 0; // No clock out + +#ifdef TWDEBUG + for (i = 0; i < sizeof(ds1307raw_t); i++) + printf_P(PSTR("0x%02x: 0x%02x\r\n"), i, *(((uint8_t *)&rtime) + i)); +#endif + if ((i = iic_write((uint8_t *)&rtime, sizeof(ds1307raw_t), 0, DS1307_ADR)) != sizeof(ds1307raw_t)) + printf_P(PSTR("Can't write to RTC, sent %d (vs %d)\r\n"), i, sizeof(ds1307raw_t)); + + return(1); +} + +/* + * ds1307_printtime + * + * Print the time in rtime with trailer + * + */ +void +ds1307_printtime(char *leader, char *trailer) { + ds1307raw_t rtime; + uint8_t hour; + + if (ds1307_gettod(&rtime) != 1) + return; + + // Handle 12/24 hour time + hour = rtime.split.hour10 * 10 + rtime.split.hour; + if (rtime.split.s1224) { + if (rtime.split.pmam) + hour += 12; + } else + hour += (rtime.split.pmam << 1) * 10; + + printf_P(PSTR("%S%04d/%02d/%02d %02d:%02d:%02d%S"), leader, + 1900 + rtime.split.year10 * 10 + rtime.split.year, + rtime.split.month10 * 10 + rtime.split.month, + rtime.split.day10 * 10 + rtime.split.day, + hour, + rtime.split.min10 * 10 + rtime.split.min, + rtime.split.sec10 * 10 + rtime.split.sec, + trailer); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ds1307.h Wed Mar 11 16:42:27 2009 +1030 @@ -0,0 +1,93 @@ +/* + * DS1307 headers + * + * Copyright (c) 2008 + * Daniel O'Connor <darius@dons.net.au>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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 IIC_STFAIL -1 +#define IIC_FAILARB -2 +#define IIC_SLNAK -3 +#define IIC_NOREPLY -4 +#define IIC_UNKNOWN -99 + +#define DS1307_ADR 0xd0 // DS1307's TWI address + +typedef struct { + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t min; + uint8_t sec; + + uint8_t ctrl; + uint8_t ram[56]; +} ds1307_t; + +typedef union { + uint8_t raw[8]; + struct { + uint8_t sec : 4; + uint8_t sec10 : 3; // Seconds (0-59) + uint8_t ch : 1; // Clock enable (1 = off) + + uint8_t min : 4; + uint8_t min10 : 3; // Minutes (0-59) + uint8_t pad0 : 1; + + uint8_t hour : 4; + uint8_t hour10 : 1; // Hours + uint8_t pmam : 1; // AM/PM => 1 = PM or extra bit for hour10 + uint8_t s1224 : 1; // 1 = 12 hour mode + uint8_t pad1 : 1; + + uint8_t dow : 3; // Day of the week (1-7) + uint8_t pad2 : 5; + + uint8_t day : 4; + uint8_t day10 : 2; // Day of the month (1-31) + uint8_t pad3 : 2; + + uint8_t month : 4; + uint8_t month10 : 1; + uint8_t pad4 : 3; // Month (1-12) + + uint8_t year : 4; + uint8_t year10 : 4; // Year (0-99) + + uint8_t rs : 2; // Rate select + uint8_t pad6 : 2; + uint8_t sqwe : 1; // Square wave enable + uint8_t pad5 : 2; + uint8_t out : 1; // Output control enable + } split; +} ds1307raw_t; + +int ds1307_init(void); +int8_t iic_read(uint8_t *data, uint8_t len, uint8_t adr, uint8_t sla); +int8_t iic_write(uint8_t *data, uint8_t len, uint8_t adr, uint8_t sla); +int8_t ds1307_gettod(ds1307raw_t *time); +int8_t ds1307_settod(char *date); +void ds1307_printtime(char *leader, char *trailer);