Stepping Through the Port

Now Im ready to start with the port. I will depend on the vendor for information about the evaluation system. The most critical resources are

  • the CPU data sheet

  • the flash (AM29PL160C) data sheet

  • serial port (part of processor) data sheet

  • Ethernet device (part of processor) data sheet

  • the schematics of the evaluation board

  • the source code for the boards monitor

(The .pdf files for each of these documents can be retrieved from Motorola and AMDs web sites.)

The text that follows is specific to the MCF5272C3 evaluation board. I keep the descriptions as general as possible, so that it is clear how the steps apply to other systems. If you plan to use this example as a guide while porting to some other evaluation board, then it is important that you be familiar with the board and its documentation before you start.

Downloading the First Image

First, I need to establish some plan regarding how I am to get the code (in binary form) onto the target. In earlier chapters, I mentioned three alternatives: BDM, JTAG, and manual flash burning with an external programmer and a socketed boot ROM. In this case, I have a fourth alternative. The evaluation board ships with a boot monitor (not MicroMonitor) in flash memory, so I can use this boot monitor to download the programs to test them out.

If I develop in this mode, I need to be careful about one important hazard . As I write and test my boot firmware and device drivers, I need to be careful that I dont inadvertently make them dependent on the original firmware or on some value it leaves behind. A nice feature of the MCF5272C3 is that the flash memory can be configured as two separate blocks, either of which can be mapped into the space containing the reset vector (depending on the setting of a jumper .) This approach allows you to boot into the provided monitor while loading your code but to boot into your code for testing. The process is

  • boot with the provided monitor handling the reset,

  • download your code into RAM,

  • transfer your code to the alternate block of flash,

  • change the jumper, and

  • reset the board.

At the reset, the system is executing (booting from) the newly downloaded code, which is a really nice way to test your own boot code. If your code works when tested using this approach, you know that it works on its own that its not inadvertently benefiting from some setup performed by the original monitor. If your code doesnt work, then all you need to do is change the jumper back to the original position and you have the original monitor on which to fall back. This feature is really handy!

Before transferring to flash memory, I need the ability to download code and execute the code at the location to which I just downloaded it. The MCF5272CE monitor has a command called dl that allows you to transfer S-record files from a host and a command called go that allows you to transfer control to a specified address in the memory space.

With these facilities in the monitor, most terminal emulation programs should be able to transfer a file in its raw mode to the target. I chose to use my own tool (called com) simply because using something I wrote allows me to be certain of what is happening on the serial port connection. Plus, since com comes on the CD, its a tool you will have at your disposal. To prepare for the transfer, I connect an RS-232 cable from the PCs COM port to the terminal DB9 connector on the evaluation board and apply power to the evaluation board. For this particular hardware, there is no need for a NULL modem. The targets monitor is expecting the host to transmit at 19,200 baud, no parity, 8-bit chars, 1 stop bit. All normal stuff. To connect to COM port 2 at 19,200, I enter this command line (on the host) at a console prompt: com b19200 p2 .

Note 

The monitor shipped with the MCF5272CE also has facilities that support a network download (the dn command) in conjunction with a small TFTP server. We will stick with the serial port downloader just to keep things simple and to eliminate the unknowns of the Ethernet connection at this point.

At this point, the com program is waiting for characters from the COM port or the console port. If com gets a character from the COM port, com displays the character at the console. If com gets a character from the console port, com transfers the character to the COM port interface. If you hit return now, you should see the dBUG> prompt displayed. This prompt confirms connectivity between the host and the target evaluation board. I can now start building the monitor and testing it, piece by piece.

Referring to code in the targets/eval5272/monitor directory, the config.h file should be configured with all INCLUDE_XXX macros set to and FORCE_BSS_INIT defined. This process builds an absolutly minimum monitor. The file reset.s is based on a few files from the MCF5272CE monitor. [1] The reset.s file calls peripheral initialization functions (also part of the MCF5272CE monitor) and eventually calls start() . After I get to start() and get the serial port running, I am over a major hurdle . For the this evaluation board, writing the code for the serial port was simple because the code for the MCF5272CE monitor is organized quite well. I extracted functions to perform serial port putchar / getchar /gotachar functionality and inserted them into the MicroMonitor framework ( cpuio.c ). If this code works, I have an initialized target with a working serial port. So I need to build it, download it, and see if it runs.

The makefile can build a RAM- or ROM- (flash memory) based image. At this point I want a RAM-based image, so I execute make ram . This make process compiles each of the monitor modules, links all of the modules to a particular memory map ( RAM.lnk ), and then converts the COFF file, first to binary and then to S-records (because thats what the dl command is expecting).

Now I am ready to download the first test image. At the dBUG> prompt, I type dl , and then ctrl-x to tell the com program what file to transfer to the target. Next I type monCFEVAL.srec because thats the file that the bin2srec tool in the makefile created.

This procedure causes a lot of dots (one per S-record line) to be printed on the console window of the PC. The dots let me know that the data is being transferred. After the process completes, I see a message that indicates that the S-record file transfer completed successfully, and the dBUG> prompt returns.

At this point, the image is at location 0x80000 in the DRAM space of the evaluation board (refer to evaluation board documentation for more details if interested). I can now use the go command to execute some function or set of functions in the downloaded space. I need to determine the address of the start function, so I search (using grep ) the symbol file created by the makefile ( monCFEVAL.sym ) for the address. I then type go 0xADDR where ADDR is the address of the start function. This action results in startup of the MicroMonitor in the RAM space of the evaluation board. The output looks something like Listing 13.13.

Listing 13.13: Output for MicroMonitor Startup.
image from book
 dBUG> go 80450                                  MICRO MONITOR                               CPU: ColdFire 5272                    Platform: Coldfire 5272 Evaluation Board                          Built: 09/14/2001 @ 21:16:42                         Monitor RAM: 0x091310-0x0a4234                         Application RAM Base: 0x0a5000 uMON> 
image from book
 

The text of Listing 13.13 illustrates a few neat steps. I started off with the monitor that is installed on the boot flash of the evaluation board (dBUG). This monitor produced the dBUG> prompt at the top of the listing. The go command is issued with the address of the start() function (in the monitor binary that I just downloaded), which transfers control to the MicroMonitor. The first visual thing that MicroMonitor does is print a header, reporting the platform and CPU name and followed by a description of where it thinks its memory is. The final thing to notice in this listing is the new prompt, uMON> . This prompt lets me know that MicroMonitor is now running.

Ive verified a lot already. I can build and download a monitor image, plus the code I built actually works. If the code didnt work, then I would not have seen the MicroMonitor header and uMON> prompt. Just as a sanity check, I can type help at the uMON> prompt, and I should see something like Listing 13.14.

Listing 13.14: Type help as a Sanity Check.
image from book
 uMON>help call        echo        heap        help        ?           mstat reg         reset       set         sleep       ulvl        version uMON> 
image from book
 

Notice that not many commands are available at this point, which is because all the INCLUDE_XXX macros were set to zero. I can now start enabling some additional features. The next major feature should be flash memory, but, before working on that, turn on INCLUDE_MEMCMDS and INCLUDE_XMODEM . After enabling these two #defines , I rebuild and download as before. The help list (Listing 13.15) now includes cm , dm , fm , mt , pm , and sm . These commands make up the memory display, test, and modify commands pulled in by INCLUDE_MEMCMDS . The additional xmodem command is pulled in as a result of setting INCLUDE_XMODEM .

Listing 13.15: Expanded Help List.
image from book
 uMON>help call        cm          dm          echo        fm          heap help        ?           mstat       mt          pm          reg reset       set         sleep       sm          ulvl        xmodem version uMON> 
image from book
 

I now have a system that can run as a functional boot monitor. I have the ability to issue commands (obviously), display/modify/test memory ( cm , dm , fm , mt , pm , and sm ), download data into RAM ( xmodem ), and jump into the downloaded data ( call ). Note that all of these new commands are from source code in the common directory. They involve absolutely no target-specific code, so as soon as I have the basic serial port driver working, I can immediately throw in INCLUDE_MEMCMDS and INCLUDE_XMODEM .

At this point, if we werent running on top of another monitor, I would begin using xmodem to download small programs using MicroMonitors xmodem and call commands (similar to the way I am downloading the whole monitor using Motorolas dl and go ).

Enabling the Flash Driver

Next in the list of drivers is the flash device. Getting these drivers running is a multi-step process. The first step is to get to know the device and how it is connected to the CPU. In this case, the flash device has a 16-bit connection to the CPU, starting at address 0xffe00000 . The device has 11 sectors with the sizes (in bytes) specified in the SectorSizes160C[] array of common/flash/29pl160c/flashdev.c (also shown in Listing 13.16). Because the driver functions are copied to RAM, I must make sure that during FlashInit() (front end of the flash driver initialization) the instruction and data caches are disabled.

I construct my first iteration of the driver by defining INCLUDE_FLASH to 1 in config.h and executing the rebuild/download steps, which pulls in the flash code from common/monitor/flash.c and common/flash/29pl160c/*.* .

Listing 13.16: Sector Size Array.
image from book
 /* SectorSizes160C:  *  There are a total of 11 sectors for this part.  This table reflects the  *  size of each sector in bytes.  */ int SectorSizes160C[] = {         0x4000,  0x2000,  0x2000,  0x38000, 0x40000,         0x40000, 0x40000, 0x40000, 0x40000, 0x40000,         0x40000 }; struct sectorinfo sinfo160[sizeof(SectorSizes160C)/sizeof(int)]; 
image from book
 

Eventually this ports flash driver provides the following: device identification, sector erase, write, and atomic erase-write. I begin with device identification, because that is the easiest feature to implement and test. For the AM29PL160C, the device ID is read as a manufacturer ID and a device ID. The read involves writing the AutoSelect command to the device and is handled by the function Flashtype16() in common/flash/29pl160c/flashpic.c . I know that this ID [2] was properly received because MicroMonitor did not generate an error message when I restarted it with the new build. If the ID did not match with what the data sheet stated, the driver would indicate a device ID failure, which could mean the code is wrong or that the hardware does not properly support a write to the flash device.
[1]

I can also verify that the driver has properly established the sector sizes for the device by issuing a flash info command. The resulting report (in Listing 13.17) shows what the monitor thinks is the sector map for the device. Before proceeding, if I were writing this code from scratch, I would step back and verify that each sector size matches the sector size specified in the data sheet.

The next task, in order of complexity, is the flash erase command. However, I cant test flash erase if I havent written anything to the flash memory, so I look at the flash write command. Having gotten through the flash type ( AutoSelect ) process, the other interfaces are similar, just a bit more involved. The flash write process ( Flashwrite16() in common/flash/29pl160c/flashpic.c ) is similar to Flashtype16() but uses a different command sequence and writes data after the command sequence (instead of reading, as was the case for Flashtype16() ).

Listing 13.17: Device Sector Map.
image from book
 uMON>flash info Device = AMD-29PL160C   Base addr   : 0xffe00000   Sectors     : 11   Bank width  : 2   Sector     Begin       End        Size     SWProt?  Erased?      0    0xffe00000  0xffe03fff  0x004000    yes       no      1    0xffe04000  0xffe05fff  0x002000    yes       no      2    0xffe06000  0xffe07fff  0x002000    yes       yes      3    0xffe08000  0xffe3ffff  0x038000    yes       no      4    0xffe40000  0xffe7ffff  0x040000    yes       no      5    0xffe80000  0xffebffff  0x040000     no       no      6    0xffec0000  0xffefffff  0x040000     no       no      7    0xfff00000  0xfff3ffff  0x040000     no       no      8    0xfff40000  0xfff7ffff  0x040000     no       no      9    0xfff80000  0xfffbffff  0x040000     no       no     10    0xfffc0000  0xffffffff  0x040000     no       no uMON> 
image from book
 

There is one added catch here. Because I am working with a 16-bit device and each write to the device is an aligned 16-bit quantity, I must deal with the possibility that the starting address might be odd or the ending address might be even. Either or both of these situations are very likely, so the driver must deal with them. The Flashwrite16() function has a front end that deals with the possibility of an odd starting address and a back end that deals with the possibility of not ending on an odd address. Listings 13.18 through 13.20 show the front end, middle block, and back end of the Flashwrite16() function.

Listings 13.18: Front End of Flashwrite16() Function.
image from book
 int Flashwrite16(struct flashinfo *fdev,uchar *dest,uchar *src,long bytecnt) {     ftype   val;     long    cnt;     int     i, ret;     uchar   *src1;     ret = 0;     cnt = bytecnt & ~1;     src1 = (uchar *)&val;     /* Since we are working on a 2-byte wide device, every write to the      * device must be aligned on a 2-byte boundary.  If our incoming      * destination address is odd, then decrement the destination by one      * and build a fake source using *dest-1 and src[0]...      */     if (NotAligned(dest)) {         dest--;                  src1[0] = *dest;         src1[1] = *src;         /* Flash write command */         Write_aa_to_555();         Write_55_to_2aa();         Write_a0_to_555();         Fwrite(dest,src1);         /* Wait for write to complete or timeout. */         while(1) {             if (Is_Equal(dest,src1)) {                 if (Is_Equal(dest,src1))                     break;             }             /* Check D5 for timeout... */             if (D5_Timeout(dest)) {                 if (Is_Not_Equal(dest,src1)) {                     ret = -1;                     goto done;                 }                 break;             }         }         dest += 2;         src++;         bytecnt--;     } 
image from book
 

The front end (see Listing 13.18) checks for misalignment. If the write starts on an odd address, then the code builds and writes a fake two-byte source buffer (with one byte taken from the real source and the other byte taken from the already-written flash location). It then adjusts the beginning address of the source buffer so that the middle block always receives a block that starts on an aligned boundary. Later the back end uses the same strategy to deal with misalignments at the end of the block.

Listings 13.19: Middle Block of Flashwrite16() Function.
image from book
 /* Each pass through this loop writes 'fdev->width' bytes...      */     for (i=0;i<cnt;i+=fdev->width) {         /* Flash write command */         Write_aa_to_555();         Write_55_to_2aa();         Write_a0_to_555();                  /* Just in case src is not aligned... */         src1[0] = src[0];         src1[1] = src[1];         /* Write the value */         Fwrite(dest,src1);         /* Wait for write to complete or timeout. */         while(1) {             if (Is_Equal(dest,src1)) {                 if (Is_Equal(dest,src1))                     break;             }             /* Check D5 for timeout... */             if (D5_Timeout(dest)) {                 if (Is_Not_Equal(dest,src1)) {                     ret = -1;                     goto done;                 }                 break;             }         }         dest += fdev->width;          src += fdev->width;     } 
image from book
 

The middle block of code (see Listing 13.19) does the majority of the work associated with the flash write (depending on the size of the block being written).

Listings 13.20: Back End of Flashwrite16() Function.
image from book
 /* Similar to the front end of this function, if the byte count is not      * even, then we have one byte left to write, so we need to write a       * 16-bit value by writing the last byte, plus whatever is already in      * the next flash location.      */     if (cnt != bytecnt) {         src1[0] = *src;         src1[1] = dest[1];         /* Flash write command */         Write_aa_to_555();         Write_55_to_2aa();         Write_a0_to_555();         Fwrite(dest,src1);         /* Wait for write to complete or timeout. */         while(1) {             if (Is_Equal(dest,src1)) {                 if (Is_Equal(dest,src1))                     break;             }             /* Check D5 for timeout... */             if (D5_Timeout(dest)) {                 if (Is_Not_Equal(dest,src1)) {                     ret = -1;                     goto done;                 }                 break;             }         }     } done:     /* Read/reset command: */     Write_f0_to_555();     return(ret); } 
image from book
 

The back end of the function (Listing 13.19) deals with the possibility that there might be only one byte left at the end of the loop (using the same fake buffer technique as the front end).

I can test the flash write with the command

 flash write 0xfff00000 0x80000 16 

This command tells MicroMonitor to copy 16 bytes from location 0x80000 and write them to flash location 0xfff00000 . If you are actually following this process with a real evaluation board, then it is possible that 0xfff00000 has data in it, so issue the command flash erase 7 to erase that sector. When doing your own port, you should devise separate tests to verify that the front and back ends of the write function work properly (using an odd destination address with an even byte count).

Tracing through the erase and erase-and-write code is a similar exercise, so refer to the CD for complete details.

Enabling TFS

Now that Ive walked through some of the flash driver steps, I can turn on the flash file system. Assuming Ive written the Flashwrite16() and Flasherase16() functions correctly, TFS, once configured, just works when it starts.

To enable TFS, I enable the INCLUDE_TFSXXX macros in the config.h file by setting those macros to 1 . I also need to configure TFS for the target environment (more macros in config.h ). The flash device spans 0xffe00000 through 0xffffffff (2MB). The installed monitor resides at 0xffe00000 and does not use the upper half of the flash memory. I allocate sectors 8 and 9 ( 0xfff40000 through 0xfffbffff ), giving MicroMonitor .5MB for TFS file storage. The final sector (10) is used for TFS SPARE , and sector 7 ( 0xfff00000-0xfff3ffff ) is reserved for installing a ROM-version of the MicroMonitor binary. The TFS configuration entries in config.h (Listing 13.11) are adjusted to reflect these parameters.

Note 

Keep in mind now that I am launching MicroMonitor through the monitor that comes with the evaluation board. This process is a bit unusual, but, for the sake of this discussion, it is convenient . This arrangement allows us to test our code without blowing away the boot sector that has the installed boot monitor. In a final system, this dual-monitor environment would be converted to a MicroMonitor-only environment.

Before building a new image, also turn on INCLUDE_EDIT in config.h , so that there is an easy way to create a simple text file. (The INCLUDE_EDIT parameter enables a simple but useful ASCII file editor in the monitor.) Now build, download, and start up the new MicroMonitor, which includes TFS and the file editor.

As before, first check the commands that are included as a result of TFS being included (see Listing 13.21). Notice that not only are the tfs and edit commands available, but also several commands related to scripts in TFS are now included.

Listing 13.21: MicroMonitor Command Set with TFS Included.
image from book
 uMON>help argv        call        cm          dm          echo        edit exit        flash       fm          gosub       goto        heap help        ?           if          item        mstat       mt pm          read        reg         reset       return      set sleep       sm          ulvl        tfs         xmodem      version uMON> 
image from book
 

Depending on the state of the flash memory assigned to TFS, at this reset MicroMonitor might report that TFS detected corrupt file space. This result is likely because the flash space allocated to TFS wasnt cleared. You can clear the flash space in one of two ways. Use flash erase 810 or tfs init to erase the sectors (810) used by TFS.

After TFS space is cleaned up, files can be added. Now would be a good time to try out tfs add and edit to create files. Then delete some files. Then try to clean up with tfs clean . If these experiments work without errors, you can be fairly certain that TFS is installed and working properly. The output of tfs stat is helpful for debugging a misconfigured TFS, if there are problems.

Enabling Ethernet

Now that all of the basic stuff is in place, its time to work on the Ethernet driver. Aside from the initial boot, this step is the trickiest in building a new port. The Ethernet device is a bit more complicated than a serial port. Plus, if something goes wrong, its hard to know what without a good Ethernet protocol analyzer (or sniffer). Because MicroMonitor doesnt need any interrupts, the driver is about as simple as an Ethernet driver can be.

To add Ethernet support, I modify the INCLUDE_ETHERNET definition in config.h . This change enables all of the basic code for ARP, ICMP Echo ( ping ), and for a simple CLI server running on UDP port 777. The immediate goal is to get the evaluation board to respond to a ping (ICMP echo). If ping works, I know that the Ethernet transmit and receive paths are functioning, so all of the other stuff should fall into place.

Note 

You can connect the target to the host PC directly or through a hub. However you wire it up, do what you can to confirm your cabling works. For example, ping some other device using the same connection mechanism you plan to use during this port. One really nice thing about connecting to the target via a hub (assuming you dont have a protocol analyzer hooked up) is that usually the hub gives you some visual feedback to let you know that traffic is on the connection. In every hub Ive seen, there are a few LEDs that let the user know (at a very high level) if something is happening on the connection.

I also need to assign a MAC and IP address to the target. If you are working peer-to-peer or on an isolated hub, you can just make up a MAC address for testing; just make sure that when you go live you have an officially assigned one. For this example, the ColdFire board comes configured with a MAC address, so I use that address. I can use the DBUG command show to get the address. In the listings here, I use the value 00:60:1d:02:0b:08 .

Similarly, I must set up an IP address. The same rules for creating an address apply to both MAC and IP addresses. I again assume an isolated network, but I must make sure that the target IP address is on the same subnet as the host. I have my PC configured with IP address 135.3.94.39 . My PCs subnet mask is 255.255.255.0 , so I establish my targets IP address as 135.3.94.40 , which puts both devices on the same subnet. To get MicroMonitor to configure itself using these values, I create a monrc file with the following content

 set IPADD 135.3.94.40 set ETHERADD 00:60:1d:02:0b:08 set NETMASK 255.255.255.0 

Remember that the monrc file must be created executable, so the e flag must be set at time of creation.

Now I have a monitor binary with INCLUDE_ETHERNET enabled and a monrc file that has IP and MAC address information established. I have a PC connected to the target either through a hub or direct connect. The ping command can be executed, and, if everything is hooked up properly, the target responds and the ping succeeds.

[1] If you compare the target-specific code used for MicroMonitor in this port to the code used to ini tialize the shipped DBUG monitor, you will see that I shamelessly reused as much of the Motorola code as possible.

[2] This process demonstrates the versatility of TFS in on-board flash memory. In this case, it fits inside an environment using only three sectors of flash space.



Embedded Systems Firmware Demystified
Embedded Systems Firmware Demystified (With CD-ROM)
ISBN: 1578200997
EAN: 2147483647
Year: 2002
Pages: 118
Authors: Ed Sutter

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net