OFF-CHIP CODE MEMORY
Context
● You are developing an embedded application using one or more members of the 8051 family of microcontrollers.
● You are designing an appropriate hardware foundation for your application.
Problem
How do you add up to 64 kbytes of external code memory (usually ROM) to your 8051 microcontroller?
Background
See OFF – CHIP DA T A MEMOR Y [page 94] for background information.
Solution
If you have decided that you need to use external code memory doing so is straight- forward. Figure 6.6 illustrates the basic circuit.
The recommended latch and (ROM) memory combinations for a wide range of clock speeds are given in Table 6.3. These are taken from Dallas Application Note 89. As we noted in OFF – CHIP DA T A MEMOR Y [page 94], latch and memory combinations which will operate with these Dallas devices will also work with most other (generally slower) 8051 devices.
[Note that, if the microcontroller is not a CMOS device and the memory devices are CMOS devices, you will require pull-up resistors (not shown) on Port 0. This is most easily achieved using a DIL (or similar) 10K resistor pack. Note also the control of the EA pin, to force the microcontroller to retrieve instructions from external memory.]
Hardware resource implications
As discussed in OFF – CHIP DA T A MEMOR Y [page 94], use of external memory has major resource implications: it requires the use of two ports (P0 and P2), plus two pins (P3.6, P3.7) on Port 3. This reduces the number of available port pins from 32 to 14. See the following for additional comments on this.
Reliability and safety implications
As discussed in ON – CHIP MEMOR Y [page 82], the addition of external memory can reduce the reliability of your application: use an on-chip solution where possible.
In many cases, adding external ROM can be avoided if you use an appropriate 8051-device with on-chip ROM: see ‘Related patterns and alternative solutions’ for further details.
Portability
Hardware designs for external memory are generally portable. However, if you upgrade from a ‘slow’ to a ‘fast’ processor (or simply increase the crystal frequency) you need to make sure that the external latch and memory components are suffi- ciently fast: refer to Table 6.3 for suggestions.
The only way to make your external access design as portable as possible is always to use the fastest external components available. This approach has cost implications, but, if you are able to produce 100,000 copies of one, generic (fast) board rather than smaller numbers of ‘slow’, ‘medium’ and ‘fast’ versions, you may find the ‘one size fits all’ solution to be both a reliable and cost-effective solution.
Overall strengths and weaknesses
If at all possible, use of internal code memory is a better option!
Related patterns and alternative solutions
Before you add ROM to your 8051-based system, think carefully. There are many 8051 devices with large amounts of on-chip code memory available. As an example, Table
6.4 shows a selection of recent Philips 8051 devices.
As is clear from the table, 8051 devices are now available with large amounts of on-chip ROM (and good performance levels). Of course, similar devices are available from other manufacturers.
There are, perhaps, three main reasons for adding external code memory:
● You need particular on-chip hardware components (e.g. CAN bus, ADC, hardware maths) and cannot find an 8051 device that has both sufficient ROM and the required peripheral(s).
● You require external RAM. Having therefore already created much of the required external memory interface, you have decided that it makes good economic sense to add external ROM too, rather than using a device with on-chip ROM.
● You need to be able to update the code that your system will execute. For example, if your system is running on a comparatively expensive (Extended) 8051 device, you may decide that it will be more cost effective to replace a small ROM chip when code updates are required, rather than to replace the microcontroller itself.
Example: Adding ROM and RAM memory
Figure 6.7 illustrates how you can add both code and data memory to your system.
Example: Reducing the component count
If space is very tight and / or you are seeking to improve the reliability of your 8051- based system by keeping the number of connections to a minimum, you have two basic choices:
● Use a microcontroller with on-chip code memory.
● Use a memory (ROM) chip that does not require a latch.
Option 1 is not always available. For example, the powerful C509 microcontroller is very fast and has several useful features (including a hardware maths unit compati- ble with that in the 80C517). It does not, however, have on-chip ROM of any kind.
To add external memory without requiring the use of a latch, consider using an Atmel AT27C520 (64 kbyte) EPROM. It has an internal latch, so no additional compo- nents are required.
Example: Adding more than 64 kbytes of code memory
With some recent exceptions (see Table 6.1), the various members of the 8051 family only directly support a maximum of 64 kbytes of external code memory. This may not be sufficient for larger programs or where large amounts of read-only variables need to be used. ‘Bank switching’ is one option.
The idea of a bank-switched memory arrangement is, superficially, very straight- forward. In a simplified arrangement, we may have (for example) eight 64-kbyte banks of memory in the system. Access to memory locations within each block is controlled by the usual (16) address lines. To select between these eight memory blocks, we can use eight additional output pins on the microcontroller to select an appropriate memory bank, as required.
In practice, things become slightly more complicated.
First, consider interrupts. When an interrupt occurs, the microcontroller will jump to a particular address in the current bank. One way of ensuring that this address contains the relevant instructions is to duplicate your interrupt functions in all the banks (note that your compiler can usually do this automatically, as we will see later).
Similarly, library functions also need to be universally accessible and, therefore, (usually) in a common area.
The need for duplication can also arise with read-only variables stored in the code area. Unless you can ensure that these constants will only be called in a particular bank, they need to be placed in a common area.
Finally, the bank-switching code itself must be in a common area.
Having addressed these problems, you need to consider what happens when the chip is reset. At this time, all port outputs are set to 0xFFFF. If a port is being used for bank switching, the port outputs will control which bank of code your program begins to execute first. You need to ensure, mainly through the bank-switching hard- ware, that your program begins by executing code in the correct bank.
Health warning!
As these comments should begin to make clear, bank switching is complicated and prone to error. Even if you know what you are doing, people who subsequently have to maintain the system you create may not fully understand the consequences of any changes they make to the code.
If possible, avoid bank switching. If your application requires more than 64 kbytes of code memory, a much better solution is to use a Dallas 80C390, Analog Devices ADµC812 or Philips 8051MX, all of which support more than 64 kbytes of code memory. Alternatively, consider one of the two ‘upgrade’ paths from the 8051 (viz, the 80251, the 8051XA) discussed in Chapter 3.
If you are determined to implement bank switching, you need, first, an appropriate address decoding scheme and, second, a means of implementing a common code area.
There are two basic ways of tackling the ‘common area’ problem. The simplest approach is simply to duplicate all the common code in every code bank. For exam- ple, Figure 6.8 shows the use of four 64-kbyte ROM chips, with a common area (around 32 kbyte) duplicated in each.
Alternatively, we can achieve a similar result by using five 32-kbyte memory devices, arranged with one common area and four upper code banks (Figure 6.9).
While superficially more efficient, the lower cost of large memory chips means that a solution based on one memory chip is most likely to prove cost effective. In addi- tion, because most of the code examples presented in this book make comparatively little use of interrupts, or of library functions, the common area required is often small in size (typically a few kbytes) and the ‘duplicated common area’ solution is therefore less inefficient than it might initially appear.
For example, consider that we wish to add a 512-kbyte ROM and 64-kbyte RAM to a C509 microcontroller. Much of the required hardware is familiar: we have an exter- nal ROM device and an external RAM device, connected to the microcontroller through an 74HC573 latch. This is exactly the same arrangement seen previously in Figure 6.7.
Where the hardware differs is first, of course, in the size of the code memory area and, second, the presence of the 74HC257. The 74HC257 is a (quad) 2-line to 1-line data multiplexer: it provides the necessary ‘glue logic’, to interface the port pins (lower nybble of Port 3 in this example: any available port may be used).
Details of the 74HC257 connection are given in Figures 6.10 and 6.11.
Note that the Keil compiler provides support for bank switching and will support the memory arrangement shown here: see the Banker / Linker manual for details.