For example, if an applica-tion were to be run on two different PIC microcontrollers, each with different built-inhardware, the ifdef “execute if define label is found” conditional assemb
Trang 1THE DIFFERENCE BETWEEN DEFINES AND MACROS 493
which is not very helpful or easy to understand without a reference to how the pins areorganized In comparison, the same instruction with the Serflag define, i.e.,
bsf Serflag
is much easier to understand without the aid of documentation or even descriptive ments The single define eliminates remembering (or looking up) where the bit is locatedand which bit it is When reading the code, using the define directive enhances the read-ability of the purpose of the instruction over the actual source information
com-Defines work because they directly copy in the string and let the assembler evaluate
it This is different from equates, which evaluate a string and store it as a constant erenced to the label This can cause some subtle differences that can be a problem ifyou don’t know what you are doing
ref-For example, if you had the code
variable A = 37 ; ”Variable” is a run time variable
Test1 equal A * 5 ; Test1 = 185
#define Test2 A * 5 ; Test2 is Evaluated when it is used
iden-In the sample code above, I declared the variable to be A Variable is an MPASMdirective to create a temporary storage value during the application’s assembly and will
be discussed in the later sections of this chapter When it is used in Test1, the value of
A when the assembler processor encounters the statement is used, multiplied by 5 andassigned to Test1 After Test1 and Test2 are defined in the code, A is modified, whichresults in a different value being calculated for Test2 when it is used later in the application
A useful function that defines can provide is that they can provide constant stringsthroughout an application I use this ability to keep track of my “version number” of anSimpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 2Defines can be used for many different purposes While macros can be used only forreplacing full lines of text, defines can simplify instruction programming and providecommon information or text strings Neither macros nor defines can replace each other,but their functions are complementary and allow you to create richer, more easily pro-grammed and understood applications.
The Assembler Calculator
While not really part of the macro processor, the ability of the MPASM assembler(and most compilers) to do constant calculations during assembly or compilation canmake applications easier to develop and avoid your having to spend time with ahandheld calculator working out the constant values needed in your application Theassembler calculator provides capabilities for both your macros and regular pro-gramming that can be taken advantage of in a variety of situations
The assembler calculator works on algebraic equations, similar to how they’reused in high level languages It is important to remember that the calculator works
as part of the last pass of the assembler—to allow the insertion of data generatedduring the build cycle, such as the address of an application variable This can beconfusing because variables available for use by the assembler calculator aredeclared within the source in a manner similar to that of variables used in theapplication
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 3THE ASSEMBLER CALCULATOR 495
So far in this book you have seen the assembler calculator in operation calculatingconstant-value arguments for instructions such as
movlw (1 << GIE) | (1 << T0IE)
This instruction loads w register with a byte, destined for the INTCON register, whichhas the GIE (7) and T0IF (5) bits set In this case, the assembler calculator is used tochange bit numbers to actual values to be loaded into a byte The trick in this statement
is knowing that shifting one by the bit number converts the bit number into a constantvalue that will set the bit when loaded into a register
This is useful and avoids having to figure out what value is used for specific bits beingset In the preceding example, if this trick had not been used, I would have to remem-ber (or generate on a calculator) that bit 7 being set is the same as adding 128 and thatbit 5 being set is the same as adding 32 The result of these two values is 160 decimal
or 0x0A0 Using the assembler calculator, I didn’t have to worry about any of this
To reset specific bits, the same trick can be used, but the bits have to be reset, which isdone by a bitwise inversion of the bits and then ANDing the result with the current value.XORing the set bit value with 0x0FF accomplishes the bitwise inversion For example,
to clear bits 4, 2, and 1 in the w register, the following instruction could be used:
andlw 0x0FF ^ ((1 << 4) | (1 << 2) | (1 << 1))
If you were to do this manually, you would have to follow these steps:
1 Calculate the values for bits 4, 2, and 1 being set:
(1 << 4) = 16(1 << 2) = 4(1 << 1) = 2
Trang 4496 MACRO DEVELOPMENT
what I meant when I said the assembly calculator is easier and less prone to mistakes.Table 10.1 lists the calculator’s arithmetic operators All the operators have two param-eters, except for when “−” negates a value or the complement (“~”) operator, which onlyhave one parameter
In the clear bits example, I could have used the equation format
andlw ~((1 << 4) | (1 << 2) | (1 << 1))
instead of adding the 0x0FF ^ characters in the preceding instruction
For 16-bit values, you can use the “low” and “high” assembler directives Forexample, if you wanted to jump to a specific address in another page, you could usethe code
movlw HIGH Label ; ”Label“ is the
movwf PCLATH ; Destination
movlw LOW Label
movwf PCL
TABLE 10.1 OPERATORS AVAILABLE TO THE ASSEMBLER CALCULATOR
– Subtraction/negation If no first parameter, then negation
<< Shift left Shift the first parameter to the left by
second parameter number of bits
>> Shift right Shift the first parameter to the right by
second parameter number of bits
& Bitwise AND AND together the parameter’s bits
~ Complement XOR the parameter with 0xFF to get the
complemented or “inverted” value LOW Low 8 bits of a AND the parameter with 0xFF
constant value HIGH High 8 bits of a 16-bit AND the parameter with
constant value 0xFF00 and then shift right 8 bits
$ Current address Current address of the instructionSimpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 5THE ASSEMBLER CALCULATOR 497
which is the same as
movlw ((label && 0x0FF00) >> 8)
movwf PCLATH
movlw LABEL && 0x0FF
movwf PCL
In this example, the function of the first four instructions (which use HIGH and LOW)
is much clearer to somebody reading the code than the second four instructions, whichrequire the reader to evaluate what the arithmetic operations are doing
As has been discussed earlier in this book, the $ operator returns the current programcounter, which is a 16-bit value that can be manipulated using the assembler calculator’soperators as if it were a constant
Along with the arithmetic operations, parentheses (the “(” and “)” characters) can beused in the expressions to make sure that the operation is executed in the correct order
In the preceding examples I have used parentheses to make sure that the correct order
of operations takes place for these instructions
Variables that are only used in assembly can be declared using the format
variable label [ = constant][, ]
These variables are 32 bits in size and can be set to any value using the operators listedabove and employing the “=” operator to make an assignment statement such as
LABEL1 = LABEL1 * 2
It is important to remember that the label is not an application variable (i.e., itcannot be modified by the PIC microcontroller as it is running), and when it is assigned
a new value, it must be in the first column of the assembly-language source When it
is being read in another statement, it can appear in any column (except for the first)
in the line
Taking a cue from C, assembler variable assignment statements can be simplified ifthe destination is one of the source parameters These operations can be confusing touse and read unless you are familiar with C Table 10.2 lists the combined assignmentstatements
The assembler calculator also can do comparisons between two parameters using theoperators listed in Table 10.3 If the comparison is true, a 1 is returned; otherwise, a 0
is returned The comparison operators are required for the “conditional” assembly ations presented in the next section
oper-These comparisons can be compounded with || and &&, which are the logical ORand logical AND operators, respectively || returns 1 if either of its two parameters arenot equal to 0 && returns a 1 if both parameters are equal to 0 This operation brings
up an important point: In the assembler calculator, a “true” condition is any nonzero
value The variable A, after executing
A = 7 && 5
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 6498 MACRO DEVELOPMENT
TABLE 10.2 COMBINED ASSIGNMENT OPERATORS
AVAILABLE TO THE ASSEMBLER CALCULATOR
<<= Parm1 = Parm1 << Parm2
>>= Parm1 = Parm1 >> Parm2
TABLE 10.3 COMPARISON OPERATORS AVAILABLE
TO THE ASSEMBLER CALCULATOR
OPERATOR OPERATION
== Return 1 if two parameters are equal
!= Return 1 if two parameters are different
> Return 1 if the first parameter is greater
than the second parameter
>= Return 1 if the first parameter is greater
than or equal to the second parameter
< Return 1 if the first parameter is less
than the second parameter
<= Return 1 if the first parameter is less
than or equal to the second parameter
|| Return 1 if either of the two parameters
is not zero
&& Return 1 only if both of the two parameters
are not zero
! Toggle the logical value of a single
parameterSimpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 7MULTILINE C MACROS 499
will be loaded with 1 because 7 and 5 are not 0, and both are assumed to be “true.”This operation of logical values is not unique to the MPASM assembler calculator; mostlanguages use this convention for “true” and “false.”
The last operator is !, which toggles the logical state of a value, for example,
C, you may have noticed that there isn’t a “macro” directive as there is in assembly guage, but you can use defines as macros, and using C’s ability to concatenate the text onthe next line to the current line, you can produce your own multiline macros
lan-The #define directive in C is similar to the define directive in assembly language;when it is encountered, it replaces the label with the string following the define andreplaces any parameters with the arguments of the define For example, if you had a cir-cular buffer 20 entries in size and you wanted to increment the indexes to the buffer, youcould use the code
buffindex++; // Increment the buffer index
if (19 < buffindex) // If the index is 20 or greater, reset
buffindex = 0;
If the code were used often and for different index variables, you might want to considerturning it into a single line of code and using it as the basis for a define If you are familiarwith C, you would know that you could reduce the three lines above to the single line
if (19 < ++buffindex) buffindex = 0; // keep ++index in buffer range
Despite being difficult to read, this single line will increment buffindex and ensurethat it is within range for the 20-element circular buffer The line then could be turnedSimpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 8500 MACRO DEVELOPMENT
into the define (which can be used as a macro within C):
#define buffinc(indexvar) if (19 < ++indexvar) indexvar = 0;
and each time it is invoked, the code buffinc(buffindex) would be replaced with thesingle-line buffer increment and tested to ensure that it is with the index range for the20-element circular buffer
The problem is that the operation of the define is not easily read, and if there were
an error in the code, you would not be able to see it easily What is needed is a way toformat the define so that the code can be seen easily
Fortunately, C has the backslash character (\) directive, which appends (or nate) the next line of text onto the end of the current line By using this character direc-tive, you can create a multiline define (or macro) that is much easier to read andunderstand, minimizing the opportunity for errors to come into your application Forexample, using the backslash character, the buffinc define could be rewritten as
concate-#define buffinc(indexvar) \
indexvar++; \
if (19 < indexvar) \
indexvar = 0; // keep ++index within buffer range
When the backslash is used, the four lines are concatenated together, providing a similarform to the C compiler as the previous define However, it’s in a format that is much easierfor you to read or understand
Note that when using the backslash character, comments to line end (using the //format) cannot be used Instead, you must either restrict your comments to the last line
of the macro or use the /*—*/ comment form
Reading over this section, you might be tempted to ignore using multiline defines asmacros as I’ve shown here and just create functions for the code This is possible, but
it is a much less efficient way of implementing short pieces of code, such as the ple shown here Implementing the code here as a function will require saving the param-eter in a temporary area and then saving it in a destination variable when the functionhas completed Depending on the PIC MCU you are working with and the size and com-plexity of the function you wish to implement, the overhead of saving the data, callingthe function, returning from the function, and restoring the data can take more instruc-tions and instruction cycles than what is required for the macro
exam-Conditional Assembly/Compilation
If you have taken a look at some of the more complex macros presented in this book,you probably will be surprised to see that there are “structured language” statements(if, else, endif, while, and endw, as listed in Table 10.4) At first glance, thesestatements are providing high level language capabilities to the PIC microcontrollerassembly code Unfortunately, they’re not; these statements provide you with theSimpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 9CONDITIONAL ASSEMBLY/COMPILATION 501
capability of conditionally including statements in your application Conditional bly statements are not part of the macro processor; they can be used outside macros andcan be used anywhere in application code Unlike the operation of if and while thatyou are used to, allowing condition execution of the application, they are actually exe-cuted when the source code is being assembled and can be used to conditionally changeconstant values or to add or delete sections of code
assem-Conditional assembly statements are actually “directives,” and they are processedalong with other directives (such as EQU, dt, and so on) For example, if an applica-tion were to be run on two different PIC microcontrollers, each with different built-inhardware, the ifdef (“execute if define label is found”) conditional assembly could
be used in the following manner:
TABLE 10.4 CONDITIONAL ASSEMBLY DIRECTIVES AVAILABLE
IN MPASM
CONDITIONAL
ASSEMBLY DIRECTIVE FUNCTION
if Return “true” if both parameters are the same
ifdef Return “true” if parameters are not the same
ifndef Return “true” if the first parameter is greater
than the second else Return “true” if the first parameter is greater
than or equal to the second endif Return “true” if the first parameter is less than
the second while Return “true” if the first parameter is less than
or equal to the second endw Return “true” if both parameters are “true”
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 10502 MACRO DEVELOPMENT
second is ignored If the USARTPres label is not defined, then the first block of code
is ignored, and the second block is assembled as source code
For all if conditional assembly directives (including ifdef and ifndef), endif
is required, and else is an optional conditional assembly directive that will include thecode if the original condition was not true You may see a null statement after an if,
to have the else execute like
ifdef USARTPres ; If USART Present, don’t add any codeelse
endif
It can be somewhat difficult to understand what is happening Instead of using else
to provide conditional execution in the case of the label not being present, the absence
of the define should be checked for using the ifndef directive
There are a number of tricks that you can use with ifdef and ifndef conditionalassembly statements that can make your code development easier and more flexible Thefirst is conditionally deleting code As you work through an application, often you willwant to remove some code to test out different aspects of it Elsewhere in the book Italk about the idea of “commenting out the code” simply by putting the comment direc-tive (the “;” or semicolon character) before the statement such as
; addlw 0x0FF ; #### - Instruction not needed, but kept
For single instructions, this is easy to do and easy to keep track of For many instructions,
it can be difficult to keep track of everything that has to be removed (but kept) An easy way
of doing this is to put an ifdef and endif statement before and after the code, as in
ifdef Used ; #### - Ignore following
: ; Block of Code NOT to be part of application
endif ; #### - Ignore above
It takes literally just a few seconds to remove the code and can be disabled just asquickly (by defining Used or deleting the ifdef and endif statements)
The second trick is to allow the logic of an application to be used in multiple PIC controllers that may have different built-in hardware features In the preceding example,
micro-by using the ifdef directive, I can have the code that takes advantage of the built-in serialport hardware of a specific PIC microcontroller or insert bit banging code in its place if theselected PIC MCU does not have a built-in serial port I should point out that when anMPLAB IDE application is built, a define label is created indicating the PIC MCU partnumber For example if you were assembling an application for the the PIC16F84, the 16F84label is available for testing by the ifdef and ifndef directives
I have taken advantage of this feature in some applications where the code can run
in different devices For example, the following code will allow an application to runSimpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 11if ((($ & 0x01800) ^ (Label & 0x01800)) != 0)
movlw HIGH Label ; Different Pages - Update PCLATH
movwf PCLATH
endif
goto Label & 0x07FF ; Jump to Label
In this example, if the destination is in a different page from the current location (which
is returned by the $ directive in MPLAB), then PCLATH is updated before the gotostatement
The preceding example is suboptimal for four reasons The first is that whether or notPCLATH has to be updated is variably based on the address of the goto statement Amore accurate way of doing this would be
if (((($ + 2) & 0x01800) ^ (Label & 0x01800)) != 0)
movlw HIGH Label ; Different Pages - Update PCLATH
movwf PCLATH
endif
goto Label & 0x07FF ; Jump to Label
In this case, the possible address of the goto is checked rather than the current address.
There is the possibility that the current address will be in a different page than the goto,and PCLATH may or may not be updated correctly
The second problem is that this code takes up a different amount of space ing on which path is taken Doing this can result in a address “phase” error that indi-cates that during the different passes in the assembler, required addresses change in away that makes correct assembly impossible These different addresses are caused whenSimpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 12depend-504 MACRO DEVELOPMENT
the conditional code executes for a second time, and addresses come out differently.Phase errors are very hard to find, and chances are that if you have one in one location,there will be a number of them
The best way to avoid phase errors is to always make sure that the same number of tions are used no matter what path is taken in the conditional assembly For the precedingcode, I can add two nops as the code is inserted if else (assembled if the condition isnot true) is active to make sure that no addresses in the application will change:
instruc-if (((($ + 2) & 0x01800) ^ (Label & 0x01800)) != 0)
movlw HIGH Label ; Different Pages - Update PCLATH
movwf PCLATH
else
nop ; Add Two instructions to prevent
endif
goto Label & 0x07FF ; Jump to Label
The third problem with this code is that a message may be produced indicating thatthe jump is to a different page To avoid this, the goto address should have the currentpage bits added to it This changes the code to
if (((($ + 2) & 0x01800) ^ (Label & 0x01800)) != 0)
movlw HIGH Label ; Different Pages - Update PCLATH
movwf PCLATH
else
nop ; Add Two instructions to prevent
endif
goto (Label & 0x07FF) | ($ & 0x01800) ; Jump to Label
The next problem with this code is that it changes the w register This means that thepreceding code cannot be used if the contents of the w register are going to be passed
to the destination Label Instead of explicitly loading PCLATH with the destination,the bits can be changed individually using the code
if (((($ + 2) & 0x01000) ^ (Label & 0x01000)) != 0)
bsf PCLATH, 4 ; Label in Pages 1 or 3
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 13goto (Label & 0x07FF) | ($ & 0x01800) ; Jump to Label
Looking at this mess of conditional assembly statements, it is starting to look alot like a macro, and this is the reason why I have included conditional assemblystatements in this chapter Conditional assembly statements, while simplifying yourapplications in some ways, will result in fairly complex applications in others Thepreceding code has really become the lgoto macro:
lgoto Macro Label
if (((($ + 2) & 0x01000) ^ (Label & 0x01000)) != 0)
is not an issue in the PIC18 processor architecture because there are instructions thatallow movement to any address that the processor can execute)
Along with program constants, you also can declare integer variables that can
be updated during assembly of the application The variable directive, priately enough, is used to declare the variables with optional initial values, asshown below:
appro-variable i, j=7
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 14506 MACRO DEVELOPMENT
The variables that can be used as constants in the application or as parts of labels As Ipointed out in the preceding section, variables can be used to avoid having to calculateyour own constant values
I often use variables as counters for use with the while conditional assembly ment For example, if I wanted to loop six times, I could use the code
state-variable i=0 ; Declare the Counter
while (i < 6)
: ; Put in Statements to be repeated six times
i = i + 1 ; Increment the Counter
goto $ + 7 ; Put in Patch Space
which puts in a jump over six instructions of “patch” space, the listing file looks like
0000 2807 00036 goto $ + 7 ; Put in Patch Space
The conditional assembly instructions if and while use the same condition test format
as the if and while statements of the C language The condition tests can take place onlySimpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 15USING DEFINES AND CONDITIONAL ASSEMBLY FOR APPLICATION DEBUG 507
on constant values of up to 32 bits in size Like C’s if and while, the MPASM blers conditional assembly statements use the two parameter conditions listed in Table 10.5.When the statements are “true,” a nonzero value is returned If the statements are
assem-“false,” then 0 is returned
Using Defines and Conditional
Assembly for Application Debug
In this book I talk a lot about the need for simulating applications before they can beburned into actual PIC microcontroller hardware For many applications, this isn’t anissue, but for applications that have very long delays built into them, this can be a verysignificant issue because the time required for external hardware initializations actuallycan take many minutes in MPLAB because the simulation has to go through long delayloops Another situation could be for hardware that is nonessential to the task at handbut that requires a relatively complex interaction with simulated hardware or uses built-
in PIC microcontroller interfaces that are not simulated in MPLAB An example of thelatter situation is a PIC microcontroller application that uses the ADC for testing batteryvoltage levels, but if the hardware registers are accessed in the simulator, then chancesare the operation complete flag and interrupt will not work properly, and even if theydid, the value returned by the ADC would be invalid
Dealing with this problem is relatively simple with use of the conditional assemblydirectives built into the MPASM assembler These instructions will allow execution toskip over problem code areas simply by specifying a flag using the #DEFINE directive
TABLE 10.5 COMPARISON OPERATORS AND RETURN
VALUES
CONDITION FUNCTION
== Return “true” if both parameters are the same
!= Return “true” if parameters are not the same
> Return “true” if the first parameter is greater
than the second
>= Return “true” if the first parameter is greater
than or equal to the second
< Return “true” if the first parameter is less than
the second
<= Return “true” if the first parameter is less than
or equal to the second
& Return “true” if both parameters are “true”
| “True” if either one of the parameters is “true”
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 16508 MACRO DEVELOPMENT
The state of the #DEFINE flags is generally defined by their presence or absence Themost common one that you will see in my code is the Debug label that is defined forsimulation by using the statement
#DEFINE Debug
You usually will see this statement on the second or third line of my applications,although when I am ready to burn an application into a PIC microcontroller, I changethe statement to
ifndef Debug
call UnreasonablyLongDlay ; Wait for External Hardware
endif
In this code, if Debug has not been set in a #DEFINE statement, the instructions thatare to be skipped over are built into the application If Debug has been defined, thenthe nop is put into the application in the place of the call instruction If the number
of instructions is not matched with an equal number of nops, you could run into the uation where the code assembles in different sizes for the different execution paths, which
sit-results in the phase error, which is very hard to debug
Along with being used for taking out lengthy delays or hardware inconsistencies in theMPLAB simulator, Debug conditional assembly code can be used to put the applicationinto a specific state This can save quite a bit of time during simulation and also can beused to initialize the state of the application before simulation begins For example, when
I was creating the EMU-II emulator application code, I used the Debug label to enter inthe following commands:
ifdef Debug ; Clear simulated application program Flash movlw ‘P’ ; Start a program memory Program/Clear Flashcall BufferAdd
Trang 17DEBUGGING MACROS 509
This code initiates the command to load a new application into the Flash (and in ration for the code, the Flash is cleared), followed by a Ctrl-C to stop the expectedtransfer The reason for requiring this code is that any writes to the simulated Flash wouldnot be reset when I rebuilt the application These commands “clear” the simulated Flash
prepa-so that each time the application code is reset, I would be working with cleared Flashinstead of something that I would have to simulate the operation of downloading codeinto it This simulation isn’t possible because of my use of the USART in the applica-tion, which is not simulated within MPLAB
When the EMU-II application was being debugged, I placed a breakpoint at a tion where I wanted to start debugging, knowing that the program memory was clearedand I was ready to start looking at how the application executed
loca-Multiple Debug statements could be put into the application code, but I would notrecommend that you do this Multiple statements get confusing very quickly, as well asoften becoming incompatible Instead of using multiple Debug labels, I would rec-ommend that you just use one, and when you have fixed the current problem you areworking on, then you can change the ifdef Debug and ifndef Debug statements
to target the next problem
Debugging Macros
In the preceding pages I’ve given you a lot of information on how to create plex macros; now I want to spend a few pages discussing how to debug these mon-sters As the macro processor executes, it is probably going to put in some code thatwill be surprising to you I should point out that normally a C compiler will notinclude a listing showing the inserted statements, the same way an assembly-language program will It is not unusual to discover that the application does notwork as you expect because the macro processor has inserted some code that doesnot work as you would expect, and now you are left with the task of determiningwhere the problem lies In this section I will pass along a few tricks that I have dis-covered that make the debugging of macros easier and allow you to use them withgreater confidence
com-The first trick is something that a surprising number of people do not think of: beforeusing a macro in their applications: Spend some time testing your macro in all possi-ble ways to ensure that it does work as you expect Earlier I showed the rather complexmacro that I have developed for producing code that will allow a mid-range PIC MCU
to jump to addresses outside the current execution page:
lgoto Macro Label
if (((($ + 2) & 0x01000) ^ (Label & 0x01000)) != 0)
Trang 18vari-This table only lists a few of the possible starting points and destinations that are sible Note that the second case should produce an error because the starting address isone address away from the destination, and the macro takes up three instructions In thiscase, the macro will attempt to write instructions over the instructions already placed
TABLE 10.6 TABLE DEVELOPED TO TEST THE OPERATION OF THE lgoto MACRO
TEST DESTINATION STARTING
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 19DEBUGGING MACROS 511
the macros will avoid the need to go back later when your code isn’t behaving properlyand you are trying to understand why some cases work properly and others don’t The key to debugging macros is being able to observe what changes the macro codemade and whether or not they are appropriate for use in the application This may seem
to be identical to the testing done on the macro, but there is a subtle and very importantdifference: In macro testing, you are creating test cases and comparing the changes made
to specific registers to verify the operation of the macro When you are observing thechanges made by a macro in an application, you have to understand what the purpose
of the macro was and whether or not the changes that were generated were appropriatefor that point in the application
If you were debugging the lgoto macro, you might want to check to see what theexecution address is after the macro’s code has executed and if any other registerschanged inadvertently Ideally, you should not be setting a breakpoint at the expecteddestination (because there is a chance that execution would end up there at some point)but instead single-stepping through the macro’s statements to make sure that there is nojump to an unexpected address It can take some ingenuity to test the operation of themacro by seeing how it works in the application
An important key to debugging macros is being able to read what has been added tothe application When macros are expanded into the source code, the new instructionscan be difficult to see and work through For example, when macros execute, the con-ditional statements (if, ifdef, ifndef, and while) may or may not be displayeddepending on the operation I think of the regular instructions of a macro statement to
be print or echo statements, and they are copied into the source as is (except in thecase where one of the parameter strings is present in the instruction or on the line or theassembler calculator is used to produce a specific value) To illustrate these points, I havecreated conditional assembly statements for a macro:
When the macro is “expanded” (or executed), the following information will be displayed
in the listing file:
00000000 M variable i = 0
M if (i == 0)Addr 3E00 M addlw 0 - i
Trang 20512 MACRO DEVELOPMENT
are actually added to the listing file are identified by the address of the instruction and its bitpattern broken up as I have shown for the addlw 0 – 1 instruction In this example, onlyaddlw 0 – 1is inserted into the source code; the directives (variable, if, else, andendif), as well as the sublw i instruction, are all ignored
Whiledirectives are somewhat unusual to follow because the code is repeated withinthem, and there is no start and end reference information that can be easily seen Forthe example
In this case, the while and endw directives are not repeated as you would expect Again,
to really understand what is happening, you have to go back and look at the instructionsentered into the application code These instructions are displayed to the left of thecolumn of M’s along with the variable updates
Probably the best way to debug a macro is to single-step in the simulator through themacro If you are doing this in the source file, you will find execution jumps to wherethe macro is defined that can be quite disconcerting and confusing because the param-eters are displayed, not what the parameters actually are These problems can be avoided
by simulating from the listing file instead of from the source file
Breakpoints cannot be placed in MPLAB at a macro invocation for a source file When
I want to set a breakpoint at a macro invocation, I will put a nop instruction before it
to give the MPLAB simulator somewhere on which to hang the breakpoint This alsoworks with a listing file, but in this case you do not have to add the breakpoint becausebreakpoints can be put at instruction statements within the macro-generated code.Debugging macros is really the same as debugging a standard application, exceptthat there is no simulator or debugger This is an important point to remember whenyou are creating the macro You may want to “flag” where the code is executing usingmessages (using the messg directive), which is the same as printf debugging in
C For example, if you have the code
if (A == B)
messg “A == B”
; put in code for A == B
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 21STRUCTURED PROGRAMMING MACROS 513
condi-Structured Programming Macros
To finish off this chapter, I wanted to leave you with a few macros that should give yousome ideas on how powerful macros are when you need some processing to be donewhen the application is being created, as well as give you a tool for making your PICmicrocontroller assembly-language code easier The structre.inc file containsnine macros that you can use for your own applications to add structured programmingconditional execution
The macros are in the format
whereTestcan be do, until, while, if, else, and end, and Const/Var ifies whether or not the second parameter is a constant or a variable The differentmacros are listed in Table 10.7
spec-When conditional macros are invoked, the parameters passed to the macro includethe two conditions for testing as well as the condition to test for The standard C testconditions are used, as listed in Table 10.8
Only one condition can be accessed within a macro at any time There is no ability
to AND or OR conditions together Using these macros in your application is quitestraightforward, and if you are new to PIC microcontroller programming, you might want
to take a look at using these macros for your conditional programming Executing somecode conditionally if two variables are equal would use the following macro invocations:
_ifv VariableA, ==, VariableB
: ; Code to Execute if VariableA == VariableB_end
Using these macros can be expanded to include an else condition for code that cutes if the condition is not true:
exe-_ifv VariableA, ==, VariableB
: ; Code to Execute if VariableA == VariableB_else
: ; Code to Execute if VariableA != VariableB_end
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 22condition is “false.” Must have _end following.
_ifc Parm1, Execute the following code if the variable (Parm1) and constant Condition, (Parm2) operated on with the condition is “true.” _else following Parm2 is optional, and the code following it will execute if the condition
is “false.” Must have _end following.
_else Execute the following code if the result of the previous _if macro
was “false.” Execution before the _else jumps to the next _end macro.
_end End the _if or _whilemacro invocation If previous operation was
“_while”, then jump back to “_while” macro.
_whilev Parm1, Execute the following code while the two variables (Parm1 and Condition, Parm2) operated on with the Condition are “true.” Must have Parm2 _end following, which will cause execution to jump back to the
_untilv Parm1, Jump to previous _do if the variables (Parm1 and Parm2)
Condition, Parm2 operated on with Condition are “false.”
_untilc Parm1, Jump to previous _do if the variable (Parm1) and the constant Condition, Parm2 (Parm2) operated on with Condition are “false.”
TABLE 10.8 COMPARISON OPERATORS USED IN
STRUCTURED PROGRAMMING MACROS
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 23STRUCTURED PROGRAMMING MACROS 515
For these macros, I decided to use as close a label to actual programming structures
as possible, which is why I used the standard names with the underscore characterbefore them
There are five aspects and features of the macro processor that have influenced howthese structured conditional execution macros were created The first is that you cannotdistinguish between constants and variable addresses in a macro When the macro isinvoked, a variable address is passed to the macro instead of the variable label This wasprobably done to simplify the effort in writing the macro processor For this applica-tion, it means that either what the value types are must be specified explicitly or theremust be a way of declaring variables so that they can be differentiated from constants
I looked at a number of different ways to tell the two types of values apart and foundthat I could not do it without changing how variables were declared, which would makethe application code more complex Because I could not tell the two different types ofdata apart, I decided to always make the first parameter a variable and the second one
a variable (v) or constant (c) depending on the character at the end of the macro.Interestingly enough, this conversion of data does not extend to nonalphanumeric char-acters In the macros, the condition test is specified, and this is passed into the macro
I take advantage of this to avoid having to create multiple macros each with a differentcondition test Inside the macro, I use this test condition parameter to determine what
it actually is (there is no way of comparing nonnumeric values in the conditional bly functions of the macro processor) For example, in the _ifv macro, to find out what
assem-is the condition, I test the specified condition against different cases:
if (1 test 1) ; Check for “==”
movf a, wsubwf b, wbtfss STATUS, Z ; Zero Flag Set if Trueelse
if (1 test 0) ; Check for “!=”/”>”/”>=”
if (0 test 1) ; Check for “!=”
movf a, wsubwf b, wbtfsc STATUS, Z ; Zero Flag Reset if True
if (1 test 1) ; Check for “>=”
movf b, wsubwf a, wbtfss STATUS, C ; Carry Set, “>=”
elsemovf a, wsubwf b, wbtfsc STATUS, C ; Carry Reset, “>”
endifendifelse
if (0 test 1) ; Check for “<”/”<=”
if (1 test 1 )
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 24516 MACRO DEVELOPMENT
movf a, wsubwf b, wbtfss STATUS, Celse
movf b, wsubwf a, wbtfsc STATUS, Cendif
elseerror Unknown “if” Conditionendif
endif
endif
To help determine if there is an error in the code, note that if no Condition test is
“true,” an “error” is forced, indicating that the input condition is unknown This can beanother technique for debugging macros: If conditional code ends up somewhere where
it shouldn’t be, an error message will alert you to the situation and help you to debugthe application
The macros themselves use conditional code to produce simple code for the actualfunctions For example, in the code
_ifv Parm1, >, Parm2
: ; Code to Execute if Parm1 > Parm2
_else
: ; Code to Execute if Parm1 <= Parm2
_end
the best-case assembler would be
; _ifv Parm1, >, Parm2
movf b, w
subwf a, w
btfss STATUS, C
goto _ifelse1 ; Not True, Jump to “else” code
: ; Code to Execute if Parm1 > Parm2
Trang 25STRUCTURED PROGRAMMING MACROS 517
records what was the previous operation This is important for _else, _end, and_untilto make sure that they are responding correctly The last stack records the “labelnumber” for the previous operation These stacks are combined with a label number tokeep track of what is the correct label to use and jump to
The label number is appended to the end of the label using the #v(Number) feature
of the MPASM macro assembler When a label is encountered with this string at the end,the Number is evaluated and concatenated to the end of the string For the label
state-_ifv Parm1, >, Parm2
_whilec ParmA == ParmB
: ; Code to Execute if Parm1 > Parm2
; _ifv Parm1, >, Parm2
movf b, wsubwf a, wbtfss STATUS, Cgoto _ifelse1 ; Not True, Jump to “else” code
; _whilec ParmA == ParmB
_ifwhile2:
movf ParmA, wsubwf ParmB, wbtfss STATUS, Zgoto _ifend2: ; Code to Execute if Parm1 > Parm2 : ; while ParmA == Constant ParmB
goto _ifwhile2_ifend2:
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 26by the three stacks I mentioned earlier
The stacks used for storing the label number and the other values are not stacks per
se but actual variables that are shifted over by four and then loaded with the value Thislimits the total label numbers to 16 different labels, but for most small PIC microcon-troller applications, this should be sufficient If you feel that more are needed, then youcould modify the macros to use a separate stack for _if, _while, and _do, as well
as come up with a way of having multiple stack values for each one With a bit of work,you could have up to 64 label numbers for each type of structured programming macro
by expanding the type of macro saved to four different types
The macros described in this section could be considered to come under the heading
of “out there.” These macros involved quite a bit of work to get them to the point wherethey are now After reading this chapter, you do have the knowledge to produce macroslike this, but I want to caution you to think through what you are trying to accomplish.Macros, almost by definition, do not produce functions that are easy to debug or evenunderstand
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 2711
BUILDING AND LINKING
One of the most important enhancements to the PIC®application code developmentprocess made by Microchip over the past few years is the inclusion of a linker and librarymanager for MPLAB IDE These tools allow code to be developed much more efficiently
by multiple individuals than the traditional method of assembling or compiling a singlelarge file To fully take advantage of linked applications, there are a number of new con-cepts that you will have to be comfortable with These concepts are not very difficult
to understand, and you should be able to apply them almost immediately The ability tolink portions of code together will provide you with the ability to develop applicationsmore effectively for the PIC microcontroller
I have indicated that it is not very difficult to learn how to create applications that arelinked, but I would recommend that when you start learning to program the PIC micro-controller in assembly language, you do it by the traditional single-file approach Thereason I make this recommendation is that you are learning a number of new concepts,even if you are an experienced programmer, and adding additional concepts will makethe process more complicated The additional complications are not limited to develop-ment of the application code but also to using MPLAB IDE for application simulationand debugging In these cases, you will have to have multiple source file windows activeand will have to be very familiar with your code to be able to follow its execution pathbetween different modules When you become proficient at creating and debuggingsimple applications for the PIC microcontroller, you should come back to this chapter
to learn more about developing linked applications because you will be able to stand them more effectively as they relate to the PIC and PIC microcontroller applications
under-Creating Linked Applications
Creating a linked C application (using the OIC18 or PICC compilers) is surprisinglyeasy in MPLAB IDE It is accomplished simply by right clicking on “Source Files” inthe file application box of the MPLAB desktop and then selecting “Add Files ” and
Copyright © 2008, 2002, 1997 by The McGraw-Hill Companies, Inc Click here for terms of use
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 28520 BUILDING AND LINKING
then selecting the files that you would like to add The source files could be but don’thave to be in the same folder as each other or, for that matter, the project hex files thatmake your management of source files quite a bit easier You also can customize wherethe generated code is placed into the PIC microcontroller Unfortunately, these capa-bilities are not so easy to implement in assembly and other languages
When I am talking about linking, I am describing the combining of “object files”
(which have the file extension o) and library routines (with the file extension lib)together to create a single application These object files are produced by compiling mul-tiple source code files Together, these source code files make up the entire applicationand may have been written by different people; they even could have been written yearsbefore or could be provided by a third party The primary reason for providing this func-tion is to make things more convenient for application developers (meaning that it willtake only minutes to compile and build the application with the latest changes), and itprotects the application code (once some code is determined to be working correctly, it
is compiled, and the linked files are used from then on)
When I was writing the first two editions of this book, it was quite unusual to havemore than one person developing PIC microcontroller application code The devices had
a very modest amount of program memory, and the processor architecture did not lenditself well to compiled languages with linked object files Over the years since the lastedition of this book, the PIC18 devices have become very popular because they have
up to one million instruction application capabilities and an architecture for which it iseasier to write traditional compilers This has lead to products requiring teams of devel-opers and also has required source code control to ensure that the correct versions ofdifferent functions are used in the final application This trend toward multiple devel-opers is sure to continue and is being taken advantage of in low-end and mid-rangedevices, where compilers capable of producing object files that can be linked in toapplications are becoming more available
Figure 11.1 Modern application code development
takes place over several systems, linking in object files to
produce the final code image that is programmed into the
Released Code
Other Developer Code
Application Circuit
Programmer Interface
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 29CREATING LINKED APPLICATIONS 521
In Fig 11.1 I have drawn a block diagram showing how modern application opment typically takes place A developer, on his or her local machine, is modifying asource file on one aspect of the application When he or she is ready to test it out, he orshe will build the application on the local machine not compiling the code, but he or shemay take source code from other users and compile it into object files to be linked to his
devel-or her code as well as “released” object files and libraries that are available on centralservers Once the “build” is complete, the developer can download the resulting applica-tion into target hardware to test it out This method of development allows multiple devel-opers to work simultaneously and test out their code on local application hardware usingthe latest and best released code available This process is very convenient for developersand ensures that once code is deemed to be “good,” it, along with its object files, can belocated on a central server where it cannot be modified inadvertently, resulting in prob-lems for the developers who will have to try to figure out what went wrong and fix it
To demonstrate how simple it is to link together source files in an application, sider a simple HT Soft PICC (Lite) application that has one subroutine that can belocated in a separate source file The mainline code consists of
and the PrimeCheck subroutine file is
// Primecheck - Moved from One File to a New One
int PrimeCheck(int Value)
{
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 30522 BUILDING AND LINKING
int i, j;
j = 1; // Assume value is prime
for (i = 2; (i < ((Value / 2 ) + 1) && (0 != j); i++)
if (0 == (Value % i)) // If Evenly Divisible by i,
j = 0; // Value is not Prime
return j; // Return 1 if “Value” is Prime
} // end PrimeCheck
These files can be found in the “Linking Test” folder
Now, create a project in MPLAB IDE with a PIC16F84 processor (which is supported
by PICC Lite), and add Compile Test.c and PrimeCheck.c as the two sourcefiles When the MPLAB IDE desktop comes up, you will see that under the file viewwindow, both files are listed under “Source Files.” When this is done, you can displayboth files on the MPLAB IDE desktop and then select “Build All,” which will compileboth files and link them together The only issue that I found in doing this was that Ihad to have the PrimeCheck prototype in “Compile Test.”
After building the files and closing MPLAB IDE, you might want to take a look at thefolder into which you copied the two source code files and put the resulting hex file On my
PC, this folder now contains 23 different objects when I would have thought that there shouldonly be 6 (with the 6 being the two source files and their o object files, the hex file, and
a cod or coff file that would be used by the MPLAB IDE simulator or MPLAB ICDfor debugging the application) The additional 17 files are used by the compiler and the linker
to produce the application The files that you should be concerned with are
1 The source files (.c)
2 The object files (.o)
3 The compiler listing files (.lst), which provide you with basic information regardingthe results of the compilation
4 The hex file (.hex)
5 The debugger file (.cod or coff), which is used to allow source-code-level ulation and debugging
sim-6 The linker file (.lkr), which may have been brought into the build folder to modifyhow the code is implemented
7 The application map file (.map), which outlines how the application uses data andprogram memory
All the other files can be ignored
The linker file will be explained in more detail in the next section, but I wanted topoint out its existence and its function, which is to specify where code and variablescan be placed Each location for code or memory is labeled, and you can specify dif-ferent functions to be placed in specific locations in the PIC microcontroller
The application map file is a very complex file that lists how the application was ized and will be stored in memory To truly understand how the application is laid out,you will need to cross-reference this file to the listing files because the listing files haveSimpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 31organ-CREATING LINKED APPLICATIONS 523
the sizes needed by the different object files, and you can see how they were located inthe final hex file using the map file For the most part, you won’t care how the code
is placed in the PIC microcontroller, but as you develop more complex applications anduse different tools such as “bootloaders,” you will be taking on a greater interest in howthe application code is stored
When you are implementing C applications, you are going to have to identify globalvariables that are used in the different source files properly This is actually quite simple;
I would recommend that all global variables be declared in the same file as the cation “main” is located In the other files, these declarations can be copied, but afterthe file type, put in the directive extern like
appli-int extern GlobalVariable;
When the extern is used, the variable cannot be initialized as part of the declaration.This can be done only in the primary variable declaration
This overview is actually all you have to do to implement linked PICC and PIC18applications Creating linked applications for code written in other languages is quite
a bit of work, with the need to define code segments and data segments for variablesand ensure that the code is either relocatable (which means that it can be placed any-where in memory) or that you specify explicitly where it is going to be located Thiswork is not terribly difficult, but it is very easy to make a mistake in
As you start working with more complex applications, I would suggest that you imize the amount of assembler code that you create and work exclusively in PICC orPIC18, with any necessary assembly language being embedded in C source files
min-.lkr FILES
The linker script (PIC MCU part number.lkr) describes how the different memories(program memory, file registers, and data EEPROM) are set up in a specific PIC micro-controller Memory areas (known as CODEPAGE or DATABANK) within the architec-ture can be PROTECTED, preventing the linker from placing code or variables at theselocations As you become more familiar with linked-code development on the PICmicrocontroller and you are looking to develop more and more complex applications,you will want to customize the linker files so that you can specify explicitly how appli-cations are loaded into the target PIC microcontroller
A sample lkr file for the PIC16F84 is
// Sample linker command file for 16F84
// $Id: 16f84.lkr,v 1.4.16.1 2005/11/30 15:15:29 curtiss Exp $
LIBPATH
CODEPAGE NAME=vectors START=0x0 END=0x4 PROTECTED
CODEPAGE NAME=page START=0x5 END=0x3FF
CODEPAGE NAME=.idlocs START=0x2000 END=0x2003 PROTECTED
CODEPAGE NAME=.config START=0x2007 END=0x2007 PROTECTED
CODEPAGE NAME=eedata START=0x2100 END=0x213F PROTECTED
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 32524 BUILDING AND LINKING
DATABANK NAME=sfr0 START=0x0 END=0xB PROTECTED
DATABANK NAME=sfr1 START=0x80 END=0x8B PROTECTED
DATABANK NAME=gprs START=0xC END=0x4F
SECTION NAME=STARTUP ROM=vectors // Reset and interrupt vectorsSECTION NAME=PROG ROM=page // ROM code space
SECTION NAME=IDLOCS ROM=.idlocs // ID locations
SECTION NAME=DEEPROM ROM=eedata // Data EEPROM
This file notes that the reset vectors instruction area (the four locations before the rupt vector) are PROTECTED and cannot have user-developed code stored in them.Next, the program memory that the application can reside in is specified (0x5 to 0x3FF).Following this, the IDLOCS configuration register addresses are protected as is theEEPROM data area For variable storage, the DATABANK statements outline the loca-tions of the special function registers (which cannot be used for variables), along withthe file registers (gprs) that are used for variables
inter-The PIC16F84 cannot show an important aspect of the lkr file, and that is how codepages and register banks are handled by the linker In other devices, such as thePIC16C63, which has two register banks and two code pages, there are additional state-ments to indicate their presence:
// Sample linker command file for 16C63
// $Id: 16c63.lkr,v 1.3.16.1 2005/11/30 15:15:28 curtiss Exp $
LIBPATH
CODEPAGE NAME=vectors START=0x0 END=0x4 PROTECTED
CODEPAGE NAME=page0 START=0x5 END=0x7FF
CODEPAGE NAME=page1 START=0x800 END=0xFFF
CODEPAGE NAME=.idlocs START=0x2000 END=0x2003 PROTECTED
CODEPAGE NAME=.config START=0x2007 END=0x2007 PROTECTED
DATABANK NAME=sfr0 START=0x0 END=0x1F PROTECTED
DATABANK NAME=sfr1 START=0x80 END=0x9F PROTECTED
DATABANK NAME=gpr0 START=0x20 END=0x7F
DATABANK NAME=gpr1 START=0xA0 END=0xFF
SECTION NAME=STARTUP ROM=vectors // Reset and interrupt vectorsSECTION NAME=PROG1 ROM=page0 // ROM code space - page0SECTION NAME=PROG2 ROM=page1 // ROM code space - page1SECTION NAME=IDLOCS ROM=.idlocs // ID locations
It is important to note that in low-end and mid-range devices, the linker does not allowfunctions to go over page boundaries, so the available areas are specified separately (asshown in the preceding example)
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 33CREATING LINKED APPLICATIONS 525
The PIC18 architecture is a different case because the program memory space is flatand can be accessed anywhere using the goto and call instructions This results in
a simpler lkr file like the one for the PIC18F87J50 (which I chose because it has a
128 kB Flash program memory space):
// $Id: 18f87j50i.lkr,v 1.1.2.1 2006/09/27 23:12:31 curtiss Exp $// File: 18f87j50i.lkr
// Sample ICD2 linker script for the PIC18F87J50 processor
// Not intended for use with MPLAB C18 For C18 projects,
// use the linker scripts provided with that product
ACCESSBANK NAME=accessram START=0x0 END=0x5F
DATABANK NAME=gpr0 START=0x60 END=0xFF
DATABANK NAME=gpr1 START=0x100 END=0x1FF
DATABANK NAME=gpr2 START=0x200 END=0x2FF
DATABANK NAME=gpr3 START=0x300 END=0x3FF
DATABANK NAME=gpr4 START=0x400 END=0x4FF
DATABANK NAME=gpr5 START=0x500 END=0x5FF
DATABANK NAME=gpr6 START=0x600 END=0x6FF
DATABANK NAME=gpr7 START=0x700 END=0x7FF
DATABANK NAME=gpr8 START=0x800 END=0x8FF
DATABANK NAME=gpr9 START=0x900 END=0x9FF
DATABANK NAME=gpr10 START=0xA00 END=0xAFF
DATABANK NAME=gpr11 START=0xB00 END=0xBFF
DATABANK NAME=gpr12 START=0xC00 END=0xCFF
DATABANK NAME=gpr13 START=0xD00 END=0xDFF
DATABANK NAME=gpr14 START=0xE00 END=0xEF3
DATABANK NAME=dbgspr START=0xEF4 END=0xEFF PROTECTEDDATABANK NAME=gpr15 START=0xF00 END=0xF3F
DATABANK NAME=sfr15 START=0xF40 END=0xF5F PROTECTEDACCESSBANK NAME=accesssfr START=0xF60 END=0xFFF PROTECTED
Note that in the PIC18F87J50 lkr file there is a single code page specificationthroughout the entire memory map, but there are multiple file register databanks Theflat architecture of the PIC18 allows for seamless placement of code, but not of data.Also in the PIC18 lkr file, you will see that the access bank is incorporated as well.The biggest problem I have with working with the lkr files is discovering wherethey are For the standard MPLAB IDE linker files [which can be used for PICC (Lite)applications], they are in
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 34526 BUILDING AND LINKING
C:\Program Files\Microchip\MPASM Suite\LKR
Microchip PIC18 linker files are found in
C:\MCC18\lkr
MPLIB LIBRARIAN
When you work with a compiled language, you generally are given a set of libraries thatare linked into the application These libraries contain a number of object (.o) files thatcan be included in an application when needed In the appendices I have listed thelibrary functions that are available in the standard C programming language, as well asPIC18’s extensions Each of these functions is included in the library, but they areincluded in the application only when they are required Libraries are extremely usefulprogramming constructs that will make your application development quite a bit easier
To create your own libraries, create a project with the files that you want to include
in the library and then click on “Project\Build Options\Project” followed by selectingthe “MPASM/C17/C18 Suite” tab and then clicking on the “Build library target (invokeMPLIB)” radio button The next time you build your project, a library will be pro-duced The MPLIB librarian also can be invoked from the MS DOS prompt commandline—this interface is useful when you have an existing library and you want to change
or delete object files in that library The only thing that MPLIB librarian doesn’t do that
I would have liked is to automatically create a header (.h) file that would provide theprototypes of all the functions located inside the library
There are several reasons for using the MPLIB librarian for your PIC18 applications.They include
1 Helping to control the source code used in development builds With certain objectfiles only available within a standard library, you can guarantee that the applicationwill not be built with invalid code sources
2 The speed of the build will be better than in the case where you are bringing in tiple object files This is especially true if the object files are found in various loca-tions throughout your local area network
mul-3 The final size of the application code could be smaller Libraries add a level of ligence to the application build by including only the object files that are being called
intel-by the various functions within the application Without a library, unused functionswould be linked into the application along with the ones that are used
4 If you have produced a product that can be programmed by third parties The ation of a custom library would allow the users to access only the functions that youwant them to access, and any intellectual property associated with the functionswould be hidden from view
cre-After creating the custom libraries, you can add them for linking in your application
by right clicking on the “Library Files” heading in MPLAB IDE’s file view window
As with other files, the custom library could be in a folder outside the project files.Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 35on what kind of application was being run on the PC and the system requirements ofthe code The loading and execution of an application are a function that has been avail-able to many different microcontroller architectures for years but is something that hasbecome available only recently to PIC®microcontrollers.
The ability to load an application from some source, save it in memory, and then cute the code requires microcontroller program memory that can be changed by an exe-cuting program PIC17 microcontrollers with external memory had this capability, butthe systems designed around them were quite complex—what was needed was a PICmicrocontroller “bootloader” application that had the ability to update its own internalFlash program memory to become available so that this function could be implemented
exe-in applications, elimexe-inatexe-ing the need for an ICD connector or pullexe-ing out the PIC controller to update the application code To summarize the important feature of a boot-loader; it is a program that will allow a new application to be installed without requiringany special hardware
micro-Bootloaders may seem to be an unnecessary requirement because of the availability
of MPLAB ICD, which performs many of the same capabilities as this type of tool, butthey are still useful because there are situations where MPLAB ICD is not practical touse or is unavailable If you had a problem with a robot and were at a competition, it prob-ably would be much easier for you to connect a USB or serial cable between the robotand a laptop to download a new application (in the case where the competition calls foryou to come up with a custom application for your robot) Other cases where a bootloader
is preferable over MPLAB ICD is if the application is being used by someone who isn’t
Copyright © 2008, 2002, 1997 by The McGraw-Hill Companies, Inc Click here for terms of use
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 36528 BOOTLOADERS
familiar with MPLAB ICD, or it is used in a hostile environment where there is danger
of damage to the product or MPLAB ICD, and a simple, rugged host computer is thebest choice for updating the application Personally, a couple of years ago I would havedismissed the usefulness of bootloaders in applications, but I have seen a number of caseswhere they are extremely useful and more effective than other methods of updating anapplication
Bootloader Requirements
Bootloaders have a basic set of requirements that are needed to perform their tions When reviewing these requirements, remember that they are high level and notmeant to direct you in a specific direction; a good example of this is PIC18C801chips that have a bootloader function built into the chip that allows an external par-allel Flash chip to be programmed via USB with no other code running I’m notingthis because in many of the smaller pin-out devices, you may see some advantages toimplementing a bootloader, but the traditional resources that are available in chips such
func-as the PIC16F877A (for which I demonstrate a bootloader later in this chapter) arenot available, which may seem to eliminate a bootloader from being considered forthe application When working with the PIC microcontroller, many times when youare considering implementing a bootloader, you will discover that there are commonrequirements between the bootloader and providing the interface hooks for usingMPLAB ICD
The six basic requirements of a bootloader are
1 The application can communicate with the host system
2 The host system has a mechanism for sending data to the PIC
3 The PIC microcontroller must be able to write to its own memory
4 The application code can execute without modification (except for reduced size forbootloader code)
5 If an application is loaded, the system should boot it automatically
6 On startup, the system can be commanded to go into boot mode to allow the loading of a new application
down-Some of these requirements probably will seem obvious—such as the need for theapplication (both hardware and software) to be able to communicate with the hostsystem Despite being obvious, this capability is not something that will come auto-matically; along with making sure that input-output (I/O) pins are available for thebootloader, you must make sure that the schematic and the printed circuit board (PCB)have provisions for connectors and interface chips such as RS-232 translators and thesoftware that supports this interface For Logitech Harmony remote controls, boot-loader functionality is implemented three ways: through MPLAB ICD, through theremote’s USB connection, and using the NRZ UART interface built into the PIC18 Each
of these interfaces is used in different aspects of development, manufacturing, andremote setup
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 37BOOTLOADER REQUIREMENTS 529
Just as the system needs to be able to communicate with the host, the host must beable to communicate with the system Again, this is a system requirement, meaningthat there must be hardware as well as software to take advantage of the bootloaderfunctionality built into the system With the trend toward simpler systems using PCswith more complex, proprietary, and licensed interfaces, this is becoming more andmore of a problem As will be shown later in this chapter, I will tend to stick with asimple RS-232-based (UART) bootloader using a basic terminal emulator program on
my PC, but this is a slow method of passing new application code to the PIC controller, and you might want to implement a USB-based bootloader, although the code
micro-is significantly more complex and will require a very good understanding of USBWindows device model programming as well as PC application programming Whenyou are first starting out with a bootloader, use a simple interface (such as the RS-232bootloader shown later in this chapter) and develop the right technology for your appli-cation from there
While MPLAB ICD capabilities are becoming more prevalent throughout the PICmicrocontroller line card, there still are not that many part numbers that can write totheir own program memory This limits the devices that you can use in your applicationand makes it more difficult to select the part number that is best for your application.Unfortunately, there isn’t a search parameter on Microchip’s Web site that allows you
to get a fast list of PIC microcontrollers that would support bootloaders, so you willhave to go through the list of part numbers that have the basic I/O features that you arelooking for and then go through each datasheet doing a search on the EEPGM bit ofEECON1—this bit is used to select between data EEPROM and Flash program memoryfor reading and burning in new values There also should be an EEDATH register that
is used for transferring the high byte’s data to and from program memory Flash.When you create your bootloader code, it must be done with an eye toward notimpeding execution of the actual application code In the bootloader below I havemoved as much of the code as possible to the “top” of the PIC microcontroller’smemory and made sure that it does not overwrite the interrupt vector (address0x0004) You also should keep MPLAB ICD in the back of your mind—you mighthave an application in which the bootloader is going to be implemented in the field,but you may want to use MPLAB ICD for debugging both the initial application codeand the bootloader; to avoid any problems with MPLAB ICD, you should keep thelast 256 addresses free
In some cases it will be impossible to avoid placing the bootloader over interrupts
A good example of this is a bootloader that uses the USB port built into the PIC controller In this case you will have to do two things The first is to ensure that therewill be no application code addressed in this area, and the second is to write onlyapplications that do not use interrupts This does limit the applications somewhat,and you will have to decide whether or not the advantages make this course of actionappropriate
micro-Keeping assembly application code from being placed in this area is easy to do usingthe org directives For compiled code, this will require modifying the device lkr file;below I have listed the modified 18f4450i.lkr file that could be used for building
an application that will be loaded by a bootloader
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 38530 BOOTLOADERS
// $Id: 18f4450i.lkr,v 1.1.2.2 2006/03/03 23:33:13 curtiss Exp $// File: 18f4450i.lkr
// Sample ICD2 linker script for the PIC18F4450 processor
// Not intended for use with MPLAB C18 For C18 projects,
// use the linker scripts provided with that product
LIBPATH
CODEPAGE NAME=vectors START=0x0 END=0x7 PROTECTEDCODEPAGE NAME=bootloader1 START=0x8 END=0x1FF PROTECTEDCODEPAGE NAME=page START=0x200 END=0x2FFF
CODEPAGE NAME=bootloader2 START=0x3000 END=0x3DBF PROTECTEDCODEPAGE NAME=debug START=0x3DC0 END=0x3FFF PROTECTEDCODEPAGE NAME=idlocs START=0x200000 END=0x200007 PROTECTEDCODEPAGE NAME=config START=0x300000 END=0x30000D PROTECTEDCODEPAGE NAME=devid START=0x3FFFFE END=0x3FFFFF PROTECTED
ACCESSBANK NAME=accessram START=0x0 END=0x5F
DATABANK NAME=gpr0 START=0x60 END=0xFF
DATABANK NAME=gpr1 START=0x100 END=0x1EF
DATABANK NAME=blpr START=0x1D0 END=0x1F3 PROTECTEDDATABANK NAME=dbgspr START=0x1F4 END=0x1FF PROTECTEDDATABANK NAME=usb4 START=0x400 END=0x4FF PROTECTEDACCESSBANK NAME=accesssfr START=0xF60 END=0xFFF PROTECTED
The modifications to the lkr file include changing the vectors code page to end
at 0x7 instead of 0x29 and adding the bootloader1 and bootloader2 code pages,which are off-limits to the application code, along with blpr, which is used for theregisters involved with the bootloader The code produced by the linker should avoidthese areas, and if there are insufficient resources (program memory or registers) to sup-port the application and the bootloader, then you will receive an error during linking The final two requirements are really use cases: If there is no application loaded
in, then the system should go into a state where it is ready to accept an application,and if there is one already, it can poll an external control that indicates whether or notthere is a new application to be loaded For a basic system, this control is simply abit that is either high or low to indicate that the bootloader should go into applicationload mode
Trang 39MID-RANGE BOOTLOADERS 531
the serial port or a synchronous protocol of some kind Despite this limitation, adding
a bootloader as part of your application is something that you always should keep inthe back of your mind, and even if you don’t implement it, you can keep this function-ality in your hip pocket for inclusion at a later point in time
The model that I use for mid-range bootloaders is shown in Fig 12.1, and in it I placethe majority of the bootloader code at the “top” of program memory but also use thebottom four instructions These four instructions mean that the bootloader will have tosave the four instructions provided by the loaded application and be able to execute themfrom elsewhere in the application The code with these instructions is at StartVector:
StartVector: ; Otherwise, Execute the existing programbcf STATUS, RP0 ; Make sure Bank Addresses == 0
bcf STATUS, RP1bcf STATUS, IRPclrf PCLATH ; Jump to the starting address
ProgramStart: ; Put the first 4 instructions here
Bootloader Code Placement
0 × 0000
0 × 1FFF
Code Storage in PIC MCU
Application Code Storage
Main Bootloader Execution Code
Bootloader Reset Bootloader Reset Application Reset
0 × 0004
Application Code
Main Bootloader Execution Code Application Reset Application Codev
Figure 12.1 A mid-range bootloader must be designed to have minimal
impact on the application code loaded into the system.
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 40532 BOOTLOADERS
and there is no request to load in a new one, execution jumps to StartVector, and the pageand bank bits are reset Then the four original instructions are allowed to execute.Note that there is a final goto 0x0004 | ($ & 0x1800) instruction that executes
if in the first four instructions execution does not branch to some other location
As indicated earlier, as this is being written, there are no USB-equipped mid-rangePIC microcontroller part numbers that can support a bootloader through the USB If youcannot use the UART port, then there are a number of other interfaces that can be used,including
1 I2C, with the PIC microcontroller as a slave device
2 SPI, again with the PIC microcontroller as a slave device
3 The parallel slave port (PSP)
4 A proprietary “bit banging” synchronous protocol
Of these four options, the one that probably would be most reasonable to use with a
PC is to the PSP connected to the parallel (printer) port When the printer port is figured for a basic dot matrix printer (such as the EPSON FX80), the data is strobed outcontinuously with just polling for a “busy” pin, which could be used to synchronize thetransfer of the application file to the PIC microcontroller (waiting for the PIC to pro-gram the data into its program memory)
con-The need for synchronizing the write of program memory with the new data coming in
is a very important point when implementing a bootloader in a PIC microcontroller Youprobably will find that the program memory write will be slower than the data rate that youwould like to use, and even more important, when program memory is being written, thePIC microcontroller’s processor stops executing, meaning that any incoming data cannot
be processed, leading to the possibility of overwrites of the incoming data buffer Youalways should make sure that you have implemented some kind of handshaking protocolbetween your bootloader-equipped system and the host application downloader
SAMPLE BOOTLOADER CODE
Implementing a generic bootloader in the PIC microcontroller was surprisingly cult, although I am very pleased with the final functionality of the result A big part ofthe issue was designing the bootloader to work within the confines of the PIC16F877Amicrocontroller and with its Flash program memory burning algorithms; I was expect-ing that I would be able to write the code in 256 instructions, but it turned out that Ineeded about twice that to implement the function The resulting application does workwell and provides a method of downloading an application over a single 9,600-bpsserial link using a basic Terminal emulator
diffi-The development hardware for the bootloader that I used was a PIC16F877A ning at 4 MHz with the serial port interface wired to an MAX232 and a button placed
run-at RC1 The circuit was the same base circuit I used to develop the BASIC87 tion (but using a PIC16F877A instead of a PIC16F877) The difference between the twodevices made quite a bit of difference in the code because the PIC16F877A requires fourinstructions to be loaded before programming can commence
applica-Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com