CMP EMBEDDED.COM

Login | Register     Welcome Guest  
HOME DESIGN PRODUCTS COLUMNS E-LEARNING CONFERENCES CODE FORUMS/BLOGS NEWSLETTERS CONTACT FEATURES RSS RSS



Internet Appliance Design


From PROM to Flash

Steve Sumner

D esigning an embedded system containing flash program memory isn't always as straightforward as it seems. A robust flash-based system needs to deal with such things as in-circuit reprogramming and code execution from RAM-somewhat esoteric topics not associated with PROM. Although several past articles have touted flash memory and its various advantages, many have lacked the details necessary for an engineer to fully understand how to implement flash as a better alternative to PROM. I endeavor to change that by presenting an example from my own experience converting a PROM-based embedded system to flash. I will emphasize software design, as therein lies most of the difficulty.

Although I'll discuss an approach specific to the example system I'll present, the techniques should be applicable to most any embedded product being designed with flash program memory. The scheme I developed is but one possible solution to the flash reprogramming problem. I don't claim that it is the best or the only solution, just that I felt that it was a workable approach when considering the specific constraints of the product I was working on. As the saying goes, your mileage may vary.

It's not my intent to tell you how to write the code to program bytes or erase sectors in a certain vendor's flash chip-that's easy once you have the chip's data sheet. After I present an overview of the characteristics of flash and the design goals for my specific project, I'm going to discuss the tough stuff-mainly an algorithmic approach, but also some tips for working with flash that may not be entirely obvious.

Flash overview
Does anyone doubt the superiority of flash over PROM anymore for program memory storage? Flash offers all of the capabilities of PROM and adds some of its own, all at a reasonable price. The most notable advantage of flash program memory is its reprogrammability, specifically its in-circuit reprogrammability.

Everyone benefits with a system that is in-circuit reprogrammable. The end user of a flash-based product can obtain feature updates or bug fixes and easily apply them to his device, using nothing more than a standard PC, a serial cable, and a user-friendly interface. The engineer can (perhaps?) rest a little easier, knowing that if a bug survives through the testing process, it's not terribly burdensome to fix in the field. And the bean counters may benefit too, because in some instances the use of flash may even speed time to market-once the hardware and a certain core set of software features are complete, the product can be shipped and additional software features added in the future as time permits.

The downside of flash is that to achieve in-circuit reprogrammability, the software design effort is usually fairly complicated. Most types of flash have the requirement that during programming or erasing, no other accesses are allowed. If, for instance, an instruction fetch is attempted from flash during this time, the chip simply fails to respond. The implication here is that code execution needs to take place from some other memory device during reprogramming of the flash. The resource normally tapped for this task is RAM.

The majority of flash chips available to the embedded system designer today are byte- or word-writable, sector- or chip-erasable devices. This means that although code can be written to program individual bytes or words, when data is to be erased it must be done on whole sectors or even the entire chip at once. A sector is a fraction of the total chip density, for example, a 512K flash chip might have eight uniform 64K sectors.

A robust embedded system with flash program memory as part of its design needs to be protected from corruption that could render the device unbootable, and therefore unusable. Such a situation might arise if a power loss occurs right after the reprogramming software, executing from RAM, has just erased the entire flash chip in preparation of writing new program data.

Some flash chips contain "boot block" sectors that are typically a normal sector chopped up into smaller-sized pieces and placed at one end of the flash chip's memory space. The advantage of this configuration is that a small bit of code can be placed in the boot block that will never be erased. The idea here is that this code will contain routines for erasing and reprogramming the remainder of the flash chip. Because some or all of the boot sectors are never erased, the embedded device is protected from power-fail corruption during programming-a program is always present to boot the system and reinitiate the reprogramming process.

Figure 1: Flash sector architecture

The smaller size of the boot block sectors allows the engineer to tailor the size of the boot code and eliminate wasted space. For example, a flash chip architected with 64K sectors might have a boot block consisting of one 16K sector, two 8K sectors, and one 32K sector at one end of its address space. This allows the creation of a 16K, 24K, or 32K boot program, without reserving an entire 64K sector for the boot code if not needed. Vendors produce different flash chips with the smaller boot block sectors at either end of the flash to meet the needs of different processors that have their reset vectors at either high or low memory addresses. See part A of Figure 1 for an example of a flash chip's architecture.

Easier flash reprogramming variations
Although the PROM-to-flash conversion example that I will discuss later is one of the more difficult flash variations due to system and cost constraints, some easier alternatives are available. A type of flash called "simultaneous read/write" flash can be used in low-voltage (typically 3.3V and lower) designs. This type of flash allows erasing or programming of a sector during execution from a different sector, and thus is well suited to boot block code designs. On the subject of different voltage levels, some older flash required an external high programming voltage, typically 12V, to be applied to the chips during erasing or programming. More modern flash eliminates this requirement.

Another easier design variation is to have a small boot PROM or a small second flash in addition to the main flash chip that will be reprogrammed. This allows execution from the smaller device while the larger flash is being erased or programmed, although the added cost and logistical complexity of the two-device alternative may be prohibitive to a design.

A non-cost-sensitive, time-critical system that is designed to run from high-speed RAM also simplifies the flash reprogramming chore. In this case, the flash is only used as non-volatile program storage when the product is turned off. During the boot process, the code is copied to RAM and normal execution continues from there. Since the flash is then inactive with regard to code execution, erasing and reprogramming it is simplified.

A compiler and linker that support relocatable code can aid the flash programming effort, as the same code can execute either from the flash or from RAM once code is copied there from the flash. Although it can be tricky to use emulators with program counter relative code, the technique is often used to accomplish flash reprogramming.

Example conversion
Recently I was given the task of converting a PROM-based embedded product to flash program memory. Before beginning work, I summarized the goals of the redesign based on the constraints I had to work within. I needed to replace the product's PROM chip with flash, and allow for user-friendly in-circuit reprogramming via an RS-232 serial port connection to a standard PC. The product should be protected from corruption in the event of a power failure during programming, and it shouldn't create any undue difficulties during debugging. Also, it needed to be self-contained, that is, the code to conduct the reprogramming needed to be embedded in the device as shipped from the factory. Most of all I wanted an understandable design, and to me that meant that it shouldn't be overly complex, and should be written in C with as little assembly language as possible.

The system I was converting was a Motorola 68332-based design in a moderately cost-sensitive product. Details of the system relevant to the flash effort included 64KB of RAM, one RS-232 port, 99% C code, 5V logic levels, a reset vector in low memory, and a movable interrupt vector table. The compiler/linker I was using would not produce relocatable code. A background debug mode (BDM) emulator was available for debugging.

The flash selected was an AMD Am29F800BB, a 5V, 512K x 16 or 1M x 8 device, which would be used in 16-bit mode. This flash is a boot sector device that has 19 sectors making up its 1MB address space. The second "B" in the chip name indicates that its boot sectors are at the "bottom" of the address space. The memory map for this chip is depicted in part A of Figure 1. The physical boot sectors (sector numbers 0 through 3) are sized so that the boot code can be 16KB, 24KB, or 32KB. If not used as part of a "logical" boot block, any remaining "physical" boot block sectors can be used as normal sectors.

Algorithm design
By far the hardest part of implementing in-circuit reprogrammable flash program memory is deciding upon a software approach to the problem. I thought about this for quite a while and managed to stumble up some blind alleys before arriving at a feasible strategy.

I knew that to be able to reprogram the flash I would have to have the code conducting the programming execute from the RAM of the embedded product. But where would that code come from? And how would I get it into RAM and start it executing? Running from RAM is not normally done in embedded systems, and consequently the tools that an engineer utilizes (compilers, linkers, and emulators) are not usually cooperative when asked to do this. Ideally, the tools want to work with one large block of code destined for one program memory device.

I also knew that to protect the product from corruption in the event of a power failure during reprogramming, I would need to reserve some sectors in the flash for permanent code that could boot and restart the programming if it was somehow interrupted. This would have to be the first few sectors in the flash as 68332 designs require the reset vector to be at byte location 0x000004.

The strategy that I settled on placed three independent programs in the memory space of the flash chip. Each of these programs would have a different memory map for code and data storage.

Figure 2: Example system memory maps

A "boot loader" would run on power-up and initialize the system in a rudimentary way-just enough so that RAM and certain I/O are available. It decides which of the other two programs to transfer control to, based upon input from the user, and starts the selected program running. The memory map of the system when the boot loader is running can be found in part A of Figure 2.

The "application" is the program that runs to perform the function that the embedded system was designed to do. In the PROM version of the product, the application was the only program present. The memory map for the running application is shown in part B of Figure 2.

For lack of a better way of referring to it, I decided to call the program that runs from RAM the "RAM executive." The RAM executive conducts the reprogramming of flash based on data packets received on the embedded device's serial port from the PC-based reprogramming utility. The RAM executive is placed in the logical boot block of the flash along with the boot loader to protect it from accidental loss. For the memory map of the system when the RAM executive has control, see part C of Figure 2.

Details
Looking at the physical boot sector architecture of the flash chip in Part A of Figure 1, I decided to make my logical boot block 24KB, as shown in Part B. I tried to err on the pessimistic side, figuring that I could always pull back to 16KB if the combined size of the boot loader and the RAM executive ended up less than that. In actuality, I ended up staying with 24KB, as the boot loader and RAM executive together weighed in at roughly 20KB. As part A of Figure 2 shows, the boot loader was assigned 2KB and the RAM executive 22KB of the boot block's code space.

With respect to actual coding, I decided to start where the embedded system starts when it powers up-the boot loader. The boot loader does very little. First, it configures and enables the RAM chip select, initializes its own zero and non-zero RAM variables, and sets up a small stack. Then it determines what to do next: either run the application program or the RAM executive. It does this by enabling the I/O ports to read the product's keypad. If the 1, 4, and 7 keys are held down simultaneously when the device powers up, the boot loader copies the RAM executive code data from its known location in flash to RAM the boot loader itself is not using. It then jumps via the reset vector to the RAM copy of the RAM executive:

if (scan_keypad() ==
SCAN_CODE_FOR_1_4_7_COMBINED)
{
char * pRamExecSrc =
(char *)0x000800;
char * pRamExecDest =
(char *)0x100000;
/* copy the RAM executive
embedded in the flash boot
block to RAM not being used
by the boot loader: */
while (pRamExecSrc 
<
=
(char *)0x005FFF)
{
*pRamExecDest++ =
*pRamExecSrc++;
}
/* make the jump to the RAM
copy of the RAM executive
via its reset vector: */
asm("move.l
(0x100004),%a0");
asm("jmp (%a0)"); /* RAM exec */
}

Since the boot loader uses RAM at address 0x105800-0x10FFFF for its own use, that leaves RAM at 0x100000-0x1057FF unused to serve as the receptacle for the RAM executive code. And since the highest code address for the boot loader is 0x0007FF, the flash-based copy of the RAM executive code resides at 0x000800-0x005FFF. Again refer to part A of Figure 2.

If the special 1-4-7 key combination is not held down on power-up, the normal application code is run:

else
{
/* make the jump to the
application via its
reset vector: */

asm("move.l (0x006004),%a0"); asm("jmp (%a0)"); /* app */ }

Because the RAM executive and the application are independently debuggable, each has a vector table at its code starting address. For the former, this address is 0x100000; for the latter, 0x006000. The reset vector is the four bytes at byte offset 4 in the vector table. This explains the use of 0x100004 and 0x006004 in the code example above. That's really all there is to the boot loader. The application program, aside from originating at an address that is non-zero, is exactly as it was before when the product was PROM-based. The application code makes no assumptions about what the boot loader might have initialized, and simply executes as if it were the only program in the device.

When the RAM executive starts running, it also makes no assumptions about what the boot loader has done previously and executes its own startup code. The RAM executive initializes the device's serial port, and waits for the PC-based reprogramming software to communicate with it. The idea here is that the PC program will instruct the RAM executive to erase the non-boot block sectors of the flash containing the old application program, then send the address and data information to allow the RAM executive to program the flash with a new application. Since no program is executing from the flash, the RAM executive is free to treat it as a normal memory device, with no access restrictions other than those imposed by the chip maker. Once the programming of the new application code is complete, the RAM executive forces a hard reset of the system, causing the boot loader to again gain control and start the new application program running. At this point, reprogramming has been accomplished. Any further detailed discussion of the RAM executive or the PC-based reprogramming software is beyond the scope of this article.

Debugging the three programs
Since all three programs-the boot loader, RAM executive, and application-are each self-contained, the act of debugging them is simplified. The emulator cooperates reasonably, as it's not asked to do anything it's not accustomed to doing, such as running relocatable code.

Loading the boot loader code into the target system's emulation RAM and running it without a well-placed breakpoint would not be smart, however, because it will try to jump to a region of emulation memory that contains random data. When using the emulator to test the boot loader, the RAM executive and the application do not exist. To make sure the boot loader is doing its job, I load its code and place a breakpoint on the following line discussed before:

if
(scan_keypad() ==
SCAN_CODE_FOR_1_4_7_COMBINED)

Running at full speed to this breakpoint, I can then step-over (not step-into) the calling of the scan_keypad function. If I do this while holding down the appropriate keys on the keypad, I can test the boot loader's ability to load and run the RAM executive. Although the while loop will copy garbage data to the RAM executive's destination in RAM, setting another breakpoint on the line


asm("jmp (%a0)"); /* RAM exec */

allows me the chance to load the code and symbol file for the RAM executive, being careful to not reset the CPU. From there, a single step takes execution to the first instruction in the newly-loaded RAM executive, with full C source-level debugging capacity. The boot loader's execution path to the application program is tested in a similar manner. This time the special key combination is not held down, and a single breakpoint is needed on the line


asm("jmp (%a0)"); /* app */

When the emulator breaks on this instruction, the application program debug file can be loaded, and then run at full speed. Once I determined that the boot loader was sending execution where it needed to go, that is, either to the start of code through the RAM executive's reset vector or the application's reset vector, I forgot about the boot loader until time for final integration and test.

The RAM executive and the application program are also debugged independently of each other and the boot loader. The emulator software is used to prepare the appropriate chip select registers to allow the loading of these programs. For instance, since the RAM executive needs to run from a RAM chip that is disabled upon reset, that chip select has to be manually enabled to allow loading of the code. Also, the program counter at reset needs to be overridden in each case, otherwise the reset vector present in the flash chip will be used.

Code sharing among the three programs
I'm the kind of engineer that dislikes duplication of code. Whenever I find myself writing the same code in two different places, I seek a way to combine the sections if it's reasonable to do so.

Realizing that the three programs making up my flash scheme would have similar if not identical code in certain areas, I decided to have them utilize some of the same source files. This way, the boot loader and the application could share the same keypad reading routine, the RAM executive and the application programs could share very similar serial port handling code, all three programs could share similar startup code, and so on.

The vehicle by which this sharing is made possible is C's preprocessing directives. By creating the tags BUILD_BOOT_LOADER, BUILD_RAM_EXECUTIVE, and BUILD_APPLICATION, I was able to achieve my code-sharing goal.

For example, most of the serial port interrupt service routine is common to both the application and the RAM executive. The application code needs to understand how to process received data when the product is configured to be in Modbus (an industrial networking protocol) mode, but the RAM executive has no such need. To allow for this, I did the following in the source code file serial.c:

INTERRUPT sci_handler(void)
{
if ((RIE == ENABLED) &&
(RDRF == RECEIVE_FULL))
{
/* receiver interrupt */
/* get received data: */
short RxData = RDR;
#if BUILD_APPLICATION
if (ModbusEnabled)
{
/* process RxData as part
of a Modbus packet... */
}
else
#endif
{
/* process RxData as a
standalone character... */
}
}
/* ... */
}

Then, to compile the file for the application program, I used a command-line similar to this:


cc serial.c \
-DBUILD_APPLICATION=1 \
-DBUILD_RAM_EXECUTIVE=0

When compiling the RAM executive, the complimentary command-line looks like this:

cc serial.c \
-DBUILD_APPLICATION=0 \
-DBUILD_RAM_EXECUTIVE=1

This way, the application and RAM executive get slightly different serial routines compiled and linked in. The boot loader has no need to handle serial interrupts-in fact the boot loader doesn't even use interrupts-so serial.c is omitted from the file list in the boot loader's portion of the make file, and the BUILD_BOOT_LOADER tag is not used in serial.c.

Code sharing has the advantage that any change affecting more than one of the three programs only needs to be done one time and in one place. The downside is that a change affecting all three programs triples the testing effort to validate the changed section.

Getting the three programs into flash
Having three separate programs instead of one makes it more of a task to get the programs into the flash chip. With PROM, typically one large program is burned into the device, beginning at the lowest address in the chip and extending upward as far as needed to accommodate the current size of the program.

With flash the situation is not so simple, as there are three separate S-record files that make up the flash chip's address space. The application program is like the PROM's single program, except that its starting address is no longer the lowest address of the chip-the boot loader program receives that honor.

When the RAM executive's program code is in place in RAM, its starting address is 0x100000, so the linker outputs an S-record file with this address as a starting point. But there is a problem with using this S-record file as the linker creates it-it can't be burned into flash because the address range of its records (0x100000-0x1057FF) doesn't coincide with the memory range of the flash (0x000000-0x0FFFFF). From the memory map (see part A of Figure 2) it's clear that when embedded in the flash, the RAM executive must reside at 0x000800-0x005FFF. To achieve this, an S-record relocation program is used to change the addresses of the data bytes in the file without impacting the data bytes themselves. An example of such a relocation utility is P&E Microcomputer Systems' MOVE_S19.EXE (www.pemicro.com/support_center/
downloads/utilities/move_s19_downloads.exe
).

Once the RAM executive has been relocated, it and the boot loader are combined into one S-record file-no problem results since their address ranges do not overlap. The new S-record file represents the boot block code and can be delivered to the flash vendor or distributor for burning into blank flash chips. Those chips, once soldered to the printed-circuit board of the embedded product, will then be ready to serially receive the data from the application program's S-record output via the PC connection.

For application code that is fairly mature and stable, the three S-record files can be combined into one and provided to the flash vendor, thus avoiding the time-consuming process of serially-uploading the application program on the product production line. An alternative to this is to solder on blank flash chips and program all three programs at once on the production line using the BDM port of the CPU and either a custom-written or a commercial flash-programming PC software package.

To allow end users to update their devices with new application code, the S-record for the current application code can be placed on the company Web site or e-mailed to customers who have requested bug fixes or have paid for feature updates.

It goes without saying (but I'll say it anyway) that the boot loader and the RAM executive need to be fully tested before being released to the flash vendor or the production line. Bugs in these programs can prevent field reprogramming of the embedded product, the whole point of this exercise. If this makes you squeamish, it is possible to design the system so that the RAM executive can be uploaded to RAM via the serial link, before the application data is sent. The boot loader still needs to be bug-free, however.

Emulator issues with flash
The product upon which I developed my flash programming scheme had a connector to allow for RAM expansion. Extra RAM was used either by the customer for data storage (it was battery-backed), or in-house for emulation RAM during code development using a BDM emulator.

When the embedded product was PROM-based, the boot chip select was connected to both the PROM and the emulation RAM. Since both devices cannot share a single chip select, this meant that when emulating, the socketed PROM had to be removed and a special jumper had to be soldered into a RAM board to be dedicated from that point on as an emulation RAM board. This had the advantage that if I had working code running with the emulator, that code was guaranteed to run when I burned a PROM, since the PROM and emulation systems were identical, except for the physical program storage devices.

Emulating on the flash version of the product was a different story, however. In that case the flash could not be taken out of circuit because it was a surface mount component permanently soldered to the PC board, so any emulation RAM could not share the flash's chip select. The problem could have been solved using moveable jumpers, but a better and less error-prone solution was to use the power of the emulator to configure chip select registers upon receiving a reset signal. Normally, when a reset signal is received, all chip selects except the boot chip select are disabled. If I used the emulator to write into the registers to disable the boot chip select and enable the emulation RAM's chip select upon reset, I could trick the system into allowing me to load code into the emulation RAM and run it as if it were located in the boot device (the flash).

A potential disadvantage to this approach is that the emulation is no longer pure, that is, code developed on the emulator may not run the same way when moved to flash. This occurs because of the artificial situation created with the emulator by mucking with the chip select registers. Fortunately, most problems that result from this are easily found and corrected, usually right after the flash is programmed from working emulator code and the system fails to power up correctly.

Writing to flash from application code
The application program in the product I was converting to flash required that a few words of calibration data be stored in non-volatile memory. This data was specific to the printed circuit board, so each product sold contained slightly different calibration information. Once calibrated during final checkout of the product, this data never changed. In the days of PROM, the calibration data was stored in a serial EEPROM. With the advent of flash, however, it was decided that this data, along with a product serial number, should be stored in fixed, unused locations high in the boot loader's area of the flash boot block. The data would be programmed into flash from the product's setup mode.

In this situation, the application program is running from the flash when the designated locations need to be programmed. Again, executing the instructions to program the flash from RAM is the only way, but this time execution has to come back to flash and resume where it left off. My solution to this problem consisted of several steps.

First, I created a C function called ProgramFlashWordFromApp. This function manipulates only data passed to it as arguments (no global variables) and calls no other functions. The importance of this will become clear later. Writing the function was straightforward, as was debugging it to make sure it programmed some test locations in the flash correctly. A much-simplified version (just to illustrate the concept) of the ProgramFlash-WordFromApp function is:

#define FLASH \
((volatile short *)0x000000)
void ProgramFlashWordFromApp(
long WordOffset,
short WordData)
{
FLASH[WordOffset] = WordData;
/* code to unlock the flash,
wait until the location has
been programmed, do error
checking, return success or
failure, etc. omitted here
to keep the machine code
example small */
}

After debugging but while still running the emulator, I examined my C function in the disassembly window:

ProgramFlashWordFromApp:
4E560000 LINK.W A6,#0x0
202E0008 MOVE.L (0x8,A6),D0
222E000C MOVE.L (0xC,A6),D1
D080 ADD.L D0,D0
2040 MOVEA.L D0,A0
3081 MOVE.W D1,(A0)
4E5E UNLK A6
4E75 RTS

Next I copied the machine code text for the function from the disassembly window into my favorite source code editor. After a little text manipulation, I had a group of hex words that I could comma-delimit, put curly braces around, and name as a C array called ProgramFlashWordFromAppViaRam :

/* NOT const ! */ short
ProgramFlashWordFromAppViaRam[] =
{
0x4E56, 0x0000, 0x202E, 0x0008,
0x222E, 0x000C, 0xD080, 0x2040,
0x3081, 0x4E5E, 0x4E75
};

I placed this new C array in the flash source code file. I now had a RAM-based C array containing a machine language subroutine to program a word into the flash. I had to resist the urge to put a "const" qualifier on this array of constants-doing so would have resulted in the array being placed in flash. That would have been very undesirable; it needed to be in RAM so that it could execute from there.

A side note to the purists: I could have written the subroutine in assembly language, but I didn't for a few reasons. First, the actual function is considerably longer that the one I show here, and I'm lazy. Second, the C compiler can do a better job at writing the assembly than I can unless I really try, and I didn't want to go to the trouble. Third, did I mention that I'm lazy?

Next I analyzed the assembly code of the function to determine how it accessed the arguments that were pushed onto the stack before the call. At the point in the application code where I needed to write data into flash, I pushed my address and data arguments onto the stack manually using some inline assembly, and coerced the compiler into calling the first location in my RAM-based array as if it was a normal function:

asm("move.w %0,-(%%sp)" ::
"m"(Data));
asm("clr.w -(%sp)");
asm("move.l %0,-(%%sp)" ::
"m"(Offset));
asm("jsr "
"ProgramFlashWordFromAppViaRam");

Mission accomplished-the flash could now be written to from the application code.

I commented out the original C function, but I did not delete it, as it was the only copy of the source code for the machine code array. Also, whenever I use a technique such as this (which isn't often!), I try to comment it well. I've been on the maintenance end of things too often to not do this.

Had I used any global variables in my original C function, this approach would not have been practical. The linker takes the liberty of moving the addresses of global RAM variables around in memory as code is under development. By using only stack-based variables in my function, the linker can move globals around all it wants and my machine language subroutine remains valid. With simple code that uses only stack-based data and makes no function calls, even a C compiler that cannot produce a completely relocatable program often produces locally relocatable code. The fact that the machine code generated from my C function used only relative branching was key in making this technique viable.

One of the caveats to using this method is that interrupts must be disabled during the ProgramFlashWord-FromAppViaRam "function" call. Since all of the interrupt service routines reside in the flash, they are unavailable during this method of flash programming. This was not a problem in the product I was working on since the data bytes that are written in this manner are programmed while the product is in "setup" rather than "run" mode, when the system is performing no time-critical tasks. A related caveat is that this method should probably not be used to write a lot of data into flash, since running with interrupts disabled for an extended period of time will adversely effect a real-time system.

An emulation issue to be aware of when using this technique is that the flash chip select cannot be disabled and its address range overlaid with emulation RAM. To be able to read or write data, the flash chip must be present in the memory map during emulation. An easy way to accomplish this is to locate the emulation version of the program at a normally unused memory range and reenable the flash chip select at its normal address.

Let there be light
Moving a system from PROM to flash program memory is a worthwhile effort but not one to be undertaken lightly. Significant development time and planning need to be dedicated to such a change. Deciding on an algorithmic approach that works and is easily debugged can be challenging. It's my hope that this article's example and ideas on how to make the conversion have made the task seem less daunting, and have shed some light on the more arcane aspects of in-circuit flash reprogramming.

Scott Sumner is currently a senior project engineer working on automotive test systems at the Detroit Engineering Center in Rochester Hills, MI. He has been involved with designing embedded and PC-based systems since graduating from Lawrence Technological University with a BSCS in 1988 and a BSEE in 1991. He welcomes contact and can be reached via e-mail at sasumner@bigfoot.com.
Embedded.com Career Center
Looking for a new job?
SEARCH JOBS

Browse all jobs

SPONSOR
RECENT JOB POSTINGS





 :