IDE Paralel ATA hard disk drive tutorial
If your are like me, you have too many old hard disks laying around. I have gathered quite a collection of drives from PC's I have had in the past. Now you can dust off your drives and put them in your circuit. I have extra drives ranging in size from 171MB to 120GB.
Before you start, make sure you use a drive you do not care about. We are not responsible for your drive of the data that is on it.
You can find more general info at http://en.wikipedia.org/wiki/Parallel_ATA, and you can find more detailed technical info at http://www.gaby.de/gide/IDE-TCJ.txt
There are two types of hard disks PATA (parallel ata) and SATA (serial ata). In this tutorial we will use PATA, these drives use a 40 pin IDE connector. The newer type of drive SATA has only 7 pins but there is no Jallib library for these drives at the moment. Both types of hard disks are available with massive amounts of data space.
The current jallib library will accept drives up to 128GB. The 128GB limit is due to and addressing limitation, this is the 28 bit addressing limitation.The max address you will be able to reach is hex 0xFFFFFFF. If you multiply this address by 512 bytes (1 sector) you get a max size of 137,438,952,960 bytes, yes this does equal 128GB. Eventually I may upgrade the library for 48bit addressing which will allow up to a max drive size hex 0xFFFFFFFFFFFF * 512 = 128P Petabytes. But now that I think about it, 128 GB should be enough!
The most common drive sizes today are 3.5" and 2.5". The 3.5 inch drives are commonly used in desktop computers, 2.5" drives are used in laptops. The 2.5" drives are nice for your circuit because they do not require a 12v supply voltage, and they use much less power.
If you wish to use a 2.5" laptop hard drive, you may need a 2.5" to 3.5" IDE adapter like this one:
Now, if your going to put one of these into your circuit, you'll need to plug the drive into your breadboard. I took a 40pin IDE connector off an old motherboard. The easiest way to get large components of a board is to use a heat gun on the bottom side of the board to melt the solder on all pins at once.
Now take this connector and stick it into some blank breadboard and add some pins. The blank breadboard I cut is 4 holes wide by 20 long. Put the connector in the middle and connect the pins on the outside, join each pin with each pin of the connector.
Of course you will also need a 40pin IDE cable, I like the ones with the notch so you don't plug it in backwards. Here's the one I made:
It is very important that you have enough power to drive your circuit. Hard drives need a lot of amps to run, especially the 3.5" drives, so make sure you have a decent 5v and 12v power supply. I suggest that you DO NOT use your PC's power supply to drive your circuit. You can easily short circuit your power supply and blow up your PC. If you really insist on doing this, you better put a fuse on both 5v and 12v between your PC and your circuit. Just remember that I told you not to!
Pin 1 on the IDE cable is the red stripe. Here the pin out for the male connector I took off a motherboard:
| PIN | FUNCTION | PIN | FUNCTION |
|---|---|---|---|
| 1 | /RESET | 2 | GND |
| 3 | D7 | 4 | D8 |
| 5 | D6 | 6 | D9 |
| 7 | D5 | 8 | D10 |
| 9 | D4 | 10 | D11 |
| 11 | D3 | 12 | D12 |
| 13 | D2 | 14 | D13 |
| 15 | D1 | 16 | D14 |
| 17 | D0 | 18 | D15 |
| 19 | GND | 20 | NO PIN |
| 21 | 22 | GND | |
| 23 | /IOWR - READ Pin | 24 | GND |
| 25 | /IORD - Write Pin | 26 | GND |
| 27 | 28 | ALE - 1K resistor to 5v | |
| 29 | 30 | GND | |
| 31 | 32 | ||
| 33 | A1 | 34 | |
| 35 | A0 | 36 | A2 |
| 37 | /CS0 (to 5v) | 38 | /CS1 (to GND) |
| 39 | ACT - BUSY LED | 40 | GND |
Build the circuit below. As you can see it is quite simple. As you can see, it only requires 3 resistors, a led and a bunch of wire. You can put a reset button on the IDE connector if you like, but I have found no use for it so I connect it direct to 5v.
Here's what the completed circuit should look like (don't turn on the power yet):
The hard disk lib (pata_hard_disk.jal) and a sample file (16f877_pata_hard_disk.jal) will be needed for this project. You will find these files in the lib & sample directories of your jallib installation.
The most up to date version of the sample & library can be found at:
Sample file - http://jallib.googlecode.com/svn/trunk/sample/16f877_pata_hard_disk.jal
Library file - http://jallib.googlecode.com/svn/trunk/include/external/storage/harddisk/pata_hard_disk.jal
Now lets test it and make sure it works. Compile and program your pic with 16f877_sd_card.jal from your jallib samples directory. If you are using another pic, change the "include 16f877" line in 16f877_sd_card.jal to specify your PIC before compiling.
Now that you have compiled it, burn the .hex file to your PIC with your programmer
Plug your circuit into your PC for serial port communication at 38400 baud rate. Now turn it on. It should do the following in this order:
Hex output
In the first image, If your disk is formatted with fat32 you may be able to see some readable data as well as some junk. There is too much data for me to show it all in the image, on my drive formatted with fat32 I can read "Invalid partition t ableError loading operating system..."
In the second image (after clearing the output and resetting the circuit), there was too much data to show it all again. It only shows the last bytes received. If you get the same hex output "CC DD" followed by many "FF", your circuit has successfully written data and read it back again. You now have a working hard disk circuit!
I will go over some of the key points you need to know about hard disk coding. Open the sample file with an editor if you have not done so already. The code in the sample file may change, therefore it may be different then what you see here. The sample file you have downloaded will always be tested and correct.
Include the chip
Select the PIC you wish to use and your clock frequency
-- include chip include 16F877a -- target PICmicro pragma target clock 20_000_000 -- oscillator frequency -- configure fuses pragma target OSC HS -- HS crystal or resonator pragma target WDT disabled -- no watchdog pragma target LVP disabled -- no Low Voltage Programming
Disable all analog pins
enable_digital_io() -- disable all analog pins if any
Include required libraries
include delay -- include the delay library
Setup serial port and choose baud rate 38400
-- setup uart for communication const serial_hw_baudrate = 38400 -- set the baudrate include serial_hardware serial_hw_init()
Setup the hard disk library constants/settings
The registers Alternate Status, Digital Output, and Drive Address registers will only be used by advanced users, so keep the default PATA_HD_USE_CS0_CS1_PINS = FALSE
The pins /iowr, /iord, /cs0, /cs1 are active low pins that are supposed to require an inverter. If you leave PATA_HD_NO_INVERTER = TRUE, the PIC will do the inversion for you. You will most likely want to keep the default "TRUE".
-- setup hard disk library -- set true if you will use Alternate Status, -- Digital Output or Drive Address registers const byte PATA_HD_USE_CS0_CS1_PINS = FALSE -- if true, an external inverter chip is not -- needed on /iowr, /iord, /cs0, /cs1 pins const bit PATA_HD_NO_INVERTER = TRUE
Setup pin assignments
Yes, pata hard disks have a lot of pins. You will need two full 8pin port's (port B and port D of 16F877) for data transfer, three register select pins, one read pulse pin and one write pulse pin. A total of 19 io pins. I am able to comment out cs1/cs0 and save pins because of the constant we set.
-- pin assignments alias pata_hd_data_low is portb -- data port (low bits) alias pata_hd_data_low_direction is portb_direction alias pata_hd_data_high is portd -- data port (high bits) alias pata_hd_data_high_direction is portd_direction alias pata_hd_a0 is pin_a3 alias pata_hd_a0_direction is pin_a3_direction alias pata_hd_a1 is pin_a1 alias pata_hd_a1_direction is pin_a1_direction alias pata_hd_a2 is pin_a0 alias pata_hd_a2_direction is pin_a0_direction alias pata_hd_iowr is pin_e0 alias pata_hd_iowr_direction is pin_e0_direction alias pata_hd_iord is pin_a4 alias pata_hd_iord_direction is pin_a4_direction ;alias pata_hd_cs1 is pin_a3 ;alias pata_hd_cs1_direction is pin_a3_direction ;alias pata_hd_cs0 is pin_a4 ;alias pata_hd_cs0_direction is pin_a4_direction pata_hd_a0_direction = output -- register select pin pata_hd_a1_direction = output -- register select pin pata_hd_a2_direction = output -- register select pin pata_hd_iowr_direction = output -- used for write pulse pata_hd_iord_direction = output -- used for read pulse ;pata_hd_cs1_direction = output -- register select pin ;pata_hd_cs0_direction = output -- register select pin
Now include the library
include pata_hard_disk -- include the parallel ata ide hard disk library pata_hd_init() -- initialize startup settings
Add user's procedure and variables
Hard disks send data 2 bytes at a time since there are two 8 pin data ports, so I made a small serial port procedure to send 2 bytes via the serial port:
-- Function for sending hard disk data via serial -- port, data is read 2 bytes at a time. procedure send_word(byte in lowbit, byte in highbit) is serial_hw_write(lowbit) -- send 1st serial data byte serial_hw_write(highbit) -- send 2nd serial data byte end procedure
Now declare variables for recieved data
-- Declare variables for this example. var byte in_a var byte in_b
Wait for power to stabilize then send "START" to the serial port to notify the user (YOU) that the program has started ok
_usec_delay (1_000_000) -- wait for power to stabilize
-- send "start" to pc / test uart communication
send_word("S", "T")
send_word("A", "R")
send_word("T", 0x20)
send_word(13, 10)
send_word(13, 10)
Spin Up/Spin Down test
It is important to know if we have some basic communication to the drive. We will try to spin up (turn on the drive's motor) and spin down (turn off the drive's motor). This will simply send the "spin up" command to the command register then "spin down", then it will do the same once more. This shows that we have communication from your PIC to the hard drive.
for 2 loop pata_hd_register_write(PATA_HD_COMMAND_REG,PATA_HD_SPIN_UP) -- turn on motor _usec_delay(5_000_000) -- 5 sec delay pata_hd_register_write(PATA_HD_COMMAND_REG,PATA_HD_SPIN_DOWN) -- turn off motor _usec_delay(5_000_000) -- 5 sec delay end loop pata_hd_register_write(PATA_HD_COMMAND_REG,PATA_HD_SPIN_UP) -- turn on motor
Wait 10 seconds before next example
_usec_delay(10_000_000) -- wait 10 seconds before next example
Read the first and second sector from the hard drive
Now that we know we are able to write to the registers, we can try to read some data. One sector is 512 bytes. Since data is transfered 2 bytes at a time, we will loop 256 times to read one full sector while sending the data via serial port.
Reading is easy, there are 3 procedures within the library that MUST be used. You will notice this process is similar to the SD card tutorial.
pata_hd_start_read(0) - start reading at specified sector (sector 0)
pata_hd_read_data(byte1, byte2) - actually read data from the card (2 bytes at a time)
pata_hd_stop_read() - stop the read process
You can also use the pata_hd_read_pulse(number) procedure to skip past data. For every 1 value added, there will be 2 bytes skipped since this procedure simply reads data and ignores the input.
-- Read one sector for 256 loop -- 256 words, 512 bytes per sector pata_hd_read_data(in_b, in_a) -- read data send_word(in_b, in_a) -- send data via serial port end loop -- You will see hard disk LED on during this delay -- because you did not finnish reading. _usec_delay(2_000_000) -- 2 second delay -- Read 2nd sector. for 256 loop -- 256 words, 512 bytes per sector pata_hd_read_data (in_b, in_a) -- read data send_word(in_b, in_a) -- send data via serial port end loop pata_hd_stop_read() -- tell drive you are done reading -- hard disk led will turn off at this point. _usec_delay(10_000_000) -- wait 10 seconds before next example
Identify drive command
The identify drive command loads 512 bytes of data for you that contains information about your drive. You can retrieve info like drive serial number, model number, drive size, number of cylinders, heads, sectors per track and a bunch of other data required by your PC. Of course you can read more info on this at the links I have given you.
On the sticker of some older drives, you will see "CYL", "HEADS", "SEC/T" (this can also be found with the Identify command). You can calculate drive's addressable sectors with (cylinders * heads * sectors per track), and multipy that by 512) for the size of the drive.
On newer drives, you will see on the front sticker the number of LBA's, this is the number of addressable sectors. If you multiply this value by 512, you will get the size of the drive in bytes. For example, one of my drive says 60058656 LBA's. With this drive, you can send a pata_start_read command with a addresses from 0 to (60058656 - 1). The size of this drive is 60058656 * 512 = 30GB
Let's try it out, first we send the command:
-- send the identify drive command pata_hd_register_write(PATA_HD_COMMAND_REG,PATA_HD_IDENTIFY_DRIVE)
Now we must wait till the drive is ready and has data for us:
-- check if drive is ready reading and set data ports as inputs -- this MUST be used before reading since we did not use pata_hd_start_read pata_hd_data_request(PATA_HD_WAIT_READ)
The drive is now has data for us, so let's read it. Notice that the input data bytes (in_b & in_a) are backwards for identify drive (don't ask me why).
-- Read 512 bytes for 256 loop -- 256 words, 512 bytes per sector pata_hd_read_data(in_b, in_a) -- read data send_word(in_a, in_b ) -- send data via serial port end loop -- drive info high/low bytes are in reverse order
Wait 10 seconds before the next example
_usec_delay(10_000_000) -- wait 10 seconds before next example
Write data to the drive
Just like reading, there are 3 procedures that MUST be used.
pata_hd_start_write(20) - start writing at specified sector (sector 20)
pata_hd_read_data(byte1, byte2) - write to the card (2 bytes at a time)
pata_hd_stop_write() - stop the read process
When writing to your hard drive, you MUST write 512 bytes at a time. In this example, we are writing (256x2) = 512 bytes + (250x2) = 500 bytes for a total of 1012 bytes. This means we have written one sector (512 bytes), as well as 500 bytes of the next sector. The second sector (500 bytes) that we have written, will not actually be written to the hard drive until we finish the sector with data.
For this reason, you will need to use the pata_hd_write_to_sector_end(value) procedure. This procedure will automatically finish the sector for you with the "value" data specified. In our case we are writing 0xFF till the end of the 512 bytes (end of the sector).
Here's an example write, Please note that we are starting to write at sector 200
pata_hd_start_write(200) -- tell hd to get ready for reading -- now write 1 sector + most of 2nd sector, data will not -- be written unless 512 bytes are sent for 256 + 250 loop pata_hd_write_data(0xCC, 0xDD) -- write data 0xCC, 0xDD over and over end loop -- first sector has been written to the disk since 512 bytes where sent, -- but 2nd sector is not finnished, only 500 bytes sent, -- so lets finnish the sector with 6 more write pulses (0xFF's as data) pata_hd_write_to_sector_end(0xFF) pata_hd_stop_write() -- tell hd we are done writing
Now read back the data the 1012 bytes have been written
-- Now read the 1st sector you just wrote, should get -- 0xCC, 0xDD over and over pata_hd_start_read(200) -- get drive ready for reading for 256 + 250 loop -- read 512 bytes + 500 bytes pata_hd_read_data(in_b, in_a) -- read data send_word(in_b, in_a) -- send data via serial port end loop -- if you want, you can read back the last 6 bytes that are 0xFF for 6 loop pata_hd_read_data(in_b, in_a) -- read data send_word(in_b, in_a) -- send data via serial port end loop pata_hd_stop_read() -- tell drive we are done reading
If you want, you can turn off the hard drive motor at the end of the program
-- We're done, lets turn off the hd motor pata_hd_register_write(PATA_HD_COMMAND_REG,PATA_HD_SPIN_DOWN)
That's it, Now you can read & write to all those hard drives you have laying around. You can read raw data from drives and possibly even get back some lost data.
Alright, go build that hard disk thingy you where dreaming about!
Contact Us | Terms of Use | Trademarks | Privacy Statement
Copyright © 2009 . All Rights Reserved.
Powered by Drupal and Drupal Theme created by vigilianty.