circuitcellar.com
Magazine Support   Digital Library   Products & Services   Suppliers Directory 
 
 





 

Issue 147 October 2002
12, 16, 18 Hike!
Dashing for Flash


by Jeff Bachiochi

Start PIC18F252 Instruction Set Reset Serial Port In-Circuit Sources & PDF

PIC18F252

The PIC18F252 is one of the newest members of Microchip’s PIC18Fxxx family of micros. Let’s get more familiar with the processor before you dash off to start your contest entry (see Photo 1).

(Click here to enlarge)

Photo 1—Look inside before taking your first step in the dash for flash cash.

If you take a look at Figure 1, you’ll see some of the important features associated with the program memory organization. The ’F252 has 32 KB of code flash memory, 1536 bytes of data RAM, and 256 bytes of data EEPROM. There are also 31 levels of hardware stack space available in the micro. And, because the stack pointer is read/write, you can set up a software stack in RAM if you need more space. Speaking of RAM, banks of RAM are much easier to use with the PIC18F252.

Figure 2 shows six 256-byte banks of RAM. Note that one bank of RAM is identified by a bank select register (BSR). Alternately, there’s an access register bank that always contains the first 128 bytes of RAM (from bank 0) plus the last 128 bytes from bank 15 (i.e., the special function registers, or SFRs). The SFRs are RAM used by the CPU for core functions; peripheral modules use SFRs for control functions.

The data EEPROM is a single bank of 256 bytes. This might be used as configuration data for a sensor that’s incorporated in your application. The configuration data might need to be changed; however, it must be nonvolatile in nature.

The PIC chips incorporate a few safety techniques to assure this memory isn’t changed arbitrarily by errant code. First, the EEPROM data area is not mapped into the data (register) space. To read from the EEPROM block, you must place the address of interest into the EEADR register in the FSR bank. Note that the EEPGD bit must be cleared to point to the EEPROM area, and the RD bit must be set to enable a read. Both bits are found in the EECON1 register located in the FSR bank. The data stored in the EEPROM at address EEADR is available in the EEDATA register in the FSR bank.

Writing an address in the data EEPROM involves a similar process. Place the address of the write into the EEADR register. Then, insert the data to be written into the EEDATA register. The EEPGD bit must be cleared to point to the EEPROM area, and the WREN bit must be set to enable a write. Next, disable the global interrupt to prevent interference by any other peripheral. The following sequence must be executed exactly: Write 0x55 to the EECON2 register; write 0xAA to the EECON2 register; set the WR bit in the EECON1 register to begin the actual write; and then execute an NOP instruction. The global interrupt can be enabled once again. It’s a good practice to clear the WREN bit when finished writing data to the EEPROM data area.

ADDRESSING

If you’ve had the privilege to program 12- or 16-series PICs, you’re probably familiar with the page-switching requirement that’s the result of the limited width of the address field in single-word GOTO and CALL instructions. A larger 21-bit program counter provides a linear reach of 2 MB. And the paging ugliness has been done away with, thanks to multi-word GOTO and CALL instructions.

Program memory is handled in byte increments instead of the previous word-sized (12, 14, or 16 bits) increments. Although this means the PC is now incremented by two for each instruction or four for each two-word instruction, the instruction flow (i.e., the use of pipelining) still exists. This allows each instruction to be executed in a single execution cycle (after an initial fetch) except for any instruction that changes the PC (i.e., a branch instruction), which requires a new fetch to fill the pipe again.

Direct addressing is used for most data moves—get this here, put that there. The moves are based on a fixed location. Indirect addressing is handy when you need to move dynamically, based on a register’s value as opposed to the register itself. Although the original PICs had a single indirect register, the 18-series has three sets of indirect registers. Each set contains a register pair, FSRxH and FSRxL (x = 0–2), where the registers hold a 12-bit address covering the total RAM space.

In addition to this pointer pair, five other registers are used to access the data being pointed to, and they potentially affect the pointer pair (see Table 1). The indirect registers work the same way when retrieving data from them (i.e., the location pointed to by the FSRxH/L pair). Notice any similarity to C operators here?

Even though the FSRxH and FSRxL cover the data area, another useful set of registers cover the code area. This is useful for retrieving table information stored in code space. It works a bit differently from the indirect addressing registers. Because the code area is much larger than the RAM area, three address registers are needed TABPTRU/H/L. A single register TABLAT is used to hold the table read’s data. Instead of using registers to read the table data, there are four TABRD instructions you can use. Each instruction will affect the TABPTRU/H/L register differently (see Table 2).

Remember that these instructions are performing access to the code area. Normally, with non-flash memory parts, the data in the code area is read-only. Flash memory parts open Pandora’s box because the code area can be reprogrammed using the TABWR instructions similar to the TABRD instructions. If you recall from last month how a byte of a sector of a SmartMedia block is changed, then you can already guess how reprogramming a byte in code space must be handled.

A byte of code area (flash memory) that’s not erased cannot be written on a byte or word basis; it requires an erasure of a 64-byte block (e.g., TBLPTRU/H/L uses only bits 6 to 21, bits 0 to 5 are ignored). This means that if data in the other 63 bytes is important, you must have a 64-byte RAM buffer set aside to read the 64-byte block into before erasing it or the data stored there is lost.

To erase a 64-byte block of the code area, place the address of the block into the TBLPTRU/H/L registers. The EEPGD, WREN, and FREE bits must be set to point to the flash memory area to enable a write and an erase. All bits are found in the EECON1 register located in the FSR bank.

Next, disable the global interrupt to prevent interference by any other peripheral. Then, execute the following sequence to begin the internal erasure process: Write 0x55 to the EECON2 register; write 0xAA to the EECON2 register; set the WR bit in the EECON1 register to begin the actual erase; and then execute an NOP instruction.

Further instructions will be halted until the internal process is complete. The global interrupt can be enabled at that time. After the data is in RAM, bytes can be changed and the block written back into the code space. But wait, writing to the code area writes 8 bytes (i.e., a partial block) at a time, so the write process must be done eight times to completely write the 64-byte block back into the code area.

To write to the flash memory, the TBLPTRU/H/L registers are set to the beginning address of one of the partial blocks (the LSb would be xxxxx000). Eight writes to the TABLAT (using *TABWR+, post-increment) actually write to eight holding registers. These registers will be used by the hardware when the programming takes place. To initiate the write to flash memory, the EEPGD, WREN, and FREE bits must be set to point to the flash memory area to enable a write and an erase.

Next, disable the global interrupt to prevent interference by any other peripheral. Now, the following sequence is executed to begin the internal programming process: Write 0x55 to the EECON2 register; write 0xAA to the EECON2 register; set the WR bit in the EECON1 register to begin the actual write; and then execute an NOP instruction.

Further instructions will be halted until the internal process is complete. The global interrupt can be enabled once again. This entire process is repeated eight times for the remaining data bytes in the block. Note that it requires about 18 ms to update the whole block.