New Timepiece for a Classic Mac – Part 2

|

Introduction

Recently I created a new real-time clock (RTC) module for my slowly growing collection of classic Apple computers.

While the first attempt was working well, the serial timing was always a little tight, when compared to the timings exhibited by the original Apple RTC.

As an example when the original RTC was required to provide data back to the host it’s required to update the data line when the clock is low. In the instances I checked the data line was always updated within 200ns of the falling edge of the clock. Leaving 600ns before the next rising clock edge. My version however would typically update the data line between 40ns and 60ns before the rising clock edge, occasionally missing the deadline altogether and updating the data line just after the rising edge.

A feature of the Microchip ATTiny85 that I considered using was its universal serial interface (USI). While designed to communicate with I2C and SPI devices it’s generic enough to be used for other protocols.

The Apple RTC protocol shares some similarities with I2C. It uses open-collector outputs with resistor pull-ups on its data and clock lines. It’s always clocked by the host and follows a similar address + data scheme for transactions. It lacks however the start / stop sequence and acknowledgment features present in I2C, using its separate enable line to indicate when a transfer is in progress.

A slight snag that stopped me from investigating the USI while originally working on my RTC replacement is that the device would no longer be pin-compatible.

Annotated Microchip ATTiny85 Datasheet Extract

The USI interface in its I2C configuration is exposed on pins PB0 (serial data or SDA) and PB2 (serial clock or SCL). Whereas the Apple RTC uses pin PB0 for its enable signal and places data on PB1. Thereby requiring PB1 and PB0 to be swapped.

Software

Having recently come into possession of a voucher for some PCB prototypes from China I thought it might be time to take the USI module for a spin.

The Microchip ATTiny85 datasheet provides an overview of the operation of the USI peripheral when used for I2C communication:

Extract of Microchip ATTiny85 Datasheet showing USI I2C operation

When used for I2C communication the USI hardware at a basic level consists of a data shift register, a clock control unit and a counter.

The data shift register shifts on SCL edges. Sampling the value of the SDA pin on one edge into the least significant bit of the register. While shifting the most significant bit of the register on the other onto the SDA pin (if the pin is configured as an output). For the RTC the shift register will be configured to sample the SDA pin on the rising edge and update it it on the falling edge of the SCL pin when in output mode.

The clock control unit is responsible for detecting I2C start / stop conditions as well as performing the I2C clock stretching feature, providing an I2C device time to process an address and respond appropriately. These features can be safely ignored as the USI module will only drive the SCL line (for example during clock stretching) if the pin is configured as an output.

The counter is the final piece of the puzzle. Its a 4-bit counter, which is incremented on each edge of the SCL line. Therefore when it rolls over we’ve either transmitted or received a complete byte, having counted 16 clock edges.

Both the clock control unit and counter have configurable interrupts for start/stop condition detection and counter roll over respectively.

The idea being to use the pin change interrupt as in my first solution, to monitor the enable line.

When a rising edge is detected on the enable line the USI module will be reset, such that it’s ready to receive the start of the next address / command.

When a falling edge is detected on the enable line the USI counter overflow interrupt flag of the USI will be monitored, waiting for the transfer to complete. Along with the enable line in case the transfer is aborted.

Overall the same general process as before will be followed, replacing the bit bashed serial transfers with calls to the USI module.

For example the previous bit bashed receive routine:

uiBit = 8;
while (0 != uiBit)
{
	/* Sample bit on rising edge, while monitoring enable (except after last bit) */
	while (!mIsClockHigh()) if (mIsEnableHigh()) return;
	uiAddrBase = (uiAddrBase << 1) | mIsDataHigh();
	uiBit--;
	if (0 != uiBit) while (mIsClockHigh()) if (mIsEnableHigh()) return;
}

Becomes:

while (!mIsUSIOIFSet()) if (mIsEnableHigh() || mSerialTimeout()) return;
uiAddrBase = USIBR;

With a similar reduction in code size for the transmit routine.

Having freed up the processor time which was previously occupied by the serial routines, there’s now plenty of time to monitor for serial timeouts. Allowing the RTC to work with a mac which still has a functioning RTC battery if required.

Additionally it reduces the time critical windows in the code down to a single region. That being the case where a read command is provided. The module must look up the data based on the provided address and configure the USI module to transmit the response before the next clock edge. However this was easily achievable with the bit bashed version and remains so with this version.

With the new code in place and enable / data lines haphazardly swapped, the USI module manages to get the serial data stream looking almost identical to that of the original RTC. With the data line changing within 100ns of the falling clock edge when being driven by the RTC.

Hardware

The last step of the journey involves trying to come up with a new “pin compatible” module, which can be dropped in place of an Apple RTC chip. With that in mind I came up with the following:

Replacement RTC module schematic

Which becomes the following PCB:

Replacement RTC module PCB
Replacement RTC PCB 3D view (top)
Replacement RTC PCB 3D view (bottom)

The ATTiny85 in an SOIC SMD package neatly fits between the legs of the original PDIP-8 package. As do its supporting components. While not technically required I took the opportunity to add a crystal oscillator, increasing the timing accuracy, when compared to the internal RC oscillator.

A quick PCB order and dash of hand surface mount assembly and we have something resembling the 3D models above:

Replacement RTC assembled (top)
Replacement RTC assembled (bottom)

The software and hardware designs developed for this project are available on GitHub.

Update: 19th Nov 2024

Following a recent question in the comments, it’s worth nothing that the ATTiny RTC emulator described here can be dropped straight in, in place of Apple’s original RTC chip.

No modifications are required to the logic board. In fact, the battery, diode D1, supplying power to the RTC from the battery and the original crystal Y1 can all be absent.

One slight wrinkle to be aware of. I developed the software for the RTC emulator based on the excellent work of others, building on my previous drop-in replacement software for the ATTiny85. For my battery-less machines, saving the settings and boot options was the most important thing for me. There was some thought put into keeping the RTC running on battery while the machine is off, although this hasn’t been heavily tested. Given the power consumption of the ATTiny85 I don’t suspect it will last a particularly long time when running from an RTC battery.

Having switched from the single chip ATTiny85 solution to this more modular solution would have in hindsight been the perfect time to have addressed the power consumption issue. Unfortunately this wasn’t something I’d considered yet. There may well be a Mk3 module in the future that looks to address this issue.

Was this article helpful?
YesNo
, , ,

9 responses to “New Timepiece for a Classic Mac – Part 2”

  1. Francisco Perez avatar
    Francisco Perez

    I am using Windows to create to compile the file to use my TL866-II Plus to program the ATTiny85. Can you provide the compile file or instructions of how to do it

    1. Phil Greenland avatar
      Phil Greenland

      Hi Francisco, I’m about to assemble one of these for another of my machines. Will release some hex files on Github shortly. Thanks, Phil

  2. Royce avatar

    Do you know if your version will work with an older Mac, specifically a Mac 512K?

    1. Phil Greenland avatar
      Phil Greenland

      Hi Royce, I haven’t tried it in the older machines yet. My understanding was that the SE/30 and later machines RTC’s were similar to the older ones but included additional PRAM memory. They also communicate quite a bit faster than the older models. I developed the few versions of mine after trying a similar project based around the ATTiny for the Mac Plus. Which used the bitrate and didn’t stand a chance working in the SE/30. My current understanding is that it *should* work. The RTC will communicate at whatever speed the host clocks it at. The additional PRAM would be readable but the older machines just won’t see it. If you were going to try it, I’d recommend the single chip ATTiny only solution (see part 1). No assembly required and it’ll easily keep up with the older machine. It pretty much keeps up with the SE/30 but the timing appeared to be right on the edge of working. If you try it let me know how you get on / if you have any issues. Would be good to get some feedback as to whether it does…or doesn’t work in other machines. Thanks, Phil

      1. Royce avatar

        Hi Phil,

        Although I wanted to try out your latest and greatest version for more accurate time keeping, I had a few PDIP ATTiny85s handy, so I went ahead and complied and flashed your original program (from part 1) as you instructed then flashed the fuse bytes.

        I now have it running SUCCESSFULLY in a DIP socket on my Mac 512K! No changes necessary.

        I will say that I used Microchip Studio to compile the code, and I didn’t use your makefile. Because of this, I had to add #define F_CPU 16000000UL to the top of the code to get Microchip Studio to be happy with it.

        Thanks for sharing your work!

        1. Phil Greenland avatar
          Phil Greenland

          Nice one! Thanks for letting me know it works 🙂

  3. James Wages avatar

    Very interesting project! I do have one question though. I checked both pages of your Blog and your GitHub too, but it’s never made clear whether it is important to remove the stock “Y1” cylindrical can XTAL from the SE/30 motherboard, or if it can be left in place. Can you provide clarification about that?

    1. Phil Greenland avatar
      Phil Greenland

      Hi James,

      You’re right, I never mentioned….and had to check myself. It’s fine to leave it in place with either version of the project. I shall look to add a note to both pages, thanks!

      The single chip solution uses the ATTiny’s internal oscillator, but doesn’t keep the best time because of this. The module version uses the external crystal on the module to keep better time. Neither of them are able to use the watch crystal on the mainboard sadly.

      One snag I’m aware of with my two attempts here is current draw. The ATTiny tries to spend as much time asleep as it can, but will still be drawing around 1mA (according to it’s datasheet) from the battery. Which is going to deplete it fairly quickly I suspect.

      It’s not something I considered for my initial use case unfortunately. The machines I’ve been restoring had a lot of battery damage in this area, including to the original RTC itself and battery circuitry. Hence the need for a replacement.

      I may look to do a Mk3 in the future, which attempts to address the current draw, but it’s something to be aware of for now. If you do try one keeping time on battery let me know how it goes.

      Likewise if you’re able to try either the single chip or modular version in other macs I’d be interested to hear how things go. It *should* be compatible with more than just the SE/30…but I’ve not got other machines available to test with.

      Also thanks for your Youtube videos, your SE/30 recapping guides have been invaluable getting my long dead machines back up and running.

      Regards,

      Phil

      1. James Wages avatar

        Hi Phil,

        Thank you for your very detailed and helpful reply, and for your kind words.

        I be sure to will let you know when and if I test your mk2 RTC on machines other than an SE/30.

        I should mention though that a 1mA current draw from the RTC would have the greatest impact on PRAM battery life for owners of the SE/30 Reloaded motherboard by Bolle, which uses a CR2032 button cell. A CR2032 is typically only rated at 220mAh, versus 1200mAh for the stock battery 1/2 AA 3.6V Lithium. As a result, the CR2032 probably would last less than 2 weeks with a 1mA current draw.

        Best wishes,

        James

Leave a Reply

Your email address will not be published. Required fields are marked *