Adding Memory-mapped Devices
The rest of this chapter is devoted to adding memory-mapped devices to your TINI for user interaction. We will discuss adding other devices such as serial ports, I2C devices and other things in later parts of this book. We will be adding:
• Liquid crystal display
• 4-digit, 7-segment LED display
• Buttons for command input
• Keypad for text/numeric input
When we implement all of these devices, we will use a common address decoder and data bus buffer. The buttons and keypad also share some common interrupt logic as well. A simple block diagram of what we are adding is shown in Figure 8-7 to help give the big picture on how these components connect. We will start with the data bus buffer and the address decoder first, since the four input or display components use these. All of these components can be successfully implemented on solderless breadboards, soldered protoboards or any of the prototype systems for TINI that have been previously mentioned (such as the TINI protoModule or the TINI Nexus, both from Vinculum).
Figure 8-7: A block diagram of memory-mapped devices
Adding data bus buffer
As mentioned in the TINI datasheet9, “The address bus, data bus and strobe lines are subject to strict loading limitations. Exceeding these limits can cause erratic system operation with on-board as well as off-board resources. Be sure to buffer any signals that will be heavily loaded off-board.” So, to avoid adding excessive capacitive loading on the data bus, we add a simple 74ACT245, octal bi- directional transceiver. By connecting the /RD line from TINI to the 245’s T/R, TINI will control the direction of the transceiver appropriately. The schematic in Figure 8-8 shows how this is connected to TINI.
The address decoder
Since we are adding several devices to TINI, we need to assign them each a place in the TINI address space. The TINI socketboard does not come with a general-purpose address decoder. Shown here (Figure 8-9) is a simple address decoder for a liquid crystal display.
This is essentially the logical AND of /CE3, A19 and /WR; the LCD enable (E) is high when Chip Enable 3 (CE3) is low, when the write (/WR) line is low and when address line A19 is high. This scheme for address decoding works fine for the LCD on the TINI socket board but has several drawbacks: it does not allow for any flexibility (it’s wired for A19 and /CE3), it does not allow for additional peripherals to be added without additional address decoding and, worse, it takes up a large block of address space since it only decodes on address A19 (valid address to talk with the LCD will range from 0×00380000 to 0×003FFFFF).
We will be implementing a more traditional address decoding scheme for our peripherals using a 74ALS138, 1-of-8 decoder/ demultiplexer. We will show how to modify the address decoder we use to be compatible with the TINI LCD class as well as how to configure the TINI class to be compatible with this address decoder in the section on the LCD display. The schematic in Figure 8-10 shows the address decoder we will be using that allows us to control eight peripherals (the blocks labeled “Buttons,” “LCD,” “LED” and “Keypad” will be discussed in detail shortly).
Figure 8-10: Memory-mapped address decoder schematic
With this address decoder we use Peripheral Chip Enable 0 (/PCE0) and address lines A2, A3, and A4. We will also be using address lines A1 and A2 to either address specific portions of the device, as is the case in the LED display, or to enable certain modes of the device, as is the case of the LCD display. You can very easily use a different Peripheral Chip Enable line or different address lines to put these devices anywhere else in the TINI
memory space that you desire. In Table 8-3 we list how the address decoder maps these devices into TINI address space. Remember from the TINI memory map (in Chapter 6, Table 6-3) that PCE0 selects addresses in the range 0×0800000-0×08FFFFF. We are not decoding on address lines A5-A19 so if we needed to add more address decoding we would need to build a larger address decoder, as shown in Figure 8-11 (in the table, x means this address line is not decoded, so the level of this address line is irrelevant in the decoding scheme).
We will gain software access to these devices through the
com.dalsemi.system.dataport class. This class allows byte-wide reads and writes
to memory-mapped I/O devices. Here is a quick summary of what is needed:
We need to import the proper class:
then create a new DataPort for the particular address:
DataPort myDevice = new DataPort(0×0080000C);
We then configure the DataPort for the proper access. TINI provides a method for user applications to set the number of machine cycles needed in order to execute a bus read or write. This allows TINI access to both fast and slow peripherals without additional logic. Often memory-mapped peripherals have slow access times, so it may not be possible to access external devices at full speed. This timing is controlled by the selection of stretch cycles. A stretch of 0 will result in two machine cycles for a data bus read or write. A stretch of 7 will result in twelve machine cycles for a data bus read or write. Your software can dynamically change the stretch value depending on the particular memory or peripheral being accessed.
We can read from or write to the device as needed:
myDevice.write( 0×00 );
int i = myDevice.read();
Refer to Chapter 6 for more details on the TINI memory map with respect to CE and PCE.