Home‎ > ‎

MMC/SD Interface V2

Another MMC/SD interface

After years of not creating any new hardware for my CoCos I decided it was time to break out the soldering iron again and make something new.

I really like storage projects, because it is great being able to use my computers without floppy drives or hard drives.  There is just something really nice about a computer that does not have any moving parts.

Back in 2003 I created (using a CPLD) a SPI bus for the coco.  The enabled me to use MMC/SD cards with the CoCo for storage.  My first MMC Interface prototype worked very good and allowed for two cards that could be hot swapped at any time.

The things that I did not like about the project were the complexity of the CPLD, the number of wires to connect to the CoCo, etc.  So that got me thinking, is there a way one could implement a SPI bus in software and use some existing I/O lines in the CoCo?

Looking at the schematic of the CoCo I figured I would find something that I could use.  I determined that I could use the single bit sound output, the cassette input bit, the cassette motor control and the *SCS line for a clock.  I quickly layed out a schematic and got to building.

Components for the project

As part of the design I put some constraints on myself:
  1. Only use parts that I had on hand
  2. No CPLD or other programmable logic
  3. No more than 2-3 discrete logic parts
  4. The final design should fit nicely inside of the coco
  5. This design would work in any CoCo
  6. Build a suitable OS-9 driver
Checking with my spare parts area I found a few 74HCT245 parts that would work for level shifting from 5v to 3.3v.  I also had a couple of 3.3V regulators in the pile of parts.  Finally I found a spare circuit board, some wire wrap wire, and some old ribbon cable.  Now I had everything I needed.

Schematic design

My schematic was drawn on a regular piece of paper, I need to get it into a schematic capture program and get a nice picture of it uploaded here.
Basically there are 4 pins on the 6821 PIA that I am using and two wires for power.  For a total of 6 wires that must be connected to the CoCo.  The final design was changed as during debugging I determined that I could not use *SCS and so I would need an additional I/O line to create a software clock.  More information on this later.

Finding a suitable CoCo

This should have been an easy task.  Unfortunately I only have one working CoCo 3 and so I was not about to start doing hardware prototyping on it.  So I went into the pile of extra CoCo 2 and CoCo 1 systems that I had here at the house.
I chose to use a 64k CoCo2 with extended color basic:

Getting my development environment ready

I planned on using a few things for development to speed things up.
Wiring up the design

Most of my projects take days to wire up and test and debug.  This project only uses 4 I/O lines and 2 for power.
The board took a couple of hours to wire up and connect internally in the CoCo.  Nothing really out of the ordinary.  

Testing the design

After wiring up the design into the CoCo I used DECB to poke and peek the correct locations on the PIA and tested the inputs and outputs to verify that things were working.  I have a binary ripple counter with 4 LEDs and some connectors for checking clocks and so that is what I connected to the *SCS line and tested it with a peek to $ff40.

Below is a snapshot of the board that I created wired into my computer:

Writing the driver

At first when I started I figured that I would use my old MMC driver as a basis for the new driver.  Then as I started looking into the code I remembered all the pain and frustration of trying to create a driver that needed to handle 512 byte sectors in a 256 byte sector environment.  After messing around with my old code for a few hours the thought occurred to me that I could use Cloud-9's SuperDriver and prevent a lot of extra work.  Thankfully there is an example low level driver template that is included with SuperDriver that allows you to build your own custom low level driver and use it with SuperDriver. 

Coding a low level driver using SuperDriver

Using the low level tempate I started to copy most of my existing MMC code over and started adding code to handle SD and SDHC cards.  Some additional commands and a small amount of extra code is all that is required to handle the 3 different cards.  
As debugging started I found myself removing a lot of the code for SD and SDHC cards to make sure that things were working properly with the hardware.  So currently the driver only implements MMC cards.  The other problem was that in my spare parts bin I only had slots for MMC cards.  I plan on purchasing a couple of SD card slots to I can get the driver working with SD and SDHC cards soon.
The working driver code can be downloaded here.

Testing the driver

Using DriveWire and Nitros9 source made making the boot disks a quick and easy process.  About 20 seconds between changes and I was rebooted on the CoCo testing out the latest driver changes.  This is where things started to get really complicated and other things did not go to well with my original design.  I spent a few days testing and debugging the code.  Finally it was clear that another hardware change was going to be required to make the project work.
Some custom makefiles and using drivewire Java version made things go even faster.  After a rebuild I just simply re-launched drivewire using the default.set option to specify the location of the .DSK image that was just rebuilt.  Once the server was up I could reset the CoCo and load in the new driver changes for testing.
I also used the DriveWire option to have a headless CoCo.  This allowed me to telnet to localhost on port 6810 and not use a monitor or the keyboard on the CoCo for testing.

Debugging the hardware/software

The use of *SCS was a problem as this gave me a SPI mode 3 type interface (clock normally high) and this is not technically what MMC/SD/SDHC cards typically use.  I needed a clock that was normally low and would clock high during data transfer(SPI mode 0).  I had to go back to the CoCo schematic and find another PIA I/O line that would work for a software clock.
After implementing the new hardware change I had to re-write the driver to use the new clocking bit.  This caused a few more bugs and fixed some other bugs.  Finally almost a week after starting the project I was able to read and write data to the card.  

Implementing low level driver drive size detection

One of the nice features of using SuperDriver is that ability for the low level driver to report the media size during format operations.  This was a very nice feature and so I decided that I would implement the code required to support this operation.
Using CMD9 of the MMC/SD card will return the CSD register (128 bits of data).  In this register from the card you will find the C_SIZE, C_SIZE_MULT and the WRITE_BLOCK_SIZE values.  Using these three values you can determine the size of the card.  For SDHC cards the CSD register format is a little different and calculating the size of the card is slightly different.  To decode the bits for each of these important values I created the following spreadsheet.  This gave me an idea of where the bits where and how my bytes I would need to store them.  

CSD Register worksheet

Running with MMC/SD storage

Unfortunately implementing a SPI bus in software is always going to be much slower then implementing one in hardware.  As a resut the Megaread times for the driver in OS9 are not that great.  Also remember that these times are on a CoCo 2 system running Nitros9 Level I.  

OS9:date -t;megaread </sd0@;date -t
April 02, 2010  22:58:20
April 02, 2010  23:04:55

Final thoughts

Of all the projects I have worked on for the CoCo  (IDE interface, MMC interface V1, and the 512k memory board) this was by far the fastest turn around time.  Within one week of dreaming up the design I had a working project with a completly functioning OS-9 driver up and working.
Now the next question is, what do you do with 32GB of SDHC space on a CoCo?

Pictures of the project

Jim Hathaway,
Apr 4, 2010, 10:38 AM
Jim Hathaway,
Apr 4, 2010, 10:38 AM
Jim Hathaway,
Apr 4, 2010, 10:39 AM
Jim Hathaway,
Apr 4, 2010, 10:39 AM
Jim Hathaway,
Apr 4, 2010, 10:39 AM
Jim Hathaway,
Apr 4, 2010, 10:39 AM
Jim Hathaway,
Apr 4, 2010, 8:07 PM