Issue
147 October 2002
12,
16, 18 Hike!
Dashing
for Flash
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).
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.