Connecting a Hard Disk to the MCF5249 IDE interface and sending data through the UART port

After thousands of queries at www.google.com, a couple hours boring my Advanced Microprocessors teacher Ronaldo Husemann and another couple hours of intensive programming with some friends of mine, I finally finished the project of acessing a hard disk using the ColdFire MCF5249 microprocessor integrated IDE chip and transmitting the read data through the UART port. I put the C source code created with the CodeWarrior IDE here so that one can explore it and possibly modify it for his own needs. Most of it is self explanatory if you have the ColdFire MCF5249 manual in hands. Well, in fact I found the manual not very didatic, but... :-)

Note: Use this source at your own risk! Everything gone right for me, but I can't assure you that the code is 100% correct, since I collected information from a lot of places over the internet and compiled them here.

Well, now that the disclaimer is done, take a deep breath, let it out slowly and read on! ;-)

This program was intented to communicate with the HD and send each read byte through the UART port. In fact, that's what it does.

I'll talk a bit about the main routine to explain some important things out:

Well, the first thing we must do is to configure the peripherals we want to use (UART and IDE chips, in this case). The configSerial() and setupIDE() function does exactly that.

Obs: You may notice some comments or even some function names are in portuguese. I pretend to change this someday, but let me tell you this is not my fault. Part of this code was made by some friends of mine who didn't care a lot about making things, let's say, "world readable".

Ok. Excuses apart, let's take a look at those functions:

- configSerial() only set the connection speed and other settings as parity, flow control, etc. Take a look at the manual to know what each register do.

- setupIDE() does the same thing plus set the GPIO19 as a writable pin (GPIO is a little misterious at the manual. What you have to know is that it sets the pins you want to use and how. In this case, we set the 20th bit, which means we'll use the 19th pin.) Then, comes the IDE Registers section. Here we define where are the IDE registers. For more information on those registers, follow this link. It was very useful for me. Although, there are some basic things I got stuck for a long time and I'm sure you'll thanks me for telling you before you start:

Okay. After setting up the basic configuration, we're ready to access the IDE functions.

As I told you, what I do is read a byte and send it through the serial port of the ColdFire processor. So, let's break the things into two parts:

  1. Reading data:

    It is a more or less simple step. Every hard disk is divided into Heads, Cylinders and Sectors and that order is very important. Sectors are usually 512 bytes long each. So, suppose you want to read 1024 bytes, they'll be divided into 2 different sectors of 512 bytes each. A set of sectors is called a Cylinder and a set of Cylinders is called a Head. Although we tend to see disks as contiguous things, they're not that contiguous. I'm telling you all this stuff to introduce the setPosition() function.

    This function receives as parameters a Head, a Cylinder and a Sector number. Then, it positionates the disk on the specified place, so that we can read the sector into IDE_DR (remember: 256 words = 512 bytes = 1 sector). One important thing I have to mention here is that after sending the READ command (that is, writting 0x0020 into IDE_CSR), you have to wait for the data to be ready for reading. This is made with the waitForDRQ() function. The DRQ bit is another of the IDE_ISR register bits.

    As we want to read the disk in contiguous mode without the need of care about heads, cylinders and sectors, I decided to create a simple (but not that efficient) algorithm to convert an integer position value into the appropriated head/cylinder/sector combination. This way, I can use the getByte() function do read an arbitrary byte inside the disk. What getByte() does is to take the position we want to access, convert it and call the setPosition() function.

    If you don't noticed yet, we have a little problem here: we're reading words, but what we want is to read bytes. To contour this, at the end of the getByte() function there is a routine to read the upper and lower bytes os the retrieved word. To do this, we must either put a 0x00 on the upper or lower 8 bits of the word. If the byte we're retrieving is odd, the byte we want is the 8 lower bits of the word. Otherwise, we want the upper 8 bits. On the later case, we must shift the resulting AND 8 bits to the right to be able to convert the entire word to a char (8 bits).

  2. Sending data to the UART:

    After reading a byte, I simply send it through the UART with the enviaSerial() function (read 'enviaSerial()' as something like 'UARTSendChar()', 'cause is that what it does). Inside the enviaSerial() function there is a while which waits until the Ready To Send bit of the UART is set, so that we can send the byte without the risk of loosing it because of a possible overflow. Then, we simply put the byte on the bus.

Well, that's it. The remaining code is (mostly) commented out and was only some experiments I made.

Hope this document can be useful to you. I'm always glad to hear your comments about it. If you have something to say, please let me know.

Back to main page

Valid HTML 4.01!