Introduction to the PIC18F microcontrollers

Introduction

This article is an introduction to Microchip's new PIC18F series of high-end microcontrollers, with special reference to the PIC18FXX2 family.  At present this comprises the four devices summarised in Figure 1 (copy the table on page 1 of 39564b).

The PIC18F4X2 devices have 40-pin DIP packages, and are pin compatible with the PIC16F877.  The PIC18F2X2s have 28 pins, and are pin compatible with the PIC16F876.

In many ways these 18F devices are similar to, and backwards compatible with, their 16F counterparts.  They have been enhanced in quite a number of ways which we'll look at, but the good news is that, for readers familiar with the 16F series, there isn't a steep learning curve before you can start using them.  Programs written for a 16F can usually be ported to run on a similar 18F with only a modest amount of work - it's not a rewrite job, although there are a few nasty pitfalls to avoid that we'll note later.  You can learn about a number of the new features gradually, and only when you need them.

The article which follows is not an in-depth tutorial on this new PIC family.  The intention is rather to give an overview of the available features, concentrating on those areas where the 18Fs differ most from the 16Fs.  It no doubt also has a programming bias reflecting the author's background as a software engineer.  Readers may refer to the documentation described next for more details.  General familiarity with the PIC16F microprocessor family is assumed.

Most development tool references are to Microchip's assembler MPASM, because TK3 support for 18F was still in development when this article was written.  MPASM is  part of the MPLAB IDE, free from www.microchip.com (see Pic n' Mix Aug 2004), but the assembler can be run stand-alone by double-clicking on the file mpasmwin.exe in the MPLAB directory.

Documentation

The two main Microchip documents that describe the PIC18FXX2 family are the data sheet (ref 1) and the programming specification (ref 2).  These documents both cover all four devices.  The data sheet (ref 1) is referred to as "the spec" from now on.

The spec is a 330-odd page epic.  Datasheets for 16F devices like the 16F84 and 16F877 are light reading by comparison, and in the author's experience they are good quality documents containing few errors.  It would be nice to report that the spec is of similar high quality, but sadly this does not seem to be so.  The author is aware of many errors, obscurities, omissions and contradictions.  Some of these will be mentioned in what follows, but there are others which are not.  The reader is advised to approach the spec and related documentation with due care; it cannot be said always to be the reliable guide that we may have come to expect.

Peripherals

The peripherals of the 18FXX2 family are very similar to those of the 16F877.  Readers familiar with this latter device will find few surprises.  There are (depending on the device):

 - 3 or 5 I/O ports, PORTA to PORTE
 - 4 timers (Timer0 to Timer3)
 - 2 CCP modules
 - MSSP
 - USART
 - 5 or 8 10-bit A/D channels
 - PSP (40-pin devices only)
 - watchdog timer
 - power on reset and brown out detection
 - 17 or 18 interrupt sources

Timer0 can be used in either 8-bit (as on 16Fs), or 16-bit mode.  For Timer0 in 16-bit mode and Timer1 (which is always a 16-bit counter), when the low byte of the counter is read, the high byte is automatically latched by the hardware so that subsequently reading it is guaranteed to give a consistent result.  Similarly, writes to the counter high byte are latched and only take effect when the low byte is written.  The messy code needed on 16Fs to allow for the possibility of a counter/timer wrap between reads or writes of the low and high bytes of the counter is unnecessary.

In PORTA to PORTE the output latch register (present but invisible in 16F devices) is visible as an SFR.  Port outputs can be driven either by writing directly to PORTx, or to LATx (x = A to E).  The difference is that reads of LATx return the last values written by software, whereas reads of PORTx return the actual state of the device pins.

Brown out detection has four configurable threshold voltages.

The recently announced PIC18F2455/2550/4455/4550 family includes a USB 2.0 peripheral.  Beyond the scope of this article, these devices are nevertheless the main reason why the author is interested in the 18F family!  It is hoped that USB interfacing projects using some of these devices may feature in EPE before too long.

Clocking

The 18F family can be clocked at up to 40 MHz (10 Mips).  The usual range of LP, XT, HS, RC and external clock options is available.  In RC mode, CLKOUT can be disabled, which saves power and releases the pin to become another I/O pin (RA6).  In HS mode, an internal PLL can be used to quadruple the external clock speed (primarily intended for use where high external clock speeds might cause excessive EMI interference).

Memory organisation

It's in memory organisation and the more under-the-bonnet stuff like the instruction set where the real changes are.  Let's look at program memory first.

The big difference here is that program memory has grown from being 14 bits wide to 16 bits wide.  With a few exceptions discussed later, 18F instructions occupy 16 bits.  However program memory on 18F is 8-bit byte addressed.  So the PC increments by 2 for each instruction.

All instructions must start on an even program memory address.  Be warned: MPASM will let you ORG to an odd address (a perfectly legitimate thing to do on the word addressed 16Fs) and start assembling code from this address.  But such a program will not execute correctly.

Program memory on 16Fs is quoted in bytes.  So 18Fs may appear to have twice the program memory of their 16F counterparts, but only because the units have changed.  The 8K (word) 16F877 and the 16K (byte) 18F442 both have the capacity for 8192 instructions.

Program memory is readable and writeable at run time (not just at programming time).  More on this in the Tables section later.

Data memory

Data memory is banked, as it is on 16Fs, but banks are 256 bytes long rather than 128 bytes.  To allow for the possibility of up to 16 banks, there are 4 bank select bits and they have moved out of the STATUS register into their own Bank Select Register (BSR).  The data memory bank accessed is dependent on the BSR; no surprises there.

However, there's a new Access Mode.  The (up to 128) SFRs (which are mapped into Bank 15) and the first 128 of the GPRs in Bank 0 are mapped into a virtual Access Bank which is permanently visible, whatever BSR is set to.  Access Bank is selected by means of a new 'a' bit present in all instructions using file memory.  If a=0 the Access Bank is selected and this overrides the BSR setting.  a=1 means use BSR.

To accommodate this new 'a' bit, file register manipulating instructions have grown a new argument.  So, for example, the 16F 'addwf f,d' becomes 'addwf f,d,a' in 18F assembler (the notation being used is the same as in section 20 of the spec).

'a' is an optional argument.  For some instructions (eg addwf, bsf etc) the spec does not say whether a=0 or a=1 is the default.  For most instructions (eg andwf, bcf etc) it states that a=1 is the default.  Despite this, the author has found that in both MPASM versions 3.20 and 3.80 (at the time of writing the current version), the default is always a=0 (Access mode).

Access mode is nonetheless a very useful innovation.  All the SFRs are permanently visible in Access mode, removing the need to fiddle with the bank select bits to get at some of the more obscure ones, which is always a pain in 16F programming.  128 GPRs are also permanently visible, independent of BSR, for working set variables etc.  So if BSR is initialised to (say) Bank 1 then a total of 384 bytes of general purpose data memory (sufficient for most programs?) is visible without ever needing to change BSR at all.

Data EEPROM memory

EEPROM memory is accessed in almost exactly the same way as on 16Fs.

There is a very confusing discussion in the spec (section 6.8) which appears to be trying to say that data EEPROM needs refreshing at intervals if it is not rewritten.  This text is followed by a Note which appears to state the exact opposite.  The author would be interested to hear from any reader who can explain what section 6.8 is really trying to say!

Addressing

The program counter (PC) is 21 bits wide - sufficient to address h'1FFFFF' (2,097,152 decimal) program memory bytes - scope for a certain amount of future expansion!  18F CALL, GOTO and RETURN instructions can address the whole of this range (how they do it in 16 bits we'll see in the instruction set section later).  So program memory is "flat", not paged, the LCALL and LGOTO pseudo instructions are unnecessary, and there's generally no need to do messy manipulation of PCLATH bits in order to jump across 2K boundaries.  This is all much nicer than on 16Fs.

Just for the record we'll note that the 21-bit PC is physically implemented in three 8-bit SFRs:  PCL (bits 0 - 7), PCLATH (bits 8 - 15), and PCLATU (for upper) (bits 16 - 20). 

Indirect addressing

Indirect addressing is similar in principle to 16Fs, but has undergone a welcome tidy up and enhancement.  When an INDF register is used, the location pointed to by the corresponding FSR is accessed.  The FSR registers are 12 bits wide, which is sufficient to address the whole of the maximum of 16 banks of 256 bytes each.  So the dreadful IRP bit has gone, and the author is sure nobody will mourn its passing.

There are three separate INDF and three corresponding FSR registers, so it is possible to have indirect pointers set up to three separate areas of data memory at the same time.  It is much easier to move or copy areas of data memory around than on 16Fs.  Handling buffers of data is almost easy!

To store the 12 bits of the indirect address, two 8-bit registers are physically required:  FSRnL and FSRnH (n = 0 to 2).  A new instruction, LFSR, facilitates loading both parts of any FSRn at once.

Another enhancement is in the provision of modes which allow the indirect address pointer to be incremented or decremented automatically.  The author finds the assembler syntax to do this a little odd: for example to add one to the address in FSRn and then clear the addressed location, the following is written:

	clrf	PREINCn

To clear the location and then decrement the pointer, one would write:

	clrf	POSTDECn

and so on.  (PREINCn, POSTDECn etc are mapped into SFR space, but are not physically implemented registers.)  It's possible to post-decrement, post-increment, and pre-increment, but not pre-decrement.  There's also a mode in which W is used as an offset to FSRn.  For further details, readers are referred to the spec section 4.12.

Tables

A significant innovation is the provision of a proper method to create and access data tables in program memory.  This is implemented by new table read and table write instructions.

Associated with these instructions is the table pointer register.  This is 22 bits wide, so is physically 3 registers (low, high and upper as with the PC described above).  The lower 21 bits are used to address program memory.  The 22nd bit provides access to the device id and configuration bits, which are mapped to the top of program memory space.  Yes, it's possible (but probably not advisable!) to change configuration settings by software.

Reading program memory is easy.  The required address is loaded into the upper, high, and lower parts of the table pointer, and a table read instruction is executed.  The data byte is loaded into the table latch register and is available at the next instruction cycle.  As with indirect addressing, pre- and post-increment, and post-decrement of the table pointer are possible.  The assembler syntax is cryptic and different from that for indirect addressing, eg:

	tblrd*+  	; increment after read
	tblrd*-	; decrement after read
	tblrd+*	; increment before read

Writing program memory is rather more complicated.  The sequence is similar to writing data EEPROM, except that the address is held in the table pointer not in EEADR, and some control bits in the EECON1 register have to be set differently.  Data have to be written 8 bytes at a time, aligned on an 8-byte boundary in memory.

Additionally, program memory has to be erased before it can be written.  The erase sequence is again similar to writing data EEPROM.  Program memory is erased in blocks of 64 bytes, which must be 64-byte aligned.  It goes without saying that the memory being erased should not be in use to store current program instructions, especially those for the erase sequence itself, otherwise unpredictable effects may occur...

It's not possible for the PIC to be writing program memory and reading instructions from it at the same time, so the processor halts completely for about 2ms for each erase and write operation, according to the spec.  (The author has done some tests with a 18F442, and found that this quoted time is a bit pessimistic, but even so erasing then writing 64 bytes of program memory in 8 writes of 8 bytes each is going to take of the order of 10 - 18 ms.)  It isn't possible to get an interrupt on completion of the write, as with writing data EEPROM, to allow the processor to do other things.  This is a substantial holdup, which would probably not be tolerable in real time applications.

However for accessing static data tables, the table read mechanism is a vast improvement on the hated "computed goto" sometimes inevitable on the 16F series.  Readers familiar with the author's previous rant on this subject ("PIC macros and computed GOTOs", EPE Jan 2003) will know his views.  Table read, as well as being much simpler, safer and easier to use, is more efficient, allowing data bytes to be held straightforwardly and contiguously in memory, rather than encoded one byte per 16-bit word in 'RETLW' instructions.  Properly implemented, table read can be used to access a table located anywhere in memory, from anywhere in memory, without any PCLATH complications.

The MPASM 'db' and 'data' statements can be used to set up arrays of data bytes in program memory.  A MPASM "feature" (not mentioned in the spec) is that each 'db' statement starts a new word in the .hex file, any unspecified bytes being zero padded.  So if you want data bytes packed two to a 16-bit word, as usually you will, it's necessary to define data in multiples of two bytes for each db statement, eg:

	db '0', '1'		; defines ascii 0 and 1 in two contiguous bytes, but..
	db '0'		; generates two bytes containing 0x30 and 0x00	

The computed goto construct is still possible on 18Fs, but any programmer who uses it still has to grapple with the all complexities of PCLATH and additionally PCLATU - the only place in 18F programming where this would now appear to be necessary.  Recidivists who persist with the computed goto on 18Fs have only themselves to blame, and can expect no help from the present author.

Interrupts

Another useful addition to the 18F architecture is the provision of automatic context saving by hardware on interrupt.  When an interrupt is taken, the STATUS, BSR and W registers are always saved in a non-accessible memory area.   On exit from an ISR, it is possible optionally to specify that the automatically saved context is reloaded by the hardware from its save area.  For most programs this is the only context information that needs preserving, and so it eliminates the chore of saving and restoring context in software in the ISR, and can usefully speed up interrupt response times.

By default interrupts look just as they do on the 16F series, where all interrupt sources vector through one address and are handled by the same ISR.  However the 18F architecture also supports a high and low priority interrupt scheme with two vector locations and potentially two ISRs.  Apart from the Timer0, which for some reason must always be a high priority interrupt, all other interrupt sources are software programmable to be high or low priority.  This is done by means of a third array of bits for each interrupt.  As well as the interrupt flag bit and interrupt enable bit, there is an interrupt priority bit.

Enabling of the high and low priority interrupt system is under software control at run time.  High and low priority interrupts can be separately enabled and disabled as a group.

High priority interrupts preempt low priority ISR processing.  This means that low priority ISRs cannot safely use the hardware's context saving mechanism described above, since the save area can be overwritten by a high priority interrupt.  Low priority ISRs must do context saving and restoring by software as on 16Fs.  It also means that high and low priority ISRs must not access the same locations, or else the low priority ISR must disable high priority interrupts before doing so (which probably rather defeats the point of high priority interrupts).

In some of its example code for writing program and data memory, the spec (section 5) shows only high priority interrupts being disabled around the special write unlock sequences.  The author is sure that this is an error, and that if priority interrupts are in use then both priority levels must be disabled.  In any event this is the safer option.

The author has played with priority interrupts, and finds them great fun.  However he admits that they are likely to be of very little application to the majority of EPE projects, and so has reluctantly resisted the temptation to discuss them further here.  Readers requiring more information on interrupts generally may refer to his previous articles ("Programming PIC Interrupts", EPE Mar/Apr 2002).

Stack

The return address stack is 31 entries deep, and allows any combination of calls and interrupts to occur.  It stores the full 21-bit return address value.

The stack is visible, unlike the 16F stack.  There is a stack pointer which is readable and writeable.  There are PUSH and POP instructions, but somewhat curiously PUSH takes no arguments; only the PC can be written to the stack with PUSH.  Likewise POP does not return the top of stack value; it effectively discards it by decrementing the stack pointer.  The top of the stack location is visible, and can be accessed and changed via the TOSU, TOSH, and TOSL registers.

Stack underflow and overflow cause status bits to be set.  A configuration bit can be set to cause a device reset if underflow or overflow occurs.

Most of these features are probably intended for real time operating system designers, and the author doesn't think that any of them is of much use to the average programmer.  They could even be quite harmful.  Messing about with the stack pointer and the return address stack are both excellent methods to make a program go wrong in spectacular and very hard to debug ways.  The clunky nature of the PUSH and POP instructions, and the odd width (21 bits) of the stack make it unsuitable for passing procedure operands in the style of a high level language compiler.

Well designed programs should not be in any danger of blowing a 31-deep stack, and only well designed programs are likely to include reset code to detect and recover properly from a stack overflow or underflow.  If reset is disabled in the configuration, only an extremely paranoid programmer is going to bother to poll the status bits to check for possible stack errors.  In most cases it's unlikely that, if a stack error has occurred, the program will still be functioning well enough to detect it anyway.

Configuration

There are 11 bytes holding various device configuration bits, and two holding device id information, which are generally unremarkable.  Quite a  number of these bits are to do with memory protection; it is possible selectively to prevent read and/or write access to 4K blocks of program memory from other 4K blocks.  This would allow the implementation of a rudimentary protected mode operating system with fixed 4K partitions.  There is also a boot block comprising the first 512 bytes of memory, which can be separately protected, and which is intended to hold the bootstrap code for a downloaded application.

The configuration memory can be read and written by software using the table mechanism; writing incurs the same 2ms processor halt overhead as writing program memory.  It can be written a byte at a time.  The spec doesn't say explicitly anywhere, but from experiment it seems to be unnecessary to erase configuration memory before writing it.

Programming

Programming 18F devices will not be covered here, as it's something that few readers will want or need to do for themselves.  It is just noted that while the same programming hardware as for 16Fs can be used, the software procedures and algorithms are completely different (they are in fact based on the table read and write operations covered earlier.)  Both low and high voltage programming modes are supported.

Instruction set

There are 76 instructions on the 18F processor, compared with 35 on the 16F series.  It can hardly be described as a RISC any more!  With 3 exceptions, noted below, all the 16F instructions are present on the 18F.  We've met some of the new instructions along the way.  This section is not going to attempt to describe all of the remaining ones, but just give a flavour of what's new.

Most instructions are 16 bits or 2 bytes long.  However a few are double length, or 4 bytes long.  These include the CALL and GOTO instructions, which is how these instructions manage to encode the full 21 bits of program memory address.

The second word of double length instructions always starts with binary '1111', which is interpreted by the processor as a NOP instruction.  So these instructions can be safely used with skip instructions, for example:

		btfsc	STATUS,Z,A		; skip if Z is clear
		goto	ZEROSET
		...

ZEROSET:
		...

If Z is clear, the skip will actually occur into the second half of the GOTO instruction. This will execute as a NOP, and then go on to execute the next "proper" instruction.  Thus the program will function as intended.

In addition there is a set of branch instructions.  Branches are addressed relative to the current instruction, and are single length, so their range is limited.  With the conditional branches it is possible to branch backwards 128 bytes or forwards 126 bytes from the current instruction; the unconditional branch (bra) can go backwards 1024 bytes or forwards 1022 bytes.  So if ZEROSET were within range in the example above, it could have been written:

		btfsc	STATUS,Z,A
		bra	ZEROSET		; unconditional branch 
		...

which would generate less code.  But even better, since there are conditional branch instructions to test all the STATUS bits directly, we could simply have written:
		
		bz	ZEROSET		; branch if Z is set

In passing it is noted that there are two new flags, N and OV, in the STATUS register, which may be helpful in twos complement arithmetic operations.  N (negative) is set by some instructions when the most significant bit of a result is '1', and OV (overflow) is set when it changes.

Hardware multiply is supported by two instructions MULWF and MULLW, which execute in a single instruction cycle.  These instructions take two 8-bit operands and generate a 16-bit result.  There are code examples in the spec showing how to construct 16-bit signed and unsigned multiply routines using them.

There is a MOVFF instruction to copy a file memory location directly to another without having to go through W.

Three 16F instructions have disappeared.  CLRW is unnecessary because W is an addressable SFR on the 18F series (mnemonic WREG), so it is possible to write the equivalent 'clrf WREG,A' instead.

RLF and RRF have been replaced by RLCF and RRCF respectively.  The latter are almost semantically identical to RLF and RRF on a 16F, but they have the additional effect of setting Z. 18Fs also support RLNCF and RRNCF which are rotates that do not go through carry.  The DECF and INCF instructions have also changed compared with their 16F equivalents in that they additionally set C and DC on the 18F.  It's not clear why Microchip have been inconsistent and changed the RLF and RRF mnemonics but not INCF and DECF.

These differences can be critical when porting 16F code to 18F.  For example, Peter Hemsley's High Speed Binary to Decimal routine (EPE Sep 2004) does not work when reassembled and run on an 18F, because its logic relies on C being preserved across DECF instructions.  The spec is most unhelpful: it does state that Z, C and DC (also N and OV) are "affected" by DECF and INCF, but gives no further information of exactly how, when and in what circumstances any of these flags is changed.  It is not obvious to the author how a DECF instruction should affect C and DC (if at all).

These changes in the way flags are affected are perhaps the least satisfactory aspect of Microchip's enhancements.  They offer little of any practical use to the programmer, and for the most part will only cause problems.  The bottom line is that special attention may need to be given when porting 16F code using RLF, RCF, INCF or DECF instructions, to make sure that the program logic does not require the preservation of Z, C or DC.

MPASM in 18F mode does not support some of the shortcut pseudo-instructions like SKPC.  Presumably the reasoning is that the conditional branch instructions provide a better alternative.  While this is true for new code, the control flow is not the same, and when porting code from 16F it would have been useful to have retained these mnemonics for backwards compatibility.  However, they are easy enough to replace automatically with their longhand equivalents using macros.
  
And finally the author would be interested if any reader could devise a mnemonic that will help him remember the differences between the SUBFWB, SUBWFB, and SUBWF instructions!

Development tools

In compensation for their poor documentation, it would have been nice to conclude that Microchip's MPASM/MPLAB development tools, when applied to 18F program development, were of high quality.  But sadly again, that's not possible either.  Consider the following (the notation being used is the same as in section 20 of the spec).

MPASM has built-in to it F and W (also f and w) as mnemonics for the 'd' argument.  It doesn't need any equates or include files for (eg) addwf FRED,W or addwf FRED,F statements to assemble correctly. Even if F and W are redefined, eg:

W  equ      1
..
   addwf	FRED,W

the "correct" code (result in W in this case) is still assembled.

TK3, on the other hand, requires equates to be defined for F and W.  If they are defined wrongly, the wrong assembly results will be obtained.

But inconsistently, MPASM does NOT have equates for 'a' argument mnemonics built-in.  If 'addwf FRED,F,A' is assembled for an 18F without any include files, an error is obtained.  The 18fxxx.inc files include the definitions 'A equ 0' and 'BANKED equ 1'.  So using the appropriate one of these include files one can indeed write 'addwf FRED,F,A', and it will assemble correctly.

[As a short digression, the author prefers to write 'addwf FRED,F,B' instead of 'addwf FRED,F,BANKED', and so proposes a convention: that for 18F code in EPE the symbol B is reserved for this use, and is always equated to 1.  It is suggested that this is not done by modifying the 18fxxx.inc files, which should be the unmodified Microchip versions, but as a separate statement that all our .asm files contain.]

For 16F assembly, if 'addwf FRED' is assembled then MPASM assembles its default 'addwf FRED,F', and generates a warning message.  TK3 requires explicit specification of F or W, and generates an error.  The author thinks either behaviour is acceptable.

But for 18F assembly with MPASM this warning message has disappeared.  'addwf FRED' just assembles as 'addwf FRED,F,A' using the defaults for 'd' and 'a' with NO warning message given.  The author finds this very disappointing, as leaving off the 'd' argument is a slip he makes regularly, and he has come to rely on the warning message to find occurrences for him.

Of course, more errors are possible with three arguments when defaults are permitted.  In spite of F and W being built-in, MPASM can't seem to tell which argument has been omitted (probably because the symbols have all been pre-processed and reduced to 0s and 1s by the time it checks).  In MPASM, 'addwf FRED,A' assembles as 'addwf  FRED,W,A', which is possibly what was intended, but 'addwf FRED,BANKED' assembles as 'addwf FRED,F,A', which is almost certainly not what was meant.  (In these examples, A and BANKED are being taken as the 'd' argument, and the 'a' argument defaults.)  In neither case is any warning message given.

In 18F assembly code, instructions can take anything from 0 to 3 arguments, and the number is mostly different from their 16F equivalents.  When converting from 16F to 18F, or perhaps when working concurrently on 16F and 18F projects, it is all too easy to make mistakes.

The author is so concerned at the possible coding errors that can go undetected by MPASM in this way that he has written a pre-processor (called prempasm) which supplies the missing checks.  Prempasm will highlight any lines where potentially the wrong number of arguments has been specified, and so where a possibly inappropriate default might be supplied by the assembler.  The idea is to run .asm files through prempasm periodically, and check out any warning messages that are generated.  In some cases these won't actually be errors - the defaults supplied may be correct.  When this has been done, MPASM can be launched directly from prempasm to do the assembly proper.

Prempasm

Fig 2 shows a screenshot of prempasm.  The first time the program is run, it will ask you to specify the path to your mpasmwin.exe.  You can refuse, but it will keep nagging you each time you run it until you do, and the "Launch MPASM" button will be greyed out and inoperative.  After this, select file/open, and browse to a .asm file.  When you click the "Open" button, the preprocessor runs straight away on the selected file.  This file is remembered next time you run the program, so thereafter you can simply click the "Go" button to repeat a scan of the same .asm file.  Scan results are displayed in the text window, and also written to a file with the same path and name as the .asm file but with the extension '.err'.

Prempasm does not perform all the other checks that MPASM does, so no warnings from prempasm does not necessarily mean that your file will assemble without errors!  It only has a simple parser, so there may occasionally be false warnings if it misunderstands something - for example it assumes that all labels start in column 1, anything that does not being treated as an instruction mnemonic, and it won't understand any macros you define.

Prempasm is available from the EPE website...  
 
It is suggested that as good coding practice, all instruction arguments are always specified in the source, even when the correct defaults would apply.

TK3 support for 18F

TK3 now supports 18FXX2s!  You can assemble code for them, program them and even simulate them using version 3.00 or later.  The TK3 assembler is actually better at error checking than MPASM.  If you omit the 'd' argument where it is needed, TK3 will generate an error.  If you omit the 'a' argument, TK3 assumes a=0 by default, but generates a warning message that it has done it.  If you assemble 'addwf  FRED,BANKED' with TK3, the beta version at the time of writing will actually assemble 'addwf FRED,F,A' as MPASM does, but you will at least get the (slightly misleading!) warning message that you have omitted the access bit.

Demo program

A demo program test18f.asm containing examples of how to use some of the new instructions and features of the 18F series is available from the EPE website..

Conclusion

Microchip have done a good job in improving the 16F core processor. They have removed almost all the awkward programming features of the 16F, and in the main provided useful and worthwhile enhancements while retaining a high degree of backwards compatibility.  It is a great shame that their programming tools and documentation are not of a commensurate standard at present, and let the product down rather badly.  Hopefully Microchip will improve these areas before too long.

References

1. PIC18FXX2 Data Sheet, DS39564B, available for free download from www.microchip.com

2. PIC18FXX2/XX8 FLASH Microcontroller Programming Specification, DS39576B, available as above

version 1.4, 19/01/05
