In this document I will describe how to connect a parallel ATA harddisk (further on simply
called HDD by me) to a 8Bit microcontroller (MCU). 8Bit, because I use these ones
myself. Of course it should be possible with a 16Bit or any other MCU, with a 16Bit
one it might be even simpler.
But before you think: "Wow, I need to build that, because thatīs what Iīve been
ever looking for!", read the Considerations.
A HDD connected to a MCU is useful where you have to log or compute large amounts of data.
But for something up to 4M or more, a FLASH device may be better suited. Keep in mind
that a HDD, because of its mechanical components, is shock sensitive, so donīt mount it
on your mountian bike. You may find it interesting, that Compact Flash (CF) Cards can
be used like HDDs. So you may use them in this case. A HDD also needs a lot more power
than a single FLASH chip and needs +5V and +12V (except some notebook types and the CF-Cards).
This is what it makes them absolutely unsuited for battery-powered devices.
What you have to expect in puncto data rates: First, the data rate mainly depends on the
speed of your MCU. 0.5kB/s to 3kB/s should be possible without big troubles. If you need
some MB/s, you need a horrendous fast MCU and you may have to use DMA and/or interrupts
what complicates it.
Another drawback is, that a HDD can only read and write blocks of 512B. If you have a really
tiny one (like the one I used for the serial interface) you donīt have the RAM to prepare
a block for reading/writing.
If you still think a HDD is the right thing for your MCU application, read on.
I think everyone knows the standard power connector.
Drive side (with commonly used cable colors on power cable) _______ / \ | o o o o | '---------' | | | | | | | '- 12VDC | | '--- 12V return (12V GND) | '----- 5V return (5V GND) '------- 5VDC
I will only explain the 40-Pin connector (the standard includes more), because it is the most spreaded one. But it shouldnīt matter since only the pin position is different.
.-----------------------------------------. 39 | . . . . . . . . . . . . . . . . . . . . | 1 40 | . . . . . . . . . . . . . . . . . . . . | 2 '-----------------------------------------'
A slash ("/") before a signal name indicates, that the signal is inverted.
| Signal names | |||
| Pin # | Host Device | Name | Description |
| 1 | --> | /RESET | This signal from the host system shall be asserted beginning with the application of power and held asserted until at least 25 us after voltage levels have stabilized within tolerance during power on and negated thereafter unless some event requires that the device(s) be reset following power on. |
| 2 | - | GND | |
| 3 | <--> | DD7 | Data signal |
| 4 | <--> | DD8 | Data signal |
| 5 | <--> | DD6 | Data signal |
| 6 | <--> | DD9 | Data signal |
| 7 | <--> | DD5 | Data signal |
| 8 | <--> | DD10 | Data signal |
| 9 | <--> | DD4 | Data signal |
| 10 | <--> | DD11 | Data signal |
| 11 | <--> | DD3 | Data signal |
| 12 | <--> | DD12 | Data signal |
| 13 | <--> | DD2 | Data signal |
| 14 | <--> | DD13 | Data signal |
| 15 | <--> | DD1 | Data signal |
| 16 | <--> | DD14 | Data signal |
| 17 | <--> | DD0 | Data signal |
| 18 | <--> | DD15 | Data signal |
| 19 | - | GND | |
| 20 | - | (keypin) | |
| 21 | <-- | DMARQ | Used for DMA data transfers between host and device. |
| 22 | - | GND | |
| 23 | --> | /DIOW | Write strobe signal from host. rising edge latches the data on DD0-DD15 into the device. |
| 24 | - | GND | |
| 25 | --> | /DIOR | Read strobe signal from host. Falling edge enables the data from the device on DD0-DD15 |
| 26 | - | GND | |
| 27 | <-- | IORDY | The use of IORDY is required for PIO modes 3 and above and otherwise optional. |
| 28 | CSEL | Used for automatic detection of device0 / device1 | |
| 29 | --> | /DMACK | This signal shall be used by the host in response to DMARQ to initiate DMA transfers. |
| 30 | - | GND | |
| 31 | <-- | INTRQ | This signal is used to interrupt the host system. |
| 32 | - | reserved | |
| 33 | --> | DA1 | For register selection |
| 34 | /PDIAG | The host shall not connect to the PDIAG- signal. | |
| 35 | --> | DA0 | For register selection |
| 36 | --> | DA2 | For register selection |
| 37 | --> | /CS0 | For register selection |
| 38 | --> | /CS1 | For register selection |
| 39 | /DASP | Indicates that a device is active, or that device 1 is present. Most of the time a LED is connected to it. | |
| 40 | - | /GND | |
Of course, you donīt need all them for basic interfaceing.
The ones I used are:
DA0, DA1, DA2, /CS0, /CS1, DD0-DD15, /RESET, /DIOR, /DIOW, /DASP
Where I put the following ones on GND:
GND, CSEL
For /CSEL you donīt need a I/O Pin of you MCU, because only the HDD-busy-LED is connected to it.
You know that from your PC. Use a 1k pullup and a LED in the following way:
^ +Ub
/DASP |
o----|<|---\/\/\/\-----'
LED 1k
I put CSEL on GND to be on the safe side, but I donīt use it, since I am jumpering the HDD
as Master or Slave and not for CSEL use. I think this is the minimal wiring which works, but
you still need a lot of I/O pins of your MCU.
The HDD is used like as a set of registers. The bidirectional data bus is DD0-DD15 and the
address selection is done by DA0-DA2, /CS0 and /CS1. Many of them have a bitwise meaning.
| HDD registers | ||||||
| Addresses | Functions | |||||
| /CS0 | /CS1 | DA2 | DA1 | DA0 | Read (/DIOR) | Write (/DIOW) |
| N | N | x | x | x | Data bus high impendance | Not used |
| N | A | 0 | x | x | Data bus high impendance | Not used |
| N | A | 1 | 0 | x | Data bus high impendance | Not used |
| N | A | 1 | 1 | 0 | Alternate Status | Device control |
| N | A | 1 | 1 | 1 | Obsolete | Not used |
| A | N | 0 | 0 | 0 | Data | Data |
| A | N | 0 | 0 | 1 | Error | Features |
| A | N | 0 | 1 | 0 | Sector count | Sector count |
| A | N | 0 | 1 | 1 | Sector number LBA 0-7 | Sector number LBA 0-7 |
| A | N | 1 | 0 | 0 | Cylinder low LBA 8-15 | Cylinder low LBA 8-15 |
| A | N | 1 | 0 | 1 | Cylinder high LBA 16-23 | Cylinder high LBA 16-23 |
| A | N | 1 | 1 | 0 | Device/Head LBA 24-27 | Device/Head LBA 24-27 |
| A | N | 1 | 1 | 1 | Status | Command |
| A | A | x | x | x | Invalid address | Invalid address |
To write a register do the following:
I will describe here how *I* did the interfaceing. This does not mean that it sticks absolutely
to the standard, but it works (at least for me).
I only use the READ SECTOR(S) with retries and the WRITE SECTOR(S) with retries commands.
(Command code: 0x20 and 0x30).
To read a sector from the hdd do the following, assuming that interrupts are turned off:
I descibe only the hardware reset and only for a one-device-configuration, since Iīve never used software reset or two devices. To do the reset, you have to pull the /RESET wire low and keep it low for at least 25us. Then reset it to high. After that you should poll the Status register and wait till the the BSY bit is low and the DRDY is high. Thatīs all.
All MCU firmware downloadable here is for a MCU clock frequence of 20MHz even if the
schematic says 4MHz
The assembler source for Microchips MPLAB can be downloaded here:
V7.2 (for board Rev. 0.35): serhdd72.asm (Baud rate: 57600)
V7.3 (for board Rev. 0.35): serhdd73.asm (Baud rate: adjustable)
There is also a INTEL-Hex-file available here:
V7.2 (for board Rev. 0.35): serhdd72.hex (Baud rate: 57600)
V7.3 (for board Rev. 0.35): serhdd73.hex (Baud rate: adjustable)
A GIF of the schematic is available here:
Rev. 0.35: rev0_35.gif
A high resolution (360dpi) GIF of both sides of the board is available here:
Rev. 0.35: rev0_35_toplayer.gif, rev0_35_bottomlayer.gif
You have to resize them to 100mm x 80mm.
A face plan is available here:
Rev. 0.35: rev0_35_faceplan.gif
The source of the Linux program I used to the test whole thing can be downloaded here: hdd3.c [view online]
Note: The program is fairly incomplete. In fact these are more code fragments than a really usable
program, but you can use it for testing and experimenting. It only works with firmware Rev. 7.3.
As the name says, the modules is intended to be an interface. If you build it, you still need another MCU or a PC which is controlling it. It is absolutely useless otherwise. The module uses only Device 0 (Master) for the HRDCHS, HWRCHS, HRDLBA, HWRLBA and HIDENT commands.
| Command table | ||
| Command synonym | Hex code | Short description |
| HNOP | 0x00 | Interface NOOP. Sends the HNOP code back to the host. |
| HWBSY | 0x01 | Waits while the HDD is busy. |
| HWDRQ | 0x02 | Waits till the HDD is ready for data transfer. |
| HRESET | 0x03 | Does a HDD hardware reset. |
| HRDREG | 0x04 | Read a HDD register. |
| HWRREG | 0x05 | Write a HDD register. |
| HIDENT | 0x06 | Issues the IDENTIFY DEVICE command and sends the data. |
| HRDDATA | 0x07 | Read the data register. |
| HWRDATA | 0x08 | Write the data register. |
| HRDCHS | 0x09 | Read a block at a given CHS address. |
| HWRCHS | 0x0A | Write a block at a given CHS address. |
| HRDLBA | 0x0B | Read a block at a given LBA address. |
| HWRLBA | 0x0C | Write a block at a given LBA address. |
| Status byte table | ||
| Status byte synonym | Hex code | Short description |
| ERR | 0x20 | Error |
| CSUMERR | 0x21 | Checksum error |
| RDY | 0x22 | Ready |
| NOSUPP | 0x23 | Command not supported. (Not used in V7.2. A not supported command does simply nothing. |
| Address bytes for HRDREG and HWRREG | ||
| Register | Hex code | Bits |
| Data | 0x02 | 00000010b |
| Error/Features | 0x06 | 00000110b |
| Sector count | 0x0A | 00001010b |
| Sector number | 0x0E | 00001110b |
| Cylinder low | 0x12 | 00010010b |
| Cylinder high | 0x16 | 00010110b |
| Device/Head | 0x1A | 00011010b |
| Status/Command | 0x1E | 00011110b |
| Features/Device control | 0x1D | 00011101b |
Bit 7 Bit 0
| |
V V
_______________
| | | | | | | | |
---------------
DA2 /CS0
DA1 /CS1
DA0
After this byte, the interface reads the register content and sends it.
Bit 7 Bit 0
| |
V V
_______________
| | | | | | | | |
---------------
DA2 /CS0
DA1 /CS1
DA0
After this byte, the interface waits for the register contents to write. If it has received the
register content, it writes the HDD register.
A small HDD protocol bugfix and a new command to allow the host software to adjust the baudrate. After reset (power on or reset button) the module starts with a baudrate of 9600.
| Baudrates | |
| Hex code | Baud rate |
| 0x81 | 9600 |
| 0x40 | 19200 |
| 0x20 | 38400 |
| 0x15 | 57600 |
| 0x0A | 115200 |
For the capacitators you should use the following ones:
| Capacitator types | |
| Cap. number | Type |
| C1, C2, C10, C11, C13, C12, C14 | Ceramic, 16V or higher |
| C20, C21, C22, C23, C19 | Tantal, 16V or higher |
| C8, C9, C3, C4, C5, C6, C7 | Elko, 16V or higher |
You can view them here
The main resource was the ATA3 standard draft revision 3. It can be found here:
d2008r7b.pdf
I also used this text file a bit for orientation:
ide.txt
Thatīs all. You shouldnīt need more for what Iīve done.
Q: What about CDROM drives?
A: I donīt think that a CDROM drive is really needed for a MCU application. Most drives use
ATAPI commands. You would have to implement them (firmware + host software) but the interface itself might be the same.
Q: What about CD-Writers?
A: Youīd have to be very good to prevent a buffer underrun. Read "What about CDROM drives?".
Q: What about Floppy drives?
A: At the beginning of this project (the planning in my head) I wanted to make a floppy
disk drive, because of the removable media. But floppies are *very* stupid drives. To write to any
magntical storage media you need to modulate the data. This modulation has to be done *external* for
floppy drives. You canīt transfer the data directly like with the HDD. This makes is very complicated
unless you use a floppy disk controller IC which are not easy to get and SMD most of the time.
Copyright (C) 2003 by Wiesner Thomas
Last change: November 11th 2006