math, and more. The package costs $39 S&H. Contact:Scott Edwards Electronics 72037.2612@compuserve.com 964 Cactus Wren Lane Tel: 602-459-4802 Sierra Vista, AZ 85635 Fax: 602-459-0623 CIS: 72037,2612 ------------------------------ 4.3) Miscellaneous documentation on the PIC MicroChip Technology Incorporated - application notes ED Teck. Pubs Fred Eady 407-454-9905 BBS 407-454-3198 Writes articles for popular magazines. Has a PIC programmer kit for $70. BBS available, good source of information, very helpful. Parallax Stamps and programmer, etc. BBS 916-624-7101 Help 916-624-8333 AP Circuits BBS 1-403-291-9342 (Canada) Can download EASYTRAX(V2.06), various utilities, GERBER file proofers, etc. ------------------------------ 5.0) Notes for programmers: All PIC instructions are a single word. The equivalent of the immediateaddress mode of other processors is the literal mode, used by instructionsending in "LW", such as MOVLW, ADDLW, SUBLW, ANDLW, IORLW, XORLW, and RETLW.The byte of data used by these instructions is directly encoded in theinstruction itself. All PIC instructions take a single instruction cycle (four oscillator cycles) to execute, unless a conditional test is TRUE or the program counter is changed as a result of an instruction, in this case the execution takes two instruction cycles. For example: movlw 37 goto next next: movwf porta The goto instruction takes two cycles (1 to get the value of label "next" and 1 to load that value into the program counter) This is useful as a two-cycle NOP, and is often written as "goto .+1" to avoid the need for a label. The W register is equivalent to the accumulator on other processors. Almost all data movement, arithmetic, and logic operations use W. Instructions that operate on W and a register (i.e., instructions ending in "WF", like ADDWF and MOVWF) allow the result to be placed in either W or the register (but not both). This is specified by a ",W" or ",F" after the operand. The default is ",F", which will place the result in the register. This can cause a lot of confusion if you're not careful, so I recommend always specifying the destination explicitly. An example of a confusing instruction: incf foo,w ; w := foo+1 note that foo is unchanged! If you want the result in both W and the register, you can use either: incf foo,w mowwf foo or: incf foo,f movf foo,w The stack is not accessible to the programmer in any way other than the call and return instructions. There is no way to push or pull data, or even to examine the stack pointer. On the 16C5x family the stack has only two levels, so it is frequently necessary to write code in a different style than would be used on a typical processor; you can only call subroutines from your main code, or from a subroutine called from main, but no deeper. If you try to make a 3rd CALL, the 2nd return address is over-written so that the return from the 3rd CALL is OK but the return from the 2nd CALL ends up where the 1st CALL should return to. The 16CXX parts which implement an 8 level stack do so in a circular fashion, so that the 9th CALL over-writes the return address for the 1st CALL. The 16C5x family doesn't have a normal return instruction; instead it has RETLW, which stands for RETurn Literal Word. RETLW loads an eight bit constant into W (just as a MOVLW instruction would), then returns from the subroutine. This can be useful, but is aggravating if you want to return a computed value. On the newer PIC families there is a normal RETURN instruction. With the exception of the 17Cxx family, there is no way for software to read an arbitrary location of program memory. In order to implement lookup tables, it is necessary to combine the use of the ADDWF and RETLW instructions. For example, the following code implements a lookup table of the first four odd prime numbers: primes: addwf pcl retlw 3 retlw 5 retlw 7 retlw 11 To use the table, load the appropriate index (in this case, 0 to 3) into W, and "call primes". The addwf instruction adds the contents of W to the PC, which has already been incremented to point to the "retlw 3". The table will return with the value in W. The total time taken is 6 instruction cycles, or 24 oscillator cycles. Note that while on most processors the use of an out-of-range index will result in the use of incorrect data, but the program execution will continue normally, on the PIC a bad index value will cause the execution of arbitrary instructions! i.e. the computed address must be in the top 1/2 of page. Normally the index would range from 0 to the size of the table minus one, but it is possible to use other ranges by putting the retlw instructions somewhere other than immediately following the "addwf pcl". It is also possible to implement tables using a "subwf pcl", or perhaps other instructions with pcl as the destination. The subtract instructions (SUBWF and SUBLW) work differently than most people expect. SUBWF subtracts W *from* the contents of the register, and SUBLW subtracts W *from* the literal. (SUBLW is not available on the 16C5x family.) If you want to subtract a literal from W, it is easiest to use the ADDLW instruction with the two 's complement of the literal. For example: addlw 0feh ; w := w - 2 Some assemblers allow this to be written as: addlw -2 There is no instruction to take the two 's complement of W (like the NEG instruction on Motorola processors), but because of the way the subtract instructions work you can use: sublw 0 On the 16C5x family, the CALL instruction can only address the first 256 words of a bank of program memory. It is common practice to use "call extenders", which are simply GOTO instructions in the first 256 words with a target in the last 256 words. On the 16C57 and 16C58, if you plan to use indirect addressing (via the FSR and IND registers), it is vitally important that your reset code clear FSR before using any other RAM locations. Otherwise you may start up in an arbitrary bank, and as soon as you change FSR all your carefully set up variables will effectively disappear. Contributed by Eric Smith ------------------------------ 5.1) Useful Code Snippets 5.101) ZERO THE 16C57 RAM 5.102) LONG CALL Macro 5.103) LONG GOTO Macro 5.104) DATA SWAP TRICK 5.105) MULTIPLE PRECISION ADDITION ------------------------------ 5.101) ZERO THE 16C57 RAM ; The following code was written by Andrew Warren and is ; copyright (C) 1992 by Fast Forward Engineering. Permission ; is hereby granted for any non-commercial use so long as ; this copyright notice is retained. MOVLW PORTA ;PREPARE TO ZERO ALL REGISTERS EXCEPT MOVWF FSR ;THE PROCESSOR STATUS, PC, RTCC, AND FSR ;REGISTERS. CLRRAM MOVLW 00011111B ;ARE WE POINTING AT "USEFSR"? ANDWF FSR,W ; SKPNZ ;IF NOT, SKIP AHEAD. BSF FSR,BIT4 ;OTHERWISE, SKIP OVER THE PROCESSOR ;STATUS, PC, RTCC, FSR, PORTA, PORTB, ;PORTC, AND THE GLOBALLY-ACCESSIBLE FILE ;REGISTERS. CLRF USEFSR ;ZERO THE REGISTER AT WHICH WE'RE ;POINTING. INCFSZ FSR ;HAVE WE DONE THEM ALL? GOTO CLRRAM ;IF NOT, LOOP BACK AND ZERO ANOTHER. ; ALL FILE REGISTERS ARE ZEROED AND WE'RE IN DATA SEGMENT 0. ------------------------------ 5.102) LONG CALL macro ; The following code was written by Andrew Warren and is ; copyright (C) 1992 by Fast Forward Engineering. Permission ; is hereby granted for any non-commercial use so long as ; this copyright notice is retained. ; "Long Call" macro. Invoked by "XCALL any_address". ; Thanks to Chris Dalla for pointing out the need for the "+2" and ; "+1" sums in the last two lines of the macro. XCALL MACRO LABEL DATA 010010100000B+STATUS+256*((LABEL>>9)&00000001B) DATA 010011000000B+STATUS+256*(LABEL>>10) LIST W=1 ;For MPALC/PICALC, make this an "E=2". CALL LABEL LIST W=0 ;For MPALC/PICALC, make this an "E=1". DATA 010010100000B+STATUS+256*((($+2)>>9)&00000001B) DATA 010011000000B+STATUS+256*(($+1)>>10) ENDM ------------------------------ 5.103) LONG GOTO Macro ; The following code was written by Andrew Warren and is ; copyright (C) 1992 by Fast Forward Engineering. Permission ; is hereby granted for any non-commercial use so long as ; this copyright notice is retained. ; "Long Goto" macro. Invoked by "XGOTO any_address". XGOTO MACRO LABEL DATA 010010100000B+STATUS+256*((LABEL>>9)&00000001B) DATA 010011000000B+STATUS+256*(LABEL>>10) LIST W=1 ;For MPALC/PICALC, make this an "E=2". GOTO LABEL LIST W=0 ;For MPALC/PICALC, make this an "E=1". ENDM ------------------------------ 5.104) DATA SWAP TRICK by: Mike Keitz Swapping W with a File (RAM) register (PIC 16Cxx) Sometime you need to swap the data in W with that in RAM, a port, or a special purpose register (i.e. W<->F). This may appear to be easy with a few MOV instructions and a temporary RAM location, but when you sit down to code it you'll see that it'll take *two* temporary locations and 6 instructions to shuffle the data around using only MOVs. So, like many things with a PIC program, an unconventional technique can be really useful... like this: XORWF file,w XORWF file,f XORWF file,w Try it on paper until you're convinced it will work. Remember that XORing the W+F+F leaves a result of the original value of W (the two xors with the same data cancel out, so the final result is W xor 0 = W). The sequence affects the Z flag, of course (one that had a MOVFW in it would as well), but not in a particularly useful way. This will work as-is with a port which is set for all output. The port will be read 3 times, but written to only once during the second instruction. If the port has some bits set for input, the result left in W for the input bits is probably going to be wrong. (I'll leave it to you to analyze the situations when it happens to be right) A correct read of the input bits can be done with a conventional MOVFW after the routine is used to update the output bits. Understanding this, I now present the logical extension: swapping two file registers. This is tremendously useful to indirectly index two data sets at the same time (didn't think that was do-able, eh?) First, a conventional solution is worth considering: MOVFW FSR ;(the special purpose register) MOVWF tmp ;(a temporary location) MOVFW fsr2 ;(a location defined to hold the alternate index) MOVWF FSR MOVFW tmp MOVWF fsr2 This is 6 instructions, and requires a temporary location. If RAM is scarce in your design (and it probably is, since you want to indirectly index two data sets at once), consider using the W<->F method above... The obvious approach is to use the routine above three times, assuming you wrote it as a macro: swapwf FSR swapwf fsr2 swapwf FSR So this is 9 instructions, but W is not affected, and no temporary RAM is required. If you can tolerate losing the value in W while swapping the files, then this shorter version will also work: MOVFW FSR swapwf fsr2 MOVWF FSR This is a total of only 5 instructions, 1 less than the conventional method. Allocating a temporary location to store W during the swap would add 2 more. Everything is a trade-off, I suppose. ------------------------------ 5.105) MULTIPLE PRECISION ADDITION by: Mike Keitz This trick concerns multiple precision addition (i.e. 16, 24, etc. numbers) The ADDWF instruction adds two numbers, and sets the C flag if there is a carry out. But there is no instruction that adds W+F+C to carry the carry throught the higher bytes. There is an easy work-around for 16 bit numbers: simply increment one of the numbers before adding if the C bit is set. This is adequately detailed in the Microchip application notes, but I'll show it here for reference: add16 movfw datal ;Adds 16 bit number in datal and datah addwf resultl,1 ;to resultl and resulth, movfw datah ;leaving the result in resultl and resulth ;Following 3 instrs. are a primitive add with ;carry W+F+C -->F. ;C flag may not correctly represent ;carry out of W+F+C skpnc ;If no carry... incf resulth,1 ;If carry, add 1 to result. addwf resulth,1 ;Done. The problem with this technique is that it cannot be used for numbers larger than 16 bits because the C flag will not be set properly at the conclusion of the last 3 instructions. In particular, if resulth is FF and C is set going in, C will be incorrectly clear at the conclusion of the operation. (Don't you wish it was YOU and not your customer who was the first to try that?) No big problem with the 16 bit add, the result will still be correct, but the overflow won't be indicated. The best way around this I could think of was to use this 4-instruction sequence instead of the 3-instruction one above. I think there are other 4-instruction sequences that do essentially the same thing. Then a 24, 32, etc. bit add can be carried out (pun intended?) by using this sequence for the "middle" bytes. The faster skpnc/inc/add above can be used for the last byte if having a proper carry out of the whole operation is not required. ; Add W to F with proper carry in and out. skpnc incfsz f,1 addwf f,0 movwf f Although this has 2 conditional instructions, the execution time is always 4 cycles, if you're counting. (Another PIC rule of thumb: a skip instruction and the one after it will always take 2 cycles, unless the instruction possibly skipped is a goto or call) ------------------------------ 6) Attributions Thanks are due to the following who have contributed to this documention. Jory Bell Don Lekei <72677.2623@compuserve.com> Eric Smith Jeff Dague Steven M. Davidson Ian King kalam ? David B. Thomas Martin Vuille Alasdair MacLean Andrew Tucker Nigel Ballard Timothy McDonough Len Umina Hank Riley Siegfried Grob Andrew M Errington Henri Schultze Tom Mornini Lance Walley Christer Johansson Ed Meyer Simon Bridger Fernando Soares Chris Madden NOTE: .......If your name should be here, apologies. Let me know ! ------------------------------ Disclaimer: Inclusion of any code samples in this document does NOT imply any approval or guarantee as to the suitability of said samples for any purpose whatsoever other than as a self-training aid. I.E. If it blows your ICE, trashes your hard disc, wipes your backup, burns your building down or just plain don't work, #### IT AIN'T MY FAULT #### In the event of judicial ruling to the contrary, any liability shall be limited to the sum charged on you by me for the aforementioned document OR nothing, whichever is the lower. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Except where otherwise stated, this document Copyright (c) 1994,95 by T.A.Kellett, [T.A.K.DesignS Warrington UK ] all rights reserved. This FAQ may be posted to any USENET newsgroup, on-line service, or BBS as long as it is posted in its entirety including this copyright statement. This FAQ may not be distributed for financial gain. This FAQ may not be included in commercial collections or compilations without express permission from the author(s). _______________________________________________________________________________ Tom Kellett < Tom@takdsign.demon.co.uk > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~