LED Clock: Interfacing to the DS1302 RTC Chip

It occurred to me that I haven’t posted the latest update on data interfacing to the Dallas/Maxim DS1302 real-time clock (RTC) chip; and then I searched and saw that I haven’t posted anything on it. I received the sample chips mid-June and started working with them after I had prototyped the A6276 LED driver and was waiting for my shipment of LEDs. Apparently once I received the LEDs, I was so excited by the bright blue glow that I forgot to get back to the timekeeping functions. :-)

“Auditioning” the 1302

I’m looking at two different timekeeping chips to use in the clock. The DS1340 looks like the better choice but is only available in surface-mount packages, so I’ll need to make a carrier before I can breadboard it to test; thus so far I’ve been testing the DS1302.

The 1302 tracks YY/MM/DD HH:MM:SS plus day of week and choice of 24-hour or AM/PM. It uses an external 32768Hz oscillator and has a VCC2 input to allow it to run on a lithium backup battery for up to 11 years in the absence of primary power. It doesn’t do daylight savings time, has century-unaware leap year support (but my clock will not still be in use in 2100), and requires you to set day of week manually rather than calculating it algorithmically. It’s not terribly sophisticated–but I don’t need terrible sophistication to get this job done.

It uses a “simple” three-wire interface for data communications:

Name Signal Use
CE clock enable? raise to begin transmission; lower to end communication
SCLK serial clock? cycle to transmit and receive data
I/O I/O data to and from clock chip

To write data to the 1302, raise CE, transmit the register address to the 1302 (setting the low bit to indicate a write operation, and clocking each bit), transmit the data (clocking each bit), and lower CE. To read data from the 1302, raise CE and transmit the register address (clearing the low bit, and clocking), continue clocking and read the received data, and lower CE.

But in the Real World . . .

I jumpered it to my Curiously Strong LogoChip and coded up an implementation of the protocol, but was getting totally random data back. The 1302 claims to support clock speeds down to DC (i.e. as slow as you want it to go), so I slowed it down to 1Hz and put the logic probe on it to see whether the bits it was sending matched the bytes I was outputting. After watching it send ultra-high-speed flurries of data back in response to the slow requests I was sending it, I realized it behaves much more predictably when I connect its ground pin to ground instead of leaving it floating. Oopsie.

Once I was actually communicating with the chip with a common voltage reference, I was able to read and display its seconds register. I found that it changed once a second as expected; and I knew its output wouldn’t be a simple count from 0-59, because it uses binary-coded decimal (BCD), where each nybble is the binary coding for the corresponding decimal digit.

I was surprised, though, to see the values alternating high and low: 64, 192, 65, 192, 66, 194, 67, 195. This suggested a bit alignment problem–I wasn’t reading the right bit in the right position. I wrote a Perl script to translate the decimal values into binary with leading zeroes (to make the bits line up so I could scan visually for patterns) and fed it a complete 60-second cycle, with this result:

64  -  01000000
192  -  11000000
65  -  01000001
193  -  11000001
66  -  01000010
194  -  11000010
67  -  01000011
195  -  11000011
68  -  01000100
196  -  11000100
72  -  01001000
200  -  11001000
73  -  01001001
201  -  11001001
74  -  01001010
202  -  11001010
75  -  01001011
203  -  11001011
76  -  01001100
204  -  11001100
80  -  01010000
208  -  11010000
81  -  01010001
209  -  11010001
82  -  01010010
210  -  11010010
83  -  01010011
211  -  11010011
84  -  01010100
212  -  11010100
88  -  01011000
216  -  11011000
89  -  01011001
217  -  11011001
90  -  01011010
218  -  11011010
91  -  01011011
219  -  11011011
92  -  01011100

I needn’t have included the whole thing, because it’s obvious what’s happening. What I thought was the high bit was changing the most rapidly, so it must in fact be the low bit. Somehow the byte got rotated one bit to the right. It’s only fair to mention at this point that the chip will keep repeating its transmitted data as long as you keep clocking it; so a rotation like this simply means that I’m a clock cycle off, not that something utterly bizarre is happening.

I searched my code for an errant clock cycle between the address-write and the data-read, but couldn’t find anything amiss. As an ugly kludge to get it working, I changed the read routine to cycle the clock after reading the bit rather than before, and of course began to get the correct data. Then I reexamined the datasheet and found the slightest justification in their confusing language that this behavior is by design: the first bit from the DS1302 is transmitted on the falling edge of the same clock cycle whose rising edge carried the last bit of the address register. Ewwwww.

I’ve been trying to think of cleverer ways to adapt to the situation, but haven’t come up with any. Clocking after reading works for single-byte reads, and should work (I haven’t tried it yet) for multi-byte reads in burst mode. So I guess I’ll leave it that way.

Here are the first few entries of a correct seconds cycle, in all their glory:

128  -  1 | 000 | 0000
129  -  1 | 000 | 0001
130  -  1 | 000 | 0010
131  -  1 | 000 | 0011
132  -  1 | 000 | 0100
133  -  1 | 000 | 0101
134  -  1 | 000 | 0110
135  -  1 | 000 | 0111
136  -  1 | 000 | 1000
137  -  1 | 000 | 1001
144  -  1 | 001 | 0000
145  -  1 | 001 | 0001
146  -  1 | 001 | 0010
147  -  1 | 001 | 0011

The 1 in the high bit of the high nybble represents that the clock is halted (which it obviously isn’t; not sure what to make of that, unless maybe it’s a write-only register???), the next three bits represent the tens-of-seconds digit, and the lower four bits represent the seconds digit. So this short list here shows seconds 00 – 13.

Higher-Level Timekeeping Functions

In order to be able to interpret the data coming back while testing the read routines, I had already written some functions to parse the time data. I haven’t gone back to test all of them after getting the read working, and I have some cleaning up to do on them anyway. Now that I have a one-digit prototype display working, I think returning to the timekeeping is the next step. Hopefully I can soon integrate the two, so the demo display can show actual seconds information.

4 Responses to “LED Clock: Interfacing to the DS1302 RTC Chip”

  1. kinwai says:

    hi, i stumble upon your blog while searching for articles on DS1302. Im working on a project using DS1302. Problem is, i have try a few codes from avrfreaks.net but i didnt seem to work. Could you be so kind to share some codes? my email is nelsonaquik@yahoo.com thanks a bunch!

  2. Keith Neufeld says:

    Kinwai, I don’t think my Logo code is going to do you much good on an AVR.

    I’m planning to get back to the clock soon, and I’m planning to port it from PIC/Logo to AVR/Arduino/C when I do. So you can certainly check back, but no promises on how soon that’ll be.

  3. preston noon says:

    I am starting in on the DS1302 as well, Arduino Nano. . . 7-segment displays. . .
    A can covert your code. . . . I’d love to see it.

  4. Keith Neufeld says:

    Preston, wow, how time flies . . . Nope, I sure haven’t been back to the clock yet.

    Let me email you my Logochip code. You’re going to have to hack through it, but you should be able to convert it okay, or at least use it as an example to get your Arduino code going. I can answer basic questions about it; I just can’t afford time right now to provide much help or do the conversion myself.

Leave a Reply