--- /dev/null
+# Copyright 2014 Doug Szumski <d.s.szumski@gmail.com>
+# Copyright 2008-2011 Michel Pollet <buserror@gmail.com>
+#
+# This file is part of simavr.
+#
+# simavr is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# simavr is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with simavr. If not, see <http://www.gnu.org/licenses/>.
+
+target= ds1338demo
+firm_src = ${wildcard at*${board}.c}
+firmware = ${firm_src:.c=.axf}
+simavr = ../../
+
+IPATH = .
+IPATH += ../parts
+IPATH += ${simavr}/include
+IPATH += ${simavr}/simavr/sim
+
+VPATH = .
+VPATH += ../parts
+
+LDFLAGS += -lpthread
+
+all: obj atmega32_ds1338.axf ${target}
+
+atmega32_ds1338.axf: atmega32_ds1338.c ds1338.c twimaster.c
+
+include ${simavr}/Makefile.common
+
+board = ${OBJ}/${target}.elf
+
+${board} : ${OBJ}/ac_input.o
+${board} : ${OBJ}/ds1338_virt.o
+${board} : ${OBJ}/${target}.o
+
+${target}: ${board}
+ @echo $@ done
+
+clean: clean-${OBJ}
+ rm -rf *.hex *.a *.axf ${target} *.vcd .*.swo .*.swp .*.swm .*.swn
--- /dev/null
+/*
+ atmega32_ds1338.c
+
+ Copyright 2014 Doug Szumski <d.s.szumski@gmail.com>
+
+ This file is part of simavr.
+
+ simavr is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ simavr is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with simavr. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <avr/io.h>
+#include <avr/sleep.h>
+#include <avr/interrupt.h>
+#include <util/delay.h>
+
+#include <stdio.h>
+
+#undef F_CPU
+#define F_CPU 7380000
+
+#include "avr_mcu_section.h"
+AVR_MCU(F_CPU, "atmega32");
+
+#include "ds1338.h"
+#include "i2cmaster.h"
+
+volatile uint8_t update_flag;
+
+/*
+ * This demo consists of a DS1338 RTC connected via the TWI bus
+ * of an atmega32. The square wave output of the DS1338 is
+ * enabled, with the tick-rate set to 1HZ. This is then fed
+ * to pin D3 on the atmega32 which is configured to generate
+ * an interrupt on a rising edge. When the interrupt fires the
+ * time is read from the DS1338.
+ */
+
+int
+main()
+{
+ i2c_init();
+
+ /*
+ * Demonstrate the virtual part functionality.
+ */
+ ds1338_init();
+ ds1338_time_t time = {
+ .date = 31,
+ .day = 6,
+ .hours = 23,
+ .minutes = 59,
+ .month = 12,
+ .seconds = 56,
+ .year = 14,
+ };
+ ds1338_set_time(&time);
+
+ // Setup pin change interrupt for the square wave output
+ cli();
+ DDRD &= ~(1 << PD3);
+ // Fire INT1 on the rising edge
+ MCUCR |= (1 << ISC11) | (1 << ISC10);
+ GICR |= (1 << INT1);
+ sei();
+
+ while(time.seconds != 2)
+ {
+ if (update_flag) {
+ ds1338_get_time(&time);
+ update_flag = 0;
+ }
+ }
+
+ cli();
+ sleep_mode();
+
+}
+
+ISR (INT1_vect)
+{
+ update_flag = 1;
+}
--- /dev/null
+/*
+ ds1338.c
+
+ DS1338 / DS1307 I2C clock module driver
+
+ Copyright 2012, 2014 Doug Szumski <d.s.szumski@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>
+ */
+
+#include <stdint.h>
+
+#include "ds1338.h"
+#include "i2cmaster.h"
+
+static void
+ds1338_write(const uint8_t reg, const uint8_t data)
+{
+ i2c_start(DS1338_TWI_ADR + I2C_WRITE);
+ i2c_write(reg);
+ i2c_write(data);
+ i2c_stop();
+}
+
+static uint8_t
+ds1338_read(const uint8_t reg)
+{
+ i2c_start(DS1338_TWI_ADR + I2C_WRITE);
+ i2c_write(reg);
+ i2c_rep_start(DS1338_TWI_ADR + I2C_READ);
+ uint8_t data = i2c_readNak();
+ i2c_stop();
+
+ return data;
+}
+
+void
+ds1338_init(void)
+{
+ ds1338_write(DS1338_CONTROL, DS1338_CONTROL_SETTING);
+ // Set the CS bit to zero to enable clock
+ uint8_t data = ds1338_read(DS1338_SECONDS);
+ data &= ~(1 << DS1338_CH);
+ ds1338_write(DS1338_SECONDS, data);
+}
+
+void
+ds1338_get_time(ds1338_time_t * const time)
+{
+ uint8_t data = ds1338_read(DS1338_SECONDS);
+ time->seconds = 10 * ((data & 0b01110000) >> 4) + (data & 0x0F);
+
+ data = ds1338_read(DS1338_MINUTES);
+ time->minutes = UNPACK_BCD(data);
+
+ data = ds1338_read(DS1338_HOURS);
+ if (data & (1 << DS1338_12_24_HR))
+ {
+ // 12 hour mode
+ time->hours = 10 * ((data & 0b00010000) >> 4) + (data & 0x0F);
+ time->is_pm = data & (1 << DS1338_AM_PM);
+ } else {
+ // 24 hour mode
+ time->hours = 10 * ((data & 0b00110000) >> 4) + (data & 0x0F);
+ }
+
+ data = ds1338_read(DS1338_DAY);
+ // Shift day so that it's 0-6, not 1-7
+ time->day = data - 1;
+
+ data = ds1338_read(DS1338_DATE);
+ time->date = UNPACK_BCD(data);
+
+ data = ds1338_read(DS1338_MONTH);
+ time->month = UNPACK_BCD(data);
+
+ data = ds1338_read(DS1338_YEAR);
+ time->year = UNPACK_BCD(data);
+}
+
+void
+ds1338_set_time(const ds1338_time_t * const time)
+{
+ // Should always write zero to the CS bit to enable the clock
+ ds1338_write(DS1338_SECONDS, TO_BCD(time->seconds));
+ ds1338_write(DS1338_MINUTES, TO_BCD(time->minutes));
+
+ uint8_t hour_reg = ds1338_read(DS1338_HOURS);
+ // Wipe everything apart from the 12/24 hour bit
+ hour_reg &= ~(0b00111111);
+ if ((hour_reg & (1 << DS1338_12_24_HR)) && (time->is_pm)) {
+ // 12 hour mode and it's PM
+ hour_reg |= (1 << DS1338_AM_PM);
+ }
+ hour_reg |= TO_BCD(time->hours);
+ ds1338_write(DS1338_HOURS, hour_reg);
+
+ // Shift back day from 0-6 to 1-7.
+ ds1338_write(DS1338_DAY, time->day + 1);
+ ds1338_write(DS1338_DATE, TO_BCD(time->date));
+ ds1338_write(DS1338_MONTH, TO_BCD(time->month));
+ ds1338_write(DS1338_YEAR, TO_BCD(time->year));
+}
--- /dev/null
+/*
+ ds1338.h
+
+ DS1338 / DS1307 I2C clock module driver
+
+ Copyright 2012, 2014 Doug Szumski <d.s.szumski@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>
+ */
+
+/*
+ * A simple driver to interface with the DS1338. Should work with
+ * the pin compatible DS1307 too.
+ *
+ * TODO:
+ *
+ * > Read/write registers sequentially to/from an array.
+ * > Add a function to check the 'oscillator had a problem flag'
+ * > Add a function to configure the square wave output
+ * > Add a function to allow writing to additional NVRAM
+ * > Use bit fields to save RAM when storing time
+ */
+
+#ifndef DS1338_H
+#define DS1338_H
+
+/*
+ * Internal registers. Time is in BCD.
+ * See p10 of the DS1388 datasheet.
+ */
+#define DS1338_TWI_ADR 0xD0
+#define DS1338_SECONDS 0x00
+#define DS1338_MINUTES 0x01
+#define DS1338_HOURS 0x02
+#define DS1338_DAY 0x03
+#define DS1338_DATE 0x04
+#define DS1338_MONTH 0x05
+#define DS1338_YEAR 0x06
+#define DS1338_CONTROL 0x07
+
+/*
+ * Seconds register flag - oscillator is enabled when
+ * this is set to zero. Undefined on startup.
+ */
+#define DS1338_CH 7
+
+/*
+ * 12/24 hour select bit. When high clock is in 12 hour
+ * mode and the AM/PM bit is operational. When low the
+ * AM/PM bit becomes part of the tens counter for the
+ * 24 hour clock.
+ */
+#define DS1338_12_24_HR 6
+
+/*
+ * AM/PM flag for 12 hour mode. PM is high.
+ */
+#define DS1338_AM_PM 5
+
+// Control register settings: 1Hz square wave out
+#define DS1338_CONTROL_SETTING 0b10010000
+// 4kHz
+//#define DS1338_CONTROL_SETTING 0b10010001
+// 8 kHz
+//#define DS1338_CONTROL_SETTING 0b10010010
+// 32kHz
+//#define DS1338_CONTROL_SETTING 0b10010011
+
+// Generic BCD conversion. Don't use on seconds or hours.
+#define UNPACK_BCD(x) (((x) & 0x0F) + ((x) >> 4) * 10)
+#define TO_BCD(x) ((((x) / 10) << 4) + (x) % 10)
+
+typedef struct ds1338_time_t
+{
+ uint8_t seconds;
+ uint8_t minutes;
+ uint8_t hours;
+ uint8_t is_pm;
+ uint8_t day; // Runs from 0-6
+ uint8_t date;
+ uint8_t month;
+ uint8_t year;
+} ds1338_time_t;
+
+void
+ds1338_init (void);
+
+void
+ds1338_get_time (ds1338_time_t * const time);
+
+void
+ds1338_set_time (const ds1338_time_t * const time);
+
+#endif //DS1338_H
--- /dev/null
+/*
+ ds1338_demo.c
+
+ Copyright 2014 Doug Szumski <d.s.szumski@gmail.com>
+ Copyright 2011 Michel Pollet <buserror@gmail.com>
+
+ This file is part of simavr.
+
+ simavr is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ simavr is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with simavr. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <libgen.h>
+
+#include "sim_avr.h"
+#include "avr_twi.h"
+#include "sim_elf.h"
+#include "sim_gdb.h"
+#include "ds1338_virt.h"
+
+avr_t * avr = NULL;
+ds1338_virt_t ds1338_virt;
+
+int main(int argc, char *argv[])
+{
+ elf_firmware_t f;
+ const char * fname = "atmega32_ds1338.axf";
+
+ printf("Firmware pathname is %s\n", fname);
+ elf_read_firmware(fname, &f);
+
+ printf("firmware %s f=%d mmcu=%s\n", fname, (int)f.frequency, f.mmcu);
+
+ avr = avr_make_mcu_by_name(f.mmcu);
+ if (!avr) {
+ fprintf(stderr, "%s: AVR '%s' not known\n", argv[0], f.mmcu);
+ exit(1);
+ }
+ avr_init(avr);
+ avr_load_firmware(avr, &f);
+
+ // Initialise our 'peripheral'
+ ds1338_virt_init(avr, &ds1338_virt);
+
+ // Hook up the TWI bus
+ ds1338_virt_attach_twi(&ds1338_virt, AVR_IOCTL_TWI_GETIRQ(0));
+
+ // Connect the square wave output
+ ds1338_pin_t wiring = {
+ .port = 'D',
+ .pin = 3
+ };
+ ds1338_virt_attach_square_wave_output (&ds1338_virt, &wiring);
+
+ // Even if not setup at startup, activate gdb if crashing
+ avr->gdb_port = 1234;
+ if (0) {
+ avr->state = cpu_Stopped;
+ avr_gdb_init(avr);
+ }
+
+ printf( "\nDS1338 demo launching:\n");
+
+ // Enable debug info
+ // TODO: Convert to logger?
+ ds1338_virt.verbose = 1;
+
+ int state = cpu_Running;
+ while ((state != cpu_Done) && (state != cpu_Crashed))
+ state = avr_run(avr);
+}