This is the mail archive of the ecos-patches@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

update ds1307 wallclock driver


This patch updates the ds1307 wallclock driver to use either the new
I2C API or the old way of doing things, preserving backwards
compatibility. It also adds documentation for the driver.

Bart

Index: devs/wallclock/dallas/ds1307/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/wallclock/dallas/ds1307/current/ChangeLog,v
retrieving revision 1.1
diff -u -r1.1 ChangeLog
--- devs/wallclock/dallas/ds1307/current/ChangeLog	19 Sep 2003 17:11:25 -0000	1.1
+++ devs/wallclock/dallas/ds1307/current/ChangeLog	20 Apr 2005 12:32:14 -0000
@@ -1,3 +1,10 @@
+2004-10-09  Bart Veer  <bartv@ecoscentric.com>
+
+	* doc/ds1307.sgml: add package documentation
+	
+	* src/ds1307.cxx, cdl/wallclock_ds1307.cdl: use the generic I2C
+	API rather than ad-hoc macros, if supported.
+
 2003-09-19  Gary Thomas  <gary@mlbassoc.com>
 
 	* src/ds1307.cxx: 
@@ -7,6 +14,7 @@
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2004 eCosCentric Ltd.	
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
 //
 // eCos is free software; you can redistribute it and/or modify it under
Index: devs/wallclock/dallas/ds1307/current/cdl/wallclock_ds1307.cdl
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/wallclock/dallas/ds1307/current/cdl/wallclock_ds1307.cdl,v
retrieving revision 1.1
diff -u -r1.1 wallclock_ds1307.cdl
--- devs/wallclock/dallas/ds1307/current/cdl/wallclock_ds1307.cdl	19 Sep 2003 17:11:25 -0000	1.1
+++ devs/wallclock/dallas/ds1307/current/cdl/wallclock_ds1307.cdl	20 Apr 2005 12:32:14 -0000
@@ -10,6 +10,7 @@
 ## This file is part of eCos, the Embedded Configurable Operating System.
 ## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
 ## Copyright (C) 2003 Gary Thomas
+## Copyright (C) 2004 eCosCentric Ltd
 ##
 ## eCos 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
@@ -70,7 +71,15 @@
         implements    CYGINT_WALLCLOCK_IMPLEMENTATIONS
     }
 
-
+    cdl_interface CYGINT_DEVICES_WALLCLOCK_DALLAS_DS1307_I2C {
+	display		"Access DS1307 device via the I2C API"
+	flavor		bool
+	description "
+            This interface will be implemented if the platform supports
+            the standard I2C API and the platform HAL exports an I2C
+            device cyg_i2c_wallclock_ds1307."
+    }
+    
     cdl_component CYGPKG_DEVICES_WALLCLOCK_DALLAS_DS1307_OPTIONS {
         display "DS1307 wallclock build options"
         flavor  none
Index: devs/wallclock/dallas/ds1307/current/doc/ds1307.sgml
===================================================================
RCS file: devs/wallclock/dallas/ds1307/current/doc/ds1307.sgml
diff -N devs/wallclock/dallas/ds1307/current/doc/ds1307.sgml
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/wallclock/dallas/ds1307/current/doc/ds1307.sgml	20 Apr 2005 12:32:15 -0000
@@ -0,0 +1,126 @@
+<!-- DOCTYPE refentry  PUBLIC "-//OASIS//DTD DocBook V3.1//EN" -->
+
+<!-- {{{ Banner                         -->
+
+<!-- =============================================================== -->
+<!--                                                                 -->
+<!--     ds1307.sgml                                                 -->
+<!--                                                                 -->
+<!--     Documentation for the ds1307 wallclock driver               -->
+<!--                                                                 -->
+<!-- =============================================================== -->
+<!-- ####COPYRIGHTBEGIN####                                          -->
+<!--                                                                 -->
+<!-- =============================================================== -->
+<!-- Copyright (C) 2004 eCosCentric Limited.                         -->
+<!-- This material may be distributed only subject to the terms      -->
+<!-- and conditions set forth in the Open Publication License, v1.0  -->
+<!-- or later (the latest version is presently available at          -->
+<!-- http://www.opencontent.org/openpub/)                            -->
+<!-- Distribution of the work or derivative of the work in any       -->
+<!-- standard (paper) book form is prohibited unless prior           -->
+<!-- permission obtained from the copyright holder                   -->
+<!-- =============================================================== -->
+<!--                                                                 -->      
+<!-- ####COPYRIGHTEND####                                            -->
+<!-- =============================================================== -->
+<!-- =============================================================== -->
+<!-- #####DESCRIPTIONBEGIN####                                       -->
+<!--                                                                 -->
+<!-- Author(s):   bartv                                              -->
+<!-- Contact(s):  bartv                                              -->
+<!-- Date:        2004/10/09                                         -->
+<!-- Version:     0.01                                               -->
+<!--                                                                 -->
+<!-- ####DESCRIPTIONEND####                                          -->
+<!-- =============================================================== -->
+
+<!-- }}} -->
+
+<part id="devs-wallclock-dallas-ds1307-part"><title>Dallas DS1307 Wallclock Device Driver</title>
+
+<refentry id="devs-wallclock-dallas-ds1307">
+  <refmeta>
+    <refentrytitle>Dallas DS1307 Wallclock Device Driver</refentrytitle>
+  </refmeta>
+  <refnamediv>
+    <refname><varname>CYGPKG_DEVICES_WALLCLOCK_DALLAS_DS1307</varname></refname>
+    <refpurpose>eCos Support for the Dallas DS1307 Serial Real-Time Clock</refpurpose>
+  </refnamediv>
+
+  <refsect1 id="devs-wallclock-dallas-ds1307-description"><title>Description</title>
+    <para>
+This package
+<varname>CYGPKG_DEVICES_WALLCLOCK_DALLAS_DS1307</varname> provides a
+device driver for the wallclock device in the Dallas DS1307 Serial
+Real-Time Clock chips. This combines a real-time clock and 56 bytes of
+battery-backed RAM in a single package. The driver can also be used
+with any other chips that provide the same interface to the clock
+hardware.
+    </para>
+    <para>
+The package will usually be loaded into the configuration
+automatically whenever selecting a target which contains a compatible
+chip. By default it will provide the standard eCos wallclock device,
+although another implementation such as software emulation may be
+selected if desired. The only other configuration options related to
+this package allow users to change the compiler flags. If the
+application does not actually use the wallclock device, directly or
+indirectly, then the code should get removed automatically at
+link-time to ensure that the application does not suffer any
+unnecessary overheads.
+    </para>
+  </refsect1>
+
+  <refsect1 id="devs-wallclock-dallas-ds1307-functions"><title>Functionality</title>
+    <para>
+This wallclock device driver package implements the standard
+functionality required by the generic wallclock support
+<varname>CYGPKG_IO_WALLCLOCK</varname>. The functionality is not
+normally accessed directly. Instead it is used by the C library time
+package to implement standard calls such as <function>time</function>
+and <function>gmtime</function>. The eCos C library also provides a
+non-standard function <function>cyg_libc_time_settime</function> for
+changing the current wallclock setting. In addition RedBoot provides
+a <command>date</command> command which interacts with the wallclock
+device.
+    </para>
+  </refsect1>
+
+  <refsect1 id="devs-wallclock-dallas-ds1307-porting"><title>Porting</title>
+    <para>
+DS1307 platform support can be implemented in one of two ways. The
+preferred approach involves the generic I2C API, as defined by the
+package <varname>CYGPKG_IO_I2C</varname>. The platform HAL can just
+provide a <structname>cyg_i2c_device</structname> structure
+<varname>cyg_i2c_wallclock_ds1307</varname> and implement the CDL
+interface
+<varname>CYGINT_DEVICES_WALLCLOCK_DALLAS_DS1307_I2C</varname>. The
+DS1307 driver will now use I2C rx and tx operations to interact with
+the chip.
+    </para>
+    <para>
+Alternatively the DS1307 driver can use macros or functions provided
+by another package to access the chip. This is intended primarily for
+older platforms that predate the <varname>CYGPKG_IO_I2C</varname>
+package. The other package should export a header file containing
+macros <function>DS_GET</function> and <function>DS_PUT</function>
+that transfer the eight bytes corresponding to the chip's clock
+registers. It should also export the name of this header via a
+<literal>#define</literal>
+<varname>CYGDAT_DEVS_WALLCLOCK_DS1307_INL</varname> in the global
+configuration header <filename
+class="headerfile">pkgconf/system.h</filename>. For full details see
+the source code.
+    </para>
+    <para>
+In addition the DS1307 device driver package
+<varname>CYGPKG_DEVICES_WALLCLOCK_DALLAS_DS1307</varname> should be
+included in the CDL target entry so that it gets loaded automatically
+whenever eCos is configured for that target.
+    </para>
+  </refsect1>
+
+</refentry>
+
+</part>
Index: devs/wallclock/dallas/ds1307/current/src/ds1307.cxx
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/wallclock/dallas/ds1307/current/src/ds1307.cxx,v
retrieving revision 1.1
diff -u -r1.1 ds1307.cxx
--- devs/wallclock/dallas/ds1307/current/src/ds1307.cxx	19 Sep 2003 17:11:25 -0000	1.1
+++ devs/wallclock/dallas/ds1307/current/src/ds1307.cxx	20 Apr 2005 12:32:16 -0000
@@ -10,6 +10,7 @@
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
 // Copyright (C) 2003 Gary Thomas
+// Copyright (C) 2004 eCosCentric Ltd
 //
 // eCos 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
@@ -52,19 +53,29 @@
 
 #include <pkgconf/hal.h>                // Platform specific configury
 #include <pkgconf/wallclock.h>          // Wallclock device config
+#include <pkgconf/devices_wallclock_dallas_ds1307.h>
 
 #include <cyg/hal/hal_io.h>             // IO macros
 #include <cyg/hal/hal_intr.h>           // interrupt enable/disable
 #include <cyg/infra/cyg_type.h>         // Common type definitions and support
+#include <string.h>                     // memcpy()
 
 #include <cyg/io/wallclock.hxx>         // The WallClock API
 #include <cyg/io/wallclock/wallclock.inl> // Helpers
 
 #include <cyg/infra/diag.h>
 
-//#define DEBUG
+#if 1
+# define DEBUG(_format_, ...)
+#else
+# define DEBUG(_format_, ...) diag_printf(_format_, ## __VA_ARGS__)
+#endif
 
-// Registers
+// Registers.
+// FIXME: there is no need to include the control register here, it
+// controls a square wave output which is independent from the wallclock.
+// However fixing it would require changing any platforms that use the
+// old DS_GET()/DS_PUT() functionality.
 #define DS_SECONDS         0x00
 #define DS_MINUTES         0x01
 #define DS_HOURS           0x02
@@ -76,11 +87,15 @@
 #define DS_REGS_SIZE       0x08   // Size of register space
 
 #define DS_SECONDS_CH      0x80   // Clock Halt
-#define DS_HOURS_24        0x80   // 24 hour clock mode
+#define DS_HOURS_24        0x40   // 24 hour clock mode
 
-//
-// This particular chip is always accessed via I2C (2-wire protocol)
-// The platform needs to provide simple I2C access functions
+// The DS1307 chip is accessed via I2C (2-wire protocol). This can be
+// implemented in one of two ways. If the platform supports the generic
+// I2C API then it should also export a cyg_i2c_device structure
+// cyg_i2c_wallclock_ds1307, and this can be manipulated via the
+// usual cyg_i2c_tx() and cyg_i2c_rx() functions. Alternatively (and
+// primarily for older ports predating the generic I2C package)
+// the platform HAL can provide the following two macros/functions:
 //
 // void DS_GET(cyg_uint8 *regs)
 //    Reads the entire set of registers (8 bytes) into *regs
@@ -91,41 +106,124 @@
 // stable (if the access function manipulates the registers in an
 // single operation)
 //
+// If the platform HAL implements the CDL interface
+// CYGINT_DEVICES_WALLCLOCK_DALLAS_DS1307_I2C then the I2C API will be used.
+
+#ifdef CYGINT_DEVICES_WALLCLOCK_DALLAS_DS1307_I2C
+# if defined(DS_GET) || defined(DS_PUT)
+#  error The macros DS_GET and DS_PUT should not be defined if the generic I2C API is used
+# endif
+
+#include <cyg/io/i2c.h>
+
+static void
+DS_GET(cyg_uint8* regs)
+{
+    cyg_uint8   tx_data[1];
+    cyg_bool    ok = true;
+
+    tx_data[0]  = 0x00; // Initial register to read
+    cyg_i2c_transaction_begin(&cyg_i2c_wallclock_ds1307);
+    if (1 != cyg_i2c_transaction_tx(&cyg_i2c_wallclock_ds1307, true, tx_data, 1, false)) {
+        // The device has not responded to the address byte.
+        ok = false;
+    } else {
+        // Now fetch the data
+        cyg_i2c_transaction_rx(&cyg_i2c_wallclock_ds1307, true, regs, 8, true, true);
+
+        // Verify that there are reasonable default settings. The
+        // register values can be used as array indices so bogus
+        // values can lead to bus errors or similar problems.
+        
+        // Years: 00 - 99, with 70-99 interpreted as 1970 onwards.
+        if ((regs[DS_YEAR] & 0x0F) > 0x09) {
+            ok = false;
+        }
+        // Month: 1 - 12
+        if ((regs[DS_MONTH] == 0x00) ||
+            ((regs[DS_MONTH] > 0x09) && (regs[DS_MONTH] < 0x10)) ||
+            (regs[DS_MONTH] > 0x12)) {
+            ok = false;
+        }
+        // Day: 1 - 31. This check does not allow for 28-30 day months.
+        if ((regs[DS_DOM] == 0x00) ||
+            ((regs[DS_DOM] & 0x0F) > 0x09) ||
+            (regs[DS_DOM] > 0x31)) {
+            ok = false;
+        }
+        // Hours: 0 - 23. Always run in 24-hour mode
+        if ((0 != (regs[DS_HOURS] & DS_HOURS_24)) ||
+            ((regs[DS_HOURS] & 0x0F) > 0x09) ||
+            ((regs[DS_HOURS] & 0x3F) > 0x023)) {
+            ok = false;
+        }
+        // Ignore the DOW field. The wallclock code does not need it, and
+        // it is hard to calculate.
+        // Minutes: 0 - 59
+        if (((regs[DS_MINUTES] & 0x0F) > 0x09) ||
+            (regs[DS_MINUTES] > 0x59)) {
+            ok = false;
+        }
+        // Seconds: 0 - 59
+        if (((regs[DS_SECONDS] & 0x0F) > 0x09) ||
+            (regs[DS_SECONDS] > 0x59)) {
+            ok = false;
+        }
+    }
+    cyg_i2c_transaction_end(&cyg_i2c_wallclock_ds1307);
+    if (! ok) {
+        // Any problems, return Jan 1 1970 but do not update the hardware.
+        // Leave it to the user or other code to set the clock to a sensible
+        // value.
+        regs[DS_SECONDS]  = 0x00;
+        regs[DS_MINUTES]  = 0x00;
+        regs[DS_HOURS]    = 0x00;
+        regs[DS_DOW]      = 0x00;
+        regs[DS_DOM]      = 0x01;                                                         
+        regs[DS_MONTH]    = 0x01;                                                        
+        regs[DS_YEAR]     = 0x70;
+        regs[DS_CONTROL]  = 0x00;
+    }
+}
 
-// Platform details
-#include CYGDAT_DEVS_WALLCLOCK_DALLAS_1307_INL
+static void
+DS_PUT(cyg_uint8* regs)
+{
+    cyg_uint8 tx_data[9];
+    tx_data[0] = 0;
+    memcpy(&(tx_data[1]), regs, 8);
+    cyg_i2c_tx(&cyg_i2c_wallclock_ds1307, tx_data, 9);
+}
+
+#else
+// Platform details. The platform HAL or some other package should
+// provide this header, containing the required macros
+# include CYGDAT_DEVS_WALLCLOCK_DALLAS_1307_INL
+#endif
 
 //----------------------------------------------------------------------------
 // Accessor functions
+
 static inline void
 init_ds_hwclock(void)
 {
     cyg_uint8 regs[DS_REGS_SIZE];
-    
-    // Verify that there are reasonable default settings - otherwise
-    // set them.
 
     // Fetch the current state
     DS_GET(regs);
-
-    if (0x00 == regs[DS_MONTH])
-	regs[DS_MONTH] = TO_BCD(1);
-
-    if (0x00 == regs[DS_DOW])
-	regs[DS_DOW] = TO_BCD(1);
-
-    if (0x00 == regs[DS_DOM])
-	regs[DS_DOM] = TO_BCD(1);
-
-    // Make sure clock is running and in 24 hour mode
-    regs[DS_HOURS] |= DS_HOURS_24;
-    regs[DS_SECONDS] &= ~DS_SECONDS_CH;
-
-    // Update the state
-    DS_PUT(regs);
+    
+    // If the clock is not currently running or is not in 24-hours mode,
+    // update it. Otherwise skip the update because the clock may have
+    // ticked between DS_GET() and DS_PUT() and we could be losing the
+    // occasional second.
+    if ((0 != (regs[DS_HOURS] & DS_HOURS_24)) ||
+        (0 != (regs[DS_SECONDS] & DS_SECONDS_CH))) {
+        regs[DS_SECONDS] &= ~DS_SECONDS_CH;
+        regs[DS_HOURS]   &= ~DS_HOURS_24;
+        DS_PUT(regs);
+    }
 }
 
-
 static inline void
 set_ds_hwclock(cyg_uint32 year, cyg_uint32 month, cyg_uint32 mday,
                cyg_uint32 hour, cyg_uint32 minute, cyg_uint32 second)
@@ -133,28 +231,30 @@
     cyg_uint8 regs[DS_REGS_SIZE];
 
     // Set up the registers
-    regs[DS_YEAR] = TO_BCD((cyg_uint8)(year % 100));
-    regs[DS_MONTH] = TO_BCD((cyg_uint8)month);
-    regs[DS_DOM] = TO_BCD((cyg_uint8)mday);
-    regs[DS_HOURS] = TO_BCD((cyg_uint8)hour) | DS_HOURS_24;
-    regs[DS_MINUTES] = TO_BCD((cyg_uint8)minute);
+    regs[DS_CONTROL]    = 0x00;
+    regs[DS_YEAR]       = TO_BCD((cyg_uint8)(year % 100));
+    regs[DS_MONTH]      = TO_BCD((cyg_uint8)month);
+    regs[DS_DOM]        = TO_BCD((cyg_uint8)mday);
+    regs[DS_DOW]        = TO_BCD(0x01);     // Not accurate, but not used by this driver either
+    regs[DS_HOURS]      = TO_BCD((cyg_uint8)hour);
+    regs[DS_MINUTES]    = TO_BCD((cyg_uint8)minute);
     // This also starts the clock
-    regs[DS_SECONDS] = TO_BCD((cyg_uint8)second);
+    regs[DS_SECONDS]    = TO_BCD((cyg_uint8)second);
 
     // Send the register set to the hardware
     DS_PUT(regs);
 
-#ifdef DEBUG
-    // This will cause the test to eventually fail due to these printouts
-    // causing timer interrupts to be lost...
-    diag_printf("Set -------------\n");
-    diag_printf("year %02d\n", year);
-    diag_printf("month %02d\n", month);
-    diag_printf("mday %02d\n", mday);
-    diag_printf("hour %02d\n", hour);
-    diag_printf("minute %02d\n", minute);
-    diag_printf("second %02d\n", second);
-#endif
+    // These debugs will cause the test to eventually fail due to
+    // the printouts causing timer interrupts to be lost...
+    DEBUG("DS1307 set -------------\n");
+    DEBUG("regs %02x %02x %02x %02x %02x %02x %02x %02x\n",
+          regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]);
+    DEBUG("year %02d\n", year);
+    DEBUG("month %02d\n", month);
+    DEBUG("mday %02d\n", mday);
+    DEBUG("hour %02d\n", hour);
+    DEBUG("minute %02d\n", minute);
+    DEBUG("second %02d\n", second);
 }
 
 static inline void
@@ -168,27 +268,28 @@
 
     *year = (cyg_uint32)TO_DEC(regs[DS_YEAR]);
     // The year field only has the 2 least significant digits :-(
-    if (*year >= 34) {
+    if (*year >= 70) {
         *year += 1900;
     } else {
         *year += 2000;
     }
     *month = (cyg_uint32)TO_DEC(regs[DS_MONTH]);
     *mday = (cyg_uint32)TO_DEC(regs[DS_DOM]);
-    *hour = (cyg_uint32)TO_DEC(regs[DS_HOURS] & 0x7F);
+    *hour = (cyg_uint32)TO_DEC(regs[DS_HOURS] & 0x3F);
     *minute = (cyg_uint32)TO_DEC(regs[DS_MINUTES]);
     *second = (cyg_uint32)TO_DEC(regs[DS_SECONDS] & 0x7F);
 
-#ifdef DEBUG
-    // This will cause the test to eventually fail due to these printouts
-    // causing timer interrupts to be lost...
-    diag_printf("year %02d\n", *year);
-    diag_printf("month %02d\n", *month);
-    diag_printf("mday %02d\n", *mday);
-    diag_printf("hour %02d\n", *hour);
-    diag_printf("minute %02d\n", *minute);
-    diag_printf("second %02d\n", *second);
-#endif
+    // These debugs will cause the test to eventually fail due to
+    // the printouts causing timer interrupts to be lost...
+    DEBUG("DS1307 get -------------\n");
+    DEBUG("regs %02x %02x %02x %02x %02x %02x %02x %02x\n",
+          regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]);
+    DEBUG("year %02d\n", *year);
+    DEBUG("month %02d\n", *month);
+    DEBUG("mday %02d\n", *mday);
+    DEBUG("hour %02d\n", *hour);
+    DEBUG("minute %02d\n", *minute);
+    DEBUG("second %02d\n", *second);
 }
 
 //-----------------------------------------------------------------------------


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]