]> cloudbase.mooo.com Git - z180-stamp.git/commitdiff
Add date rtc i2c
authorLeo C <erbl259-lmu@yahoo.de>
Sat, 23 Aug 2014 17:34:22 +0000 (19:34 +0200)
committerLeo C <erbl259-lmu@yahoo.de>
Sat, 23 Aug 2014 17:34:22 +0000 (19:34 +0200)
15 files changed:
avr/Tupfile
avr/cmd_date.c [new file with mode: 0644]
avr/command_tbl.c
avr/date.c [new file with mode: 0644]
avr/debug.c
avr/i2c.c [new file with mode: 0644]
avr/main.c
avr/pcf8583.c [new file with mode: 0644]
include/cmd_mem.h
include/common.h
include/config.h
include/crc.h
include/debug.h
include/i2c.h [new file with mode: 0644]
include/rtc.h [new file with mode: 0644]

index 60022d64e0a4accb231f5b0362aa76f1ddf5be87..d0bed48da3f95ac109844329b4035caeab0d4323 100644 (file)
@@ -3,9 +3,9 @@ include_rules
 PROG           = stamp-test
 SRC            = main.c
 SRC            += cli.c cli_readline.c command.c command_tbl.c
-SRC            += cmd_help.c cmd_echo.c cmd_mem.c cmd_boot.c
-SRC            += env.c xmalloc.c
-SRC            += timer.c con-utils.c serial.c
+SRC            += cmd_help.c cmd_echo.c cmd_date.c cmd_mem.c cmd_boot.c
+SRC            += env.c xmalloc.c date.c
+SRC            += timer.c con-utils.c serial.c i2c.c pcf8583.c
 SRC            += background.c z180-serv.c z80-if.c
 
 SRC_Z          = ../z180/hdrom.c
diff --git a/avr/cmd_date.c b/avr/cmd_date.c
new file mode 100644 (file)
index 0000000..bc93efc
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/*
+ * RTC, Date & Time support: get and set date & time
+ */
+#include <common.h>
+#include <string.h>
+#include <avr/pgmspace.h>
+#include <command.h>
+#include <rtc.h>
+#include <i2c.h>
+
+
+static const char * const weekdays[] = {
+       "Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur",
+};
+
+int mk_date (const char *, struct rtc_time *);
+
+command_ret_t do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct rtc_time tm;
+       int rcode = CMD_RET_SUCCESS;
+       
+       (void) cmdtp; (void) flag;
+
+       switch (argc) {
+       case 2:                 /* set date & time */
+               if (strcmp_P(argv[1],PSTR("reset")) == 0) {
+                       my_puts_P(PSTR("Reset RTC...\n"));
+                       rtc_reset ();
+               } else {
+                       /* initialize tm with current time */
+                       rcode = rtc_get (&tm);
+
+                       if(!rcode) {
+                               /* insert new date & time */
+                               if (mk_date (argv[1], &tm) != 0) {
+                                       my_puts_P(PSTR("## Bad date format\n"));
+                                       break;
+                               }
+                               /* and write to RTC */
+                               rcode = rtc_set (&tm);
+                               if(rcode)
+                                       my_puts_P(PSTR("## Set date failed\n"));
+                       } else {
+                               my_puts_P(PSTR("## Get date failed\n"));
+                       }
+               }
+               /* FALL TROUGH */
+       case 1:                 /* get date & time */
+               rcode = rtc_get (&tm);
+
+               if (rcode) {
+                       my_puts_P(PSTR("## Get date failed\n"));
+                       break;
+               }
+               /* TODO: flash */
+               printf_P(PSTR("Date: %4d-%02d-%02d (%sday)    Time: %2d:%02d:%02d\n"),
+                       tm.tm_year, tm.tm_mon, tm.tm_mday,
+                       (tm.tm_wday<0 || tm.tm_wday>6) ?
+                               "unknown " : weekdays[tm.tm_wday],
+                       tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+               break;
+       default:
+               rcode = CMD_RET_USAGE;
+       }
+
+       return rcode;
+}
+
+/*
+ * simple conversion of two-digit string with error checking
+ */
+static int cnvrt2 (const char *str, int *valp)
+{
+       int val;
+
+       if ((*str < '0') || (*str > '9'))
+               return (-1);
+
+       val = *str - '0';
+
+       ++str;
+
+       if ((*str < '0') || (*str > '9'))
+               return (-1);
+
+       *valp = 10 * val + (*str - '0');
+
+       return (0);
+}
+
+/*
+ * Convert date string: MMDDhhmm[[CC]YY][.ss]
+ *
+ * Some basic checking for valid values is done, but this will not catch
+ * all possible error conditions.
+ */
+int mk_date (const char *datestr, struct rtc_time *tmp)
+{
+       int len, val;
+       char *ptr;
+
+       ptr = strchr (datestr,'.');
+       len = strlen (datestr);
+
+       /* Set seconds */
+       if (ptr) {
+               int sec;
+
+               *ptr++ = '\0';
+               if ((len - (ptr - datestr)) != 2)
+                       return (-1);
+
+               len = strlen (datestr);
+
+               if (cnvrt2 (ptr, &sec))
+                       return (-1);
+
+               tmp->tm_sec = sec;
+       } else {
+               tmp->tm_sec = 0;
+       }
+
+       if (len == 12) {                /* MMDDhhmmCCYY */
+               int year, century;
+
+               if (cnvrt2 (datestr+ 8, &century) ||
+                   cnvrt2 (datestr+10, &year) ) {
+                       return (-1);
+               }
+               tmp->tm_year = 100 * century + year;
+       } else if (len == 10) {         /* MMDDhhmmYY   */
+               int year, century;
+
+               century = tmp->tm_year / 100;
+               if (cnvrt2 (datestr+ 8, &year))
+                       return (-1);
+               tmp->tm_year = 100 * century + year;
+       }
+
+       switch (len) {
+       case 8:                 /* MMDDhhmm     */
+               /* fall thru */
+       case 10:                /* MMDDhhmmYY   */
+               /* fall thru */
+       case 12:                /* MMDDhhmmCCYY */
+               if (cnvrt2 (datestr+0, &val) ||
+                   val > 12) {
+                       break;
+               }
+               tmp->tm_mon  = val;
+               if (cnvrt2 (datestr+2, &val) ||
+                   val > ((tmp->tm_mon==2) ? 29 : 31)) {
+                       break;
+               }
+               tmp->tm_mday = val;
+
+               if (cnvrt2 (datestr+4, &val) ||
+                   val > 23) {
+                       break;
+               }
+               tmp->tm_hour = val;
+
+               if (cnvrt2 (datestr+6, &val) ||
+                   val > 59) {
+                       break;
+               }
+               tmp->tm_min  = val;
+
+               /* calculate day of week */
+               GregorianDay (tmp);
+
+               return (0);
+       default:
+               break;
+       }
+
+       return (-1);
+}
+
index 2fb41b9b833145b85d24fb784b4532a49110f92f..6fcbee71472026acf229e08a8be6a7c34597112f 100644 (file)
@@ -16,10 +16,20 @@ extern command_ret_t do_restart(cmd_tbl_t *, int, int, char * const []);
 extern command_ret_t do_dump_mem(cmd_tbl_t *, int, int, char * const []);
 extern command_ret_t do_eep_cp(cmd_tbl_t *, int, int, char * const []);
 extern command_ret_t do_busreq_pulse(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_date(cmd_tbl_t *, int, int, char * const []);
 
 
 cmd_tbl_t cmd_tbl[] = {
 
+CMD_TBL_ITEM(
+       date,   2,      1,      do_date,
+       "get/set/reset date & time",
+       "[MMDDhhmm[[CC]YY][.ss]]\ndate reset\n"
+       "  - without arguments: print date & time\n"
+       "  - with numeric argument: set the system date & time\n"
+       "  - with 'reset' argument: reset the RTC"
+),
+
 #ifdef DEBUG
 CMD_TBL_ITEM(
        !mdr,   3,      1,      do_dump_mem,
diff --git a/avr/date.c b/avr/date.c
new file mode 100644 (file)
index 0000000..c85361f
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/*
+ * Date & Time support for RTC
+ */
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+
+
+#define FEBRUARY               2
+#define        STARTOFTIME             1970
+#define SECDAY                 86400L
+#define SECYR                  (SECDAY * 365)
+#define        leapyear(year)          ((year) % 4 == 0)
+#define        days_in_year(a)         (leapyear(a) ? 366 : 365)
+#define        days_in_month(a)        (month_days[(a) - 1])
+
+
+static const FLASH int MonthOffset[] = { 
+       0,31,59,90,120,151,181,212,243,273,304,334
+};
+
+/*
+ * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
+ */
+void GregorianDay(struct rtc_time * tm)
+{
+       int leapsToDate;
+       int lastYear;
+       int day;
+
+       lastYear=tm->tm_year-1;
+
+       /*
+        * Number of leap corrections to apply up to end of last year
+        */
+       leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;
+
+       /*
+        * This year is a leap year if it is divisible by 4 except when it is
+        * divisible by 100 unless it is divisible by 400
+        *
+        * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be
+        */
+       if((tm->tm_year%4==0) &&
+          ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) &&
+          (tm->tm_mon>2)) {
+               /*
+                * We are past Feb. 29 in a leap year
+                */
+               day=1;
+       } else {
+               day=0;
+       }
+
+       day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday;
+
+       tm->tm_wday=day%7;
+}
+
+void to_tm(unsigned long tim, struct rtc_time * tm)
+{
+       char month_days[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
+       register int    i;
+       register long   hms, day;
+
+       day = tim / SECDAY;
+       hms = tim % SECDAY;
+
+       /* Hours, minutes, seconds are easy */
+       tm->tm_hour = hms / 3600;
+       tm->tm_min = (hms % 3600) / 60;
+       tm->tm_sec = (hms % 3600) % 60;
+
+       /* Number of years in days */
+       for (i = STARTOFTIME; day >= days_in_year(i); i++) {
+               day -= days_in_year(i);
+       }
+       tm->tm_year = i;
+
+       /* Number of months in days left */
+       if (leapyear(tm->tm_year)) {
+               days_in_month(FEBRUARY) = 29;
+       }
+       for (i = 1; day >= days_in_month(i); i++) {
+               day -= days_in_month(i);
+       }
+       days_in_month(FEBRUARY) = 28;
+       tm->tm_mon = i;
+
+       /* Days are what is left over (+1) from all that. */
+       tm->tm_mday = day + 1;
+
+       /*
+        * Determine the day of week
+        */
+       GregorianDay(tm);
+}
+
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+unsigned long
+mktime (unsigned int year, unsigned int mon,
+       unsigned int day, unsigned int hour,
+       unsigned int min, unsigned int sec)
+{
+       if (0 >= (int) (mon -= 2)) {    /* 1..12 -> 11,12,1..10 */
+               mon += 12;              /* Puts Feb last since it has leap day */
+               year -= 1;
+       }
+
+       return (((
+               (unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) +
+                       year*365 - 719499
+           )*24 + hour /* now have hours */
+         )*60 + min /* now have minutes */
+       )*60 + sec; /* finally seconds */
+}
+
index fcbd2c107011760654cf12a862573b4353335207..16df702d0a0949a47bd6c058ca4e844374fa3f0f 100644 (file)
@@ -12,8 +12,6 @@
  */
 #ifdef DEBUG
 
-//uint8_t eeprom_read_byte (const uint8_t *__p)
-
 static void print_blanks(uint_fast8_t count)
 {
        while(count--)
@@ -29,14 +27,17 @@ void dump_mem(const uint8_t *startaddr, int len,
                uint8_t (*readfkt)(const uint8_t *), char *title)
 {
        uint8_t buf[16];
+       char *indent = NULL;
        uint8_t llen = 16;
        uint8_t pre = (size_t) startaddr % 16;
        const uint8_t *addr = (uint8_t *) ((size_t) startaddr & ~0x0f);
        len += pre;
        uint8_t i;
        
-       if (title && *title)
+       if (title && *title) {
                printf_P(PSTR("%s\n"),title);
+               indent = "    ";
+       }
                
        while (len) {
                if (len < 16)
@@ -45,7 +46,7 @@ void dump_mem(const uint8_t *startaddr, int len,
                for (i = pre; i < llen; i++)
                        buf[i] = readfkt(addr + i);
 
-               printf_P(PSTR("%04x:"), addr);
+               printf_P(PSTR("%s%04x:"),indent, addr);
                for (i = 0; i < llen; i++) {
                        if ((i % 8) == 0)
                                putchar(' ');
@@ -67,37 +68,17 @@ void dump_mem(const uint8_t *startaddr, int len,
        }
 }
 
-#if 0
-void dump_ram(const uint8_t *startaddr, int len, char *title)
+void dump_eep(const uint8_t *addr, unsigned int len, char *title)
 {
-       uint8_t llen = 16;
-       uint8_t pre = (size_t) startaddr % 16;
-       const uint8_t *addr = (uint8_t *) ((size_t) startaddr & ~0x0f);
-       len += pre;
-       uint8_t i;
-
-       if (title && *title)
-               printf_P(PSTR("%s\n"),title);
+       dump_mem(addr, len, eeprom_read_byte, title);
+}
 
-       while (len) {
-               if (len < 16)
-                       llen = len;
+void dump_ram(const uint8_t *addr, unsigned int len, char *title)
+{
+       dump_mem(addr, len, ram_read_byte, title);
+}
 
-               printf_P(PSTR("    %.4x:"), (size_t) addr);
-               print_blanks(3 * pre);
-               for (i = pre; i < llen; i++)
-                       printf_P(PSTR(" %.2x"), addr[i]);
-               print_blanks(3 * (16 - i + 1) + pre);
-               for (i = pre; i < llen; i++)
-                       printf_P(PSTR("%c"), isprint(addr[i]) ? addr[i] : '.');
-               putchar('\n');
 
-               pre = 0;
-               addr += 16;
-               len -= llen;
-       }
-}
-#endif
 #if 0
 void dump_heap(void)
 {
@@ -109,35 +90,9 @@ void dump_heap(void)
 }
 #endif
 
-#if 0
-/* TODO: combine with dump_ram() */
-void dump_eep(const uint8_t *addr, unsigned int len, 
-                       uint8_t (*readfkt)(const uint8_t *))
-{
-       uint_fast8_t i;
-       uint8_t buf[16];
-
-       printf_P(PSTR("eeprom dump:"));
-       while (len) {
-               printf_P(PSTR("\n    0x%.4x:"), (unsigned int) addr);
-               for (i = 0; i<16; i++)
-                       buf[i] = readfkt(addr + i);
-               for (i = 0; i<16; i++)
-                       printf_P(PSTR(" %.2x"), buf[i]);
-               printf_P(PSTR("   "));
-               for (i = 0; i<16; i++)
-                       printf_P(PSTR("%c"), isprint(buf[i]) ? buf[i] : '.');
-
-               addr += 16;
-               len -= len > 16 ? 16 : len;
-       }
-       putchar('\n');
-}
-#endif
-
 
 /*
- * EEPROM Display
+ * Memory Display
  *     md addr {len}
  */
 command_ret_t do_dump_mem(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
diff --git a/avr/i2c.c b/avr/i2c.c
new file mode 100644 (file)
index 0000000..df97fea
--- /dev/null
+++ b/avr/i2c.c
@@ -0,0 +1,389 @@
+
+/* 
+ * I2C (TWI) master interface. 
+ */
+
+#include "common.h"
+#include <avr/interrupt.h>
+#include <util/delay.h>
+#include <string.h>
+
+#include "config.h"
+#include "timer.h"
+#include "debug.h"
+#include "i2c.h"
+
+#ifdef DEBUG
+//# define DEBUG_I2C
+#endif
+
+/* General TWI Master status codes */
+#define TWI_START                  0x08  /* START has been transmitted */
+#define TWI_REP_START              0x10  /* Repeated START has been transmitted */
+#define TWI_ARB_LOST               0x38  /* Arbitration lost */
+
+/* TWI Master Transmitter status codes */
+#define TWI_MTX_ADR_ACK            0x18  /* SLA+W has been transmitted and ACK received */
+#define TWI_MTX_ADR_NACK           0x20  /* SLA+W has been transmitted and NACK received */
+#define TWI_MTX_DATA_ACK           0x28  /* Data byte has been transmitted and ACK received */
+#define TWI_MTX_DATA_NACK          0x30  /* Data byte has been transmitted and NACK received */
+
+/* TWI Master Receiver status codes */
+#define TWI_MRX_ADR_ACK            0x40  /* SLA+R has been transmitted and ACK received */
+#define TWI_MRX_ADR_NACK           0x48  /* SLA+R has been transmitted and NACK received */
+#define TWI_MRX_DATA_ACK           0x50  /* Data byte has been received and ACK transmitted */
+#define TWI_MRX_DATA_NACK          0x58  /* Data byte has been received and NACK transmitted */
+
+/* TWI Miscellaneous status codes */
+#define TWI_NO_STATE               0xF8  /* No relevant state information available */
+#define TWI_BUS_ERROR              0x00  /* Bus error due to an illegal START or STOP condition */
+
+
+/*
+ * TWINT: TWI Interrupt Flag
+ * TWEA:  TWI Enable Acknowledge Bit
+ * TWSTA: TWI START Condition Bit
+ * TWSTO: TWI STOP Condition Bit
+ * TWEN:  TWI Enable Bit
+ * TWIE:  TWI Interrupt Enable
+ * 
+ *     (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
+ *     (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|           (1<<TWEA)
+ *     (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
+ * 
+ * default:
+ *     (1<<TWEN)|          (1<<TWINT)|           (1<<TWSTO)
+ * 
+ * Init:
+ *     (1<<TWEN)
+ * 
+ * start read/write:
+ *     (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+ *     (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+ *     (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+ *     (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+ * 
+ * wait ready:
+ *      (1<<TWIE)|(1<<TWSTO)
+ *
+ *
+ *
+ *i2c_result   
+ *
+ *     0b10000000      Busy (Transmission in progress)
+ *     0b01000000      Timeout
+ *     0b00001000      Start transmitted 
+ *     0b00000100      Slave acknowledged address
+ *     0b00000010      Data byte(s) transmitted/received
+ *     0b00000001      Transmission completed
+ *
+ *
+ *----------------------------------------------------------------------
+ */
+
+#define TWI_C_DISABLE          0x00
+#define TWI_C_ENABLE           (1<<TWEN)
+
+ typedef struct i2c_msg_s {
+       uint8_t stat;
+ #define XMIT_DONE     (1<<0)
+ #define DATA_ACK      (1<<1)
+ #define ADDR_ACK      (1<<2)
+ #define START         (1<<3)
+ #define TIMEOUT       (1<<6)
+ #define BUSY          (1<<7)
+       uint8_t idx;
+       uint8_t len;
+       uint8_t buf[CONFIG_SYS_I2C_BUFSIZE];
+} i2c_msg_t;
+
+static i2c_msg_t xmit;
+
+ISR(TWI_vect)
+{
+       uint8_t next_twcr;
+       uint8_t tmp_idx;
+
+       uint8_t twsr = TWSR;
+               
+       switch (twsr & 0xf8) {
+
+       case TWI_START:
+       case TWI_REP_START:
+               xmit.idx = 0;                   /* reset xmit_buf index */
+               xmit.stat = BUSY | START;
+
+               tmp_idx = xmit.idx;
+               if (tmp_idx < xmit.len) {               /* all bytes transmited? */
+                       TWDR = xmit.buf[tmp_idx];
+                       xmit.idx = ++tmp_idx;
+                       next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
+               } else {
+                       xmit.stat |= XMIT_DONE;
+                       xmit.stat &= ~BUSY;
+                       next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
+               }
+               break;
+
+       case TWI_MTX_ADR_ACK:
+               xmit.stat |= ADDR_ACK;
+               
+               tmp_idx = xmit.idx;
+               if (tmp_idx < xmit.len) {               /* all bytes transmited? */
+                       TWDR = xmit.buf[tmp_idx];
+                       xmit.idx = ++tmp_idx;
+                       next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
+               } else {
+                       xmit.stat |= XMIT_DONE;
+                       xmit.stat &= ~BUSY;
+                       next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
+               }
+               break;
+
+       case TWI_MTX_DATA_ACK:
+               xmit.stat |= DATA_ACK;
+
+               tmp_idx = xmit.idx;
+               if (tmp_idx < xmit.len) {               /* all bytes transmited? */
+                       TWDR = xmit.buf[tmp_idx];
+                       xmit.idx = ++tmp_idx;
+                       next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
+               } else {
+                       xmit.stat |= XMIT_DONE;
+                       xmit.stat &= ~BUSY;
+                       next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
+               }
+
+               break;
+
+       case TWI_MTX_DATA_NACK:
+               xmit.stat |= XMIT_DONE;
+               xmit.stat &= ~BUSY;
+               next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
+               break;
+
+       case TWI_MRX_ADR_ACK:
+               xmit.stat |= ADDR_ACK;
+               tmp_idx = xmit.idx;
+               if (tmp_idx < xmit.len-1) {
+                       next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
+               } else {
+                       next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
+               }
+               break;
+
+       case TWI_MRX_DATA_ACK:
+               xmit.stat |= DATA_ACK;
+               tmp_idx = xmit.idx;
+               xmit.buf[tmp_idx] = TWDR;
+               xmit.idx = ++tmp_idx;
+               if (tmp_idx < xmit.len-1) {
+                       next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
+               } else {
+               
+                       next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
+               }
+               break;
+
+       case TWI_MRX_DATA_NACK:
+               xmit.stat |= ADDR_ACK | DATA_ACK;
+
+               tmp_idx = xmit.idx;
+               xmit.buf[tmp_idx] = TWDR;
+               xmit.idx = ++tmp_idx;
+               /* fall thru */
+
+       default:
+               xmit.stat &= ~BUSY;
+               next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
+               break;
+       }
+
+#ifdef DEBUG_I2C       
+       debug("|%02x", twsr);
+#endif
+       TWCR = next_twcr;
+}
+
+
+/*------------------------------------------------------------------*/
+
+static uint8_t twps;
+static uint8_t twbr;
+
+
+static void _init(void)
+{
+       xmit.stat = 0;
+#ifdef DEBUG_I2C
+       memset((void *) xmit.buf, 0xdf, sizeof(xmit.buf));
+#endif
+
+       /* Disable TWI, disable TWI interrupt. */
+       /* (Reset TWI hardware state machine.) */
+       TWCR = TWI_C_DISABLE;
+       _delay_us(5);
+
+       TWBR = twbr;
+       TWDR = 0xff;
+       TWCR = TWI_C_ENABLE + twps;
+}
+
+void i2c_init(uint32_t speed)
+{
+       twps = 0;
+       uint32_t tmptwbr = F_CPU /2 / speed - 8;
+       
+       while (tmptwbr > 255) {
+               tmptwbr >>= 4;
+               twps += 1;
+       }
+       debug_cond((twps > 3), "TWCLK too low: %lu Hz\n", speed);
+
+       twbr = (uint8_t) tmptwbr;
+       _init();
+}
+
+
+int_fast8_t i2c_waitready(void)
+{
+       uint32_t timer = get_timer(0);
+       uint8_t timeout = 0;
+       
+       do {
+               if (get_timer(timer) >= 30) {
+                       timeout = TIMEOUT;
+                       _init();
+               }
+       } while ((TWCR & ((1<<TWIE)|(1<<TWSTO))) != 0 && !timeout);
+
+       xmit.stat |= timeout;
+
+#ifdef DEBUG_I2C
+       dump_ram((uint8_t *) &xmit, 4, "=== i2c_wait ready: (done)");
+       _delay_ms(30);
+#endif 
+       return xmit.stat;
+}
+
+//static
+int i2c_send(uint8_t chip, uint16_t addr, uint8_t alen, uint8_t *buffer, int8_t len)
+{
+       uint8_t i, n;
+       uint8_t rc;
+
+       rc = i2c_waitready();
+       if ((rc & (BUSY | TIMEOUT)) != 0)
+               return rc;
+
+       xmit.stat = BUSY;
+       xmit.buf[0] = chip<<1;
+       for (i = 1; i < alen+1; i++) {
+               xmit.buf[i] = (uint8_t) addr;
+               addr >>= 8;
+       }
+       for (n = len + i; i < n; i++)
+               xmit.buf[i] = *buffer++;
+       xmit.len = i;
+       
+#ifdef DEBUG_I2C
+       dump_ram((uint8_t *) &xmit, 0x20, "=== i2c_send");
+       _delay_ms(30);
+#endif 
+       /* Enable TWI, TWI int and initiate start condition */
+       TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA);
+
+       rc = xmit.stat;
+
+       return rc;
+}
+
+//static
+int i2c_recv(uint8_t chip, uint8_t *buffer, int8_t len)
+{
+       uint8_t rc;
+
+       rc = i2c_waitready();
+       if ((rc & (BUSY | TIMEOUT)) != 0)
+               return rc;
+
+       xmit.stat = BUSY;
+       xmit.len = len + 1;
+       xmit.buf[0] = (chip<<1) | 1;
+
+#ifdef DEBUG_I2C
+       dump_ram((uint8_t *) &xmit, 0x20, "=== i2c_recv: before start");
+       _delay_ms(30);
+#endif
+       /* Enable TWI, TWI int and initiate start condition */
+       TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA);
+       rc = i2c_waitready();
+
+#ifdef DEBUG_I2C
+       dump_ram((uint8_t *) &xmit, 0x20, "=== i2c_recv: after completion");
+       _delay_ms(30);
+#endif
+       if (rc & DATA_ACK) {
+               /* at least 1 byte received */
+               for (uint8_t i=1, n=xmit.idx; i < n; i++)
+                       *buffer++ = xmit.buf[i];
+       }
+
+       return rc;
+}
+
+/*
+ * Read/Write interface:
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+
+int i2c_write(uint8_t chip, unsigned int addr, uint_fast8_t alen,
+                               uint8_t *buffer, uint_fast8_t len)
+{
+       int rc;
+       
+       if ((alen > 2) || (1 + alen + len > CONFIG_SYS_I2C_BUFSIZE)) {
+               debug("** i2c_write: buffer overflow, alen: %u, len: %u\n",
+                       alen, len);
+               return -1;
+       }
+       
+       i2c_send(chip, addr, alen, buffer, len);
+       rc = i2c_waitready();
+       debug("** i2c_write: result=0x%02x\n",rc);
+
+       return (rc & XMIT_DONE) != 0;
+}
+
+int i2c_read(uint8_t chip, unsigned int addr, uint_fast8_t alen,
+                               uint8_t *buffer, uint_fast8_t len)
+{
+       int rc;
+
+       if ((alen > 2) || (1 + len > CONFIG_SYS_I2C_BUFSIZE)) {
+               debug("** i2c_read: parameter error: alen: %u, len: %u\n",
+                       alen, len);
+               return -1;
+       }
+       
+       if (alen != 0) {
+               i2c_send(chip, addr, alen, NULL, 0);
+       }       
+       rc = i2c_recv(chip, buffer, len);
+       debug("** i2c_read: result=0x%02x\n",rc);
+
+       return !((rc & (XMIT_DONE|DATA_ACK)) == (XMIT_DONE|DATA_ACK));
+}
+
+
+
index c6a0f00929f2d97e7370ba11dbeba4b2f7dfae66..9103ddc036a0bcb8b8162633291c002e11d72eb6 100644 (file)
@@ -5,22 +5,14 @@
 #include "common.h"
 
 #include <util/delay.h>
-//#include <avr/power.h>
-//#include <avr/pgmspace.h>
 #include <avr/interrupt.h>
-//#include <util/atomic.h>
-//#include <avr/sleep.h>
-//#include <string.h>
-
-#include <util/delay.h>
-
 #include <stdlib.h>
 #include <stdio.h>
 
-
 #include "config.h"
 #include "debug.h"
 #include "z80-if.h"
+#include "i2c.h"
 #include "con-utils.h"
 #include "serial.h"
 #include "timer.h"
@@ -92,7 +84,7 @@ void print_reset_reason(void)
        uint8_t r = mcusr & 0x1f;
        const FLASH char * const FLASH *p = rreasons;
 
-       printf_P(PSTR("Reset reason(s): "));
+       printf_P(PSTR("Reset reason(s): %s"), r ? "" : "none");
        for ( ; r; p++, r >>= 1) {
                if (r & 1) {
                        my_puts_P(*p);
@@ -217,6 +209,7 @@ int main(void)
 #endif
                
        env_init();
+       i2c_init(34920);
 
        printf_P(PSTR("\n(ATMEGA1281+HD64180)_stamp Tester\n"));
        
diff --git a/avr/pcf8583.c b/avr/pcf8583.c
new file mode 100644 (file)
index 0000000..d33c9b0
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Date & Time support for Philips PCF8583 RTC
+ */
+
+/* #define     DEBUG   */
+
+#include "common.h"
+#include <stdlib.h>
+#include "debug.h"
+#include "command.h"
+#include "rtc.h"
+#include "i2c.h"
+
+#define REG_CS         0x00    /* control/status */
+#define REG_CSEC       0x01    /* hundredth of a second */
+#define REG_SEC                0x02    /* seconds */
+#define REG_MIN                0x03    /* minutes */
+#define REG_HOUR       0x04    /* hours */
+#define REG_YRDATE     0x05    /* year/date */
+#define REG_WDMON      0x06    /* weekdays/months */
+#define NR_OF_REGS     7
+
+
+/* ------------------------------------------------------------------------- */
+
+static uint_fast8_t bcd2bin(uint8_t val)
+{
+       return (val >> 4) * 10 + (val & 0x0f);
+}
+
+static uint8_t bin2bcd (uint_fast8_t val)
+{
+       div_t d = div(val, 10);
+       
+       return (d.quot << 4) | d.rem;
+}
+
+
+int rtc_get (struct rtc_time *tmp)
+{
+       int rel = 0;
+       uint8_t rtcbuf[NR_OF_REGS];
+       uint16_t year;
+       
+       i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, rtcbuf, NR_OF_REGS);
+       i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0x10, 1, (uint8_t *) &year, 2);
+
+       debug("Get RTC year: %u, year/date: %02x, wdays/month: %02x, "
+               "hour: %02x, min: %02x, sec: %02x, (stat: %02x)\n", year,
+               rtcbuf[6], rtcbuf[5], rtcbuf[4], rtcbuf[3], rtcbuf[2], rtcbuf[0]);
+
+       tmp->tm_sec  = bcd2bin (rtcbuf[REG_SEC]    & 0x7F);
+       tmp->tm_min  = bcd2bin (rtcbuf[REG_MIN]    & 0x7F);
+       tmp->tm_hour = bcd2bin (rtcbuf[REG_HOUR]   & 0x3F);
+       tmp->tm_mday = bcd2bin (rtcbuf[REG_YRDATE] & 0x3F);
+       tmp->tm_mon  = bcd2bin (rtcbuf[REG_WDMON]  & 0x1F);
+       while (year%4 < (rtcbuf[REG_YRDATE]>>6)) {
+               year++;
+               /* TODO: update RTC ram */
+       }
+       tmp->tm_year  = year; 
+       tmp->tm_wday = rtcbuf[REG_WDMON] >> 5;
+       tmp->tm_yday = 0;
+       tmp->tm_isdst= 0;
+
+
+       debug ( "Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+               tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+               tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+       return rel;
+}
+
+int rtc_set (struct rtc_time *tmp)
+{
+       uint8_t rtcbuf[NR_OF_REGS];
+
+       debug ( "Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+               tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+               tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+       rtcbuf[REG_CS] = 0x84;
+       rtcbuf[REG_CSEC] = 0x00;
+       rtcbuf[REG_WDMON ] = bin2bcd(tmp->tm_mon) | ((tmp->tm_wday) << 5);
+       rtcbuf[REG_YRDATE] = ((tmp->tm_year % 4) << 6) | bin2bcd(tmp->tm_mday);
+       rtcbuf[REG_HOUR  ] = bin2bcd(tmp->tm_hour);
+       rtcbuf[REG_MIN   ] = bin2bcd(tmp->tm_min);
+       rtcbuf[REG_SEC   ] = bin2bcd(tmp->tm_sec);
+
+       i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0,    1, rtcbuf, NR_OF_REGS);
+       i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0x10, 1, (uint8_t *) &tmp->tm_year, 2);
+       rtcbuf[REG_CS] = 0x04;
+       i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, rtcbuf, 1);
+
+
+       return 0;
+}
+
+void rtc_reset (void)
+{
+       uint8_t c = 0;
+       
+       i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, &c, 1);
+}
+
+
index cf379cedbe9814206b296fa480d95a545165f2bb..18023389d33ed0ce49fb7f1be7e24dfa17da9339 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef CMD_MEM_H
 #define CMD_MEM_H
 
-//#include "common.h"
-
 #include "command.h"
 #include "cmd_mem.h"
 
index a92f62c129c616390a9b898dabd41bd38fc7fdd9..e8879a613c1477dceabab305aa5e1c2c3430decb 100644 (file)
@@ -43,19 +43,15 @@ void my_puts(const char *s)
        fputs(s, stdout);
 }
 
-#ifdef __AVR__
 static inline 
 void my_puts_P(const char *s)
 {
+#ifdef __AVR__
        fputs_P(s, stdout);
-}
-
 #else
-static inline
-void my_puts_P(const char *s)
-{
        fputs(s, stdout);
-}
 #endif /* __AVR__ */
+}
+
 #endif /* COMMON_H */
 
index 08d97bdb0221cc6c10cd6053acb5239f7abac6d9..91b1fae547ed9f9d34dab5e36b66dbe1e164dd64 100644 (file)
 //#define CONFIG_CMD_MEMTEST
 //#define CONFIG_MX_CYCLIC
 
+#define CONFIG_CMD_DATE 1
+
+#define CONFIG_SYS_I2C_RTC_ADDR        0x50
+#define CONFIG_SYS_I2C_BUFSIZE 64
+#define CONFIG_SYS_I2C_CLOCK   100000L         /* 100kHz */
+
 #define CONFIG_SYS_CBSIZE      250
 #define CONFIG_SYS_ENV_NAMELEN 16
 #define CONFIG_SYS_MAXARGS     8
index c38bae40824d7aa861b4d0139646db9a2a26eddc..927b5ff726f768bfebfddb1793325da6d7077fe9 100644 (file)
@@ -1,12 +1,14 @@
 #ifndef CRC_H
 #define CRC_H
 
+#ifdef __AVR__
 #include <util/crc16.h>
-
 static inline
 uint16_t crc16(uint16_t crc, uint8_t data) 
 {
        return _crc_ccitt_update(crc, data);
 }
+#else /* !__AVR__ */
+#endif /* __AVR__ */
 
 #endif /* CRC_H */
index 7c19e40fd186fb240e07ea91a70fe4d92ec50950..8fdc830e7f1f162f075d2214d3c3b641698b8a9a 100644 (file)
@@ -3,7 +3,9 @@
 #define DEBUG_H_
 
 #include "common.h"
+#ifdef __AVR__
 #include <avr/pgmspace.h>
+#endif
 
 #ifdef DEBUG
 #define _DEBUG 1
@@ -31,6 +33,8 @@
 #endif /* 0 */
 
 
+void dump_eep(const uint8_t *addr, unsigned int len, char *title);
+void dump_ram(const uint8_t *addr, unsigned int len, char *title);
 void printfreelist(const char * title);
 
 
diff --git a/include/i2c.h b/include/i2c.h
new file mode 100644 (file)
index 0000000..50b1fd0
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2009 Sergey Kubushyn <ksi@koi8.net>
+ * Copyright (C) 2009 - 2013 Heiko Schocher <hs@denx.de>
+ * Changes for multibus/multiadapter I2C support.
+ *
+ * (C) Copyright 2001
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ *
+ * The original I2C interface was
+ *   (C) 2000 by Paolo Scaffardi (arsenio@tin.it)
+ *   AIRVENT SAM s.p.a - RIMINI(ITALY)
+ * but has been changed substantially.
+ */
+
+#ifndef _I2C_H_
+#define _I2C_H_
+
+/*
+ * Configuration items.
+ */
+/* TODO: config.h? */
+#define I2C_RXTX_LEN   128     /* maximum tx/rx buffer length */
+
+
+/*
+ * Initialization, must be called once on start up, may be called
+ * repeatedly to change the speed.
+ */
+void i2c_init(uint32_t speed);
+
+/*
+ * Probe the given I2C chip address.  Returns 0 if a chip responded,
+ * not 0 on failure.
+ */
+int i2c_probe(uint8_t chip);
+
+/*
+ * Read/Write interface:
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+int i2c_read(uint8_t chip, unsigned int addr, uint_fast8_t alen,
+                               uint8_t *buffer, uint_fast8_t len);
+int i2c_write(uint8_t chip, unsigned int addr, uint_fast8_t alen,
+                               uint8_t *buffer, uint_fast8_t len);
+
+/*
+ * Utility routines to read/write registers.
+ */
+uint8_t i2c_reg_read(uint8_t addr, uint8_t reg);
+
+void i2c_reg_write(uint8_t addr, uint8_t reg, uint8_t val);
+
+#endif /* _I2C_H_*/
diff --git a/include/rtc.h b/include/rtc.h
new file mode 100644 (file)
index 0000000..15215a9
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/*
+ * Generic RTC interface.
+ */
+#ifndef _RTC_H_
+#define _RTC_H_
+
+
+/*
+ * The struct used to pass data from the generic interface code to
+ * the hardware dependend low-level code ande vice versa. Identical
+ * to struct rtc_time used by the Linux kernel.
+ *
+ * Note that there are small but significant differences to the
+ * common "struct time":
+ *
+ *             struct time:            struct rtc_time:
+ * tm_mon      0 ... 11                1 ... 12
+ * tm_year     years since 1900        years since 0
+ */
+
+struct rtc_time {
+       int tm_sec;
+       int tm_min;
+       int tm_hour;
+       int tm_mday;
+       int tm_mon;
+       int tm_year;
+       int tm_wday;
+       int tm_yday;
+       int tm_isdst;
+};
+
+int rtc_get (struct rtc_time *);
+int rtc_set (struct rtc_time *);
+void rtc_reset (void);
+
+void GregorianDay (struct rtc_time *);
+void to_tm (unsigned long, struct rtc_time *);
+unsigned long mktime (unsigned int, unsigned int, unsigned int,
+                     unsigned int, unsigned int, unsigned int);
+
+#endif /* _RTC_H_ */