MICROCHIP SITES
LATEST NEWS
Omniscient Code Generation:  whole-progam compilation technology


Frequently Asked Questions

About HI-TECH C® (with answers!)

You may also want to check out our on-line discussion forums.

View our MPLAB® integration page to help with the integration of MPLAB with our PICC/PICC-Lite/PICC-18 compilers. These forums allow you to post and answer questions, or just browse what other people have asked or replied. If none of these questions are helpful, you may send email to support@htsoft.com.

  22   How do I create an array of pointers in ROM?
  25   Why dont the %f or %ld placeholders in printf work?
  26   How can I speed up my interrupt service routine?
  29   What does the PICC STD error, something like "cant find xxxx words/bytes for psect in segment BANK0", mean?
  30   Why do I get an "Arithmetic overflow" message?
  34   What on Earth is a fixup error?
  41   Why does #asm/endasm inline assembly near an if statement ends up in the wrong place?
  47   What symbol lengths are supported in HI-TECH C?
  48   Can I define a function that will be expanded inline?
  49   How do I use interrupts on a mid-range PIC device?
  58   How do I access bits in a RAM variable?
  61   How do I load the OSCCAL value for PIC devices?
  63   How do I program the PIC's ID Locations?
  69   How do I place data in EEPROM?
  76   How do I ensure declarations are consistent across files?
  81   How do I update my compiler?
  83   What does the error, something like "can't find * words for psect" mean?
  86   Do I need to do anything to debug with the MPLAB-ICDs?
  89   How do I position code or variables at a specific location?
  92   What does printf output to?
  95   How do I create a new project in MPLAB IDE which uses a HI-TECH C compiler?
  98   What is HPA (High Priority Access)?
  103   How do I fill unused program memory with a known value?
  106   How do I access variables in PIC18 devices' external program space?
  109   Can I install two or more versions of the same compiler?
  119   Where can I find the latest MPLAB IDE toolsuite plugin?
  125   Why do floating-point variables in MPLAB IDE have the wrong value?
  181   What does the error "(1187) invalid activation request" mean?
  191   Is there a fix for this bug?
  231   Why are some of my variables missing from MPLAB IDE?
  241   Why do I get "(924) missing argument to -O option" when compiling under MPLAB IDE?
  261   What's with all these PRO, Standard & Lite modes, compiler types, evaluation and full versions?
  271   Why do my variables in the MPLAB IDE Watch view have the wrong value?
  281   Do you support this device?
  291   What does the error, something like "Cant generate code" mean?
  301   What does the error "activation limit reached" mean when I try to activate a compiler?
  311   How can I reserve memory and prevent it be used by the compiler?
  321   Do you support the PIC17 devices?
  331   Can HI-TECH C check for MISRA compliance?
  341   What are the restrictions in Lite mode?
  351   How can I change license details of a compiler?
  361   What does the error "invalid version number" mean when I try to activate a compiler?
  371   What does the error "invalid activation response" mean when I try to activate off-line?
  381   How many computers can I install the compiler on?
  391   Does HI-TECH C support any binary object files or libraries in formats other than HI-TECH's?
  401   How can I use the TO and PD bits to determine the cause of reset on PIC devices?
  411   Are administrator rights needs to use the compiler in MPLAB IDE?
  421   What does the error "no file arguments" mean?
  431   Why dont checksums or fills work when generating a binary output?
  441   Does the same serial number work with Windows, OS X and Linux compilers?
  451   Does the HI-TECH C compiler for PIC18 MCUs support the extended instruction set?
  461   What are the nesting limits of function calls on 8-bit PIC devices?
  471   How can I create a library?
  481   Is there any limit to the size of objects I can define?
  491   How do I interpret the call graph in the assembler list file?
  501   How do I interpret the pointer reference graph in the assembler list file?
  511   Does HI-TECH C support the use of the malloc-style functions?
  521   Where I can find information about compiler messages?
  531   Why don't extended ASCII characters work in 9.70 compilers?
  541   Why don't the line numbers in an error message match the actual line with the problem?
  551   When migrating to OCG what do I need to do to allow C variables to be accessed by assembly code that assumes these variables are in certain banks?
  561   When writing code that is to be portable between OCG and non-OCG compilers how do I define absolute variables that may be used in multiple source files?
  571   Do I need to do anything to source code that contains a #pragma psect directive when porting this code to an OCG compiler?
  581   Do I need to do anything to a project that uses a make file or build script when porting this to an OCG compiler?
  591   Do I need to do anything to a project that includes user-defined libraries when porting this to an OCG compiler?
  601   What do I need to do to assembly code that references a function's auto or parameter block symbol ?a_xxxx or ?_xxxx when porting this code to an OCG compiler?
  611   What do I need to do to assembly code that references 'btemp'-type temporary variables when porting this code to an OCG compiler?
  621   What do I need to do to assembly code that reserves data memory when migrating this code to an OCG compiler?
  631   What does 'No valid installed HI-TECH compiler drivers' when building with MPLAB IDE?
  641   What could cause corrupted variables or code failure when I am using interrupts?
  651   What could cause pins in a port to change from values I assign to them?
  661   What could cause glitches on an output port?
  671   Where can I find the call graph produced by OCG compilers?
  681   Do I need to do anything to C source code that contains a #pragma interrupt_level directive when porting this code to an OCG compiler?
  691   How do I fix errors relating to 'illegal conversion of pointer types' or 'illegal conversion of integer to pointer'?
  701   When should I cast expressions?
  711   What do I need to do to C code that assigns an integer to a pointer when migrating this code to an OCG compiler?
  721   Can I access C pointers from assembly code written for an OCG compiler?
  731   Why don't my interrupts work after the PIC32 device awakes from sleep/idle mode?
  751   What optimizations are present in OCG compilers?
  761   Where can I find the old compiler versions?
  771   What version of the Compilers work with Vista/Windows 7?
  781   How do I register my Compiler on microchipdirect.com?
  791   What does the error "Could not find space xbytes for auto/param block" mean?
  801   How can I create a delay in my program?
  811   Why are SFRs undefined in my assembly code?
  821   What does a can't find space for a swtext psect mean?
  831   How do I install Mac and Linux compilers

Answers:

How do I create an array of pointers in ROM?
If the array is being placed in data memory, this would be because you have put
the "const" qualifier before the "*" in the  array definition, e.g.

const int * aname[10];  // an array (in RAM) of pointers to ints (in ROM)

This makes the const bind to the type pointed to, rather than to the array
itself. Put the const keyword immediately before the array name, for example: 

int * const aname[10] = { ... }; // an array (in ROM) of pointers to ints (in RAM)

int (* const fname[10])(void); // an array (in ROM) of pointers to functions

Remember that if the object is const, you will need to provide initial values when
you define the object.

In some situations you may want to have a const array pointing to const data, in
which case you would have 'const' both before and after the '*', e.g.

// an array (in ROM) of pointers to chars (also in ROM)
const char * const array[] = { "string 1", "string 2" };

The rule is: Anything to the left of the star in a pointer definition refers to what the
pointer accesses indirectly; anything to the right refers to the pointer variable itself.
Back to top

Why dont the %f or %ld placeholders in printf work?

If you are using an older STD compiler (not the Standard operating mode of an
OCG compiler) and you have code similar to:

printf("number=%f\n");

but the output is 'number=f', you need to enable printing for floating-point values.

You must use the command -LF, or set the Printf field in the Global tab of the
MPLAB IDE Build Options dialog to Floats+longs. This will link in a much larger
version of the printf function, but one which can print floating-point values as well
as plain ints.

The same is true for printing long int values: The -Ll option, or specifying Long ints
in the MPLAB IDE options, must be selected to print long int values.

This action is not required if you are using any compiler that uses OCG.
Back to top

How can I speed up my interrupt service routine?

OCG compilers handle interrupt routines (ISRs) better than non-OCG compilers.
In either case, however, you can improve the speed of an ISR by keeping the code
contained in the ISR to a minimum. The more registers used by the ISR code, the
more context save and restoration will be required and added by the compiler.
Consider moving complex tasks outside the ISR and having the ISR set a flag to
indicate to main-line code that the task is required.

If you are using a non-OCG compiler, avoid calling other functions from the ISR,
or if you must, ensure that you only call functions that are defined in the
same source module and before the ISR function. This ensures the compiler will know
exactly what registers are used by the function. OCG compiler will always know the
exact register usage, regardless of the program structure.
Back to top

What does the PICC STD error, something like "cant find xxxx words/bytes for psect in segment BANK0", mean?

See also the general discussion of errors with memory allocation performed by the linker
in the FAQ:

I get an error something like "cant find xxxx words/bytes for psect in segment yyyy"

This FAQ deals specifically with the PICC STD compiler and is not relevant for any other
compiler, in particular, this is not relevant when using an OCG compiler in Standard mode.
With PICC STD compiler there are often messages similar to:

Can't find space for psect rbss_0 in segment BANK0 (error)

It means that you have run out of space in RAM bank 0. The error might also mention
the class COMBANK, depending on the circumstances. The common memory is shared
with bank 0.

The solution is most likely that some variables need to be moved into banks 1, 2 or 3.
You do this by prefixing the variable declarations with a qualifier like bank1, e.g.

bank1 int fred;

Naturally you should group variables often accessed together in the same
bank. You can't use the bank qualifiers with auto variables, functions or
parameters, but it can be used with static variables. You can also use them with bit
variables.

Beware of pointers, e.g.

bank2 char * p;

is a pointer to a char in bank 2, but the pointer itself is still in bank 0.
This declaration

bank2 char * bank1 p;

is a pointer to a char in bank 2, but the pointer is located in bank 1.
 
Memory allocation and pointer typing is automatically configured in any compiler
using OCG, e.g. a compiler operating in PRO, Standard or Lite mode. This FAQ is not
relevant for these compilers.
Back to top

Why do I get an "Arithmetic overflow" message?

There are many reasons why this warning may be produced when compiling.
Here are a few examples that might help you understand why it occurs in your
code.

Example 1:

If I assign 0xFFFF to an integer, I get the message "arithmetic overflow in
constant expression. Why doesn't it just treat it as -1?

As an int, this variable can only assume values of -32768 thru to 32767.
The value 0xFFFF is equal to 65535, and is thus too big. If you really don't
want signed values, use an unsigned int, or use -1, or use ~0.

In general, if you want a value that has all bits set, and you don't want to
be specific about how many bits that is, ~0 is good. e.g.

        OnLimit = ~0;

will assign a value to the variable that has all bits set, for a 16 bit int this
will be 0xFFFF (or -1).

A macro like:

#define ALL_BITS_SET    (~0)

can be useful too.


Example 2:

What about something like:

#define XTAL 8000000
#define BEEP_FREQ 3200
#define BEEP_TIME XTAL/(64*BEEP_FREQ)-1   // = 38.0625

this also gives me "arithmetic overflow" when I assign BEEP_TIME to an
unsigned char. The final value easily fits a char so what's going on?

If you are working with a compiler that uses 16-bit ints and 32-bit longs,
you need to ensure that long arithmetic is used for the whole expression.
8000000 is by default a long number, but 3200 and 64 aren't, so 64*3200
is evaluated in int length, and overflows. Use an 'L' suffix to force long
arithmetic in an expression, e.g.

#define BEEP_TIME XTAL/(64L*BEEP_FREQ)-1   // = 38.0625

Note the 'L' appended to 64 - this makes it a long number, and the
evaluation of 64L*3200 will be done in 32-bit length.
Back to top

What on Earth is a fixup error?

There are a number of fixup-related error messages that all roughly mean the
same thing. They are all produced by the linker application and have the form:

(476)  fixup overflow referencing %s %s (location 0x%lX (0x%lX+%d), size %d, value 0x%lX)
(477)  fixup overflow in expression (location 0x%lX (0x%lX+%d), size %d, value 0x%lX)
(1267) fixup overflow referencing %s %s (0x%lX) into %d byte%s at address 0x%lX (%s%s%s %d/0x%X)
(1268) fixup overflow storing 0x%lX in %d byte%s at address 0x%lX (%s%s%s %d/0x%X)
(1356) fixup overflow referencing %s %s (0x%lX) into %d byte%s at 0x%lX/0x%X -> 0x%lX (%s%s%s %d/0x%X)
(1357) fixup overflow storing 0x%lX in %d byte%s at 0x%lX/0x%X -> 0x%lX (%s%s%s %d/0x%X)

where the printf-style placeholders will be replaced with names and values, and
the numbers in brackets are the error numbers which uniquely identify the message.
The latter two messages are actually replacements for the others. They contain
additional information to help you understand what is happening. You will see the
other messages on earlier versions of the compiler.

Most of the confusion arising as a result of this error message relates to the fact that
most people do not know what the process of fixup is. That makes it difficult to
understand the error. So what is fixup?

When you reference a symbol in either C or assembly code, the generated
opcodes ultimately produced by the assembler cannot be completed because at
that time the addresses of the symbols are not known. The binary opcodes are
output with zeros in the opcode value where the symbol address would normally
be located. Other information is output to tell the linker how to adjust the opcodes
once the addresses of the symbols are determined. The process of adjusting the
opcodes with the actual numeric addresses is called fixup.

Now consider the case when the symbol address should take up, say, 8 bits in the
opcode, but the linker determines the address to be substituted is a value like 0x110,
which is large than 8 bits in size. In this case, the fixup process has overflowed
and this is exactly what the error indicates.

So what causes this? In rough order of likelihood, this error is generated by:

* Hand-written assembly code that did not include the required address masking
* Incorrect bank qualifiers and pointers when using a PICC STD compiler
    - This is not relevant when using any OCG compiler
* Functions or statements (e.g. switch statements) that are too big
* Incorrect linker options defined by the programmer
* A bug in the code generator application

In order to determine the cause, you need to find out the assembly instruction that
triggered the error. If you received error messages 1356 or 1357, then the job is easy.
Depending on the exact cause, the file and line number information produced in the
error may be valid and you can find the offending C code. However, even if this is
the case, remember the error relates to an assembly instruction and to look at that
in detail you will probably want to look at the assembly listing file. Assume we get the
following message.

main.c: 11: (1356) fixup overflow referencing psect nvBANK2 (0x110) into 1 byte...
        ...at 0xFDA/0x2 -> 0x7ED (main.obj 30/0x8)

Open the list file main.lst and look for address 0x7ED. If you are not sure where the
addresses are located, read the assembler section in the manual on understanding
the list file. Once you can see the assembly at fault, you can determine if this was
something written by hand or generated by the compiler and the possible cause.

The other messages are produced by older compilers. The address of the instruction
in the list file is also given in these messages, but note that you may need to divide
this address by 2 manually. This is the case when compiling for Baseline, mid-range
or dsPIC devices. Note also that if you are using a non-OCG compiler, there will be
more than one assembly list file generated for multi-source projects. Check the name
of the .obj file referenced in the error as to which file to examine.

If writing assembly code by hand, check the device datasheet to determine the exact
size of each instruction operand. When using symbols as operands, ensure that the
address has been masked, if required. Often upper bits of an address relate to a
bank or page number and the instruction operand is an offset into these banks or pages.

Here what you should NOT do in PIC18 assembly, for example:

movwf  _output

Here is better code:

movlb  (_output >> 8)  ;select the bank of _output
movwf  (_output)&0ffh  ;mask out bank selection bits in address

If code sequences are too big, the goto or jump instruction can become out of range.
This can trigger a fixup error. If psects are moved, then assumptions the compiler made
may no longer be valid and fixup error may result. For example if a psect was assumed
to be located in bank 0 memory was moved to bank 2, then a fixup error might result
(among other things).
Back to top

Why does #asm/endasm inline assembly near an if statement ends up in the wrong place?

The #asm construct is not syntactically part of the C program - it's handled at the
pre-processing level. So if you have something like:

       if(cond) do_stuff();
#asm
;      assembler code here
#endasm

what happens is that the compiler sees the if() and the statement after it, then skips
ahead looking for the corresponding else -- which is absent -- but it doesn't find that
out until after the #asm/endasm block, by which time it has been output -- but as
part of the code conditional on the if() statement.

The solution is to place a dummy statement before the #asm - this terminates the
scan for the else keyword, e.g.

       if(cond) do_stuff();
       /* null statement here */ ;
#asm
;      assembler code here
#endasm

Alternatively, use the asm("") construct -- it is like a C statement, so it interacts correctly
with C control structures.
Back to top

What symbol lengths are supported in HI-TECH C?

HI-TECH C compilers use a default length of 31 significant characters in C symbols
(this is the minimum value permitted by the ANSI standard). This is adequate for
most purposes, but if more characters are needed, the length can be changed.

The -N option, represented by the Identifier length field in the Compiler tab of
MPLAB IDE's Build Options dialog, can be used to change the identifier length to
anywhere between 31 and 255 characters.

This option also controls the length of macro names used by the C preprocessor,
which also have a default length of 31.

The assemblers that are packaged with HI-TECH C have no specific limit on symbol
lengths -- all characters are significant, and the line length is the only limitation
(typically 256 characters or more).

Whatever the length of a symbol, the linker preserves the full name. Symbols
are case-sensitive in all situations.
Back to top

Can I define a function that will be expanded inline?

Currently, no. Inline functions are not an ANSI C feature, but the same functionality
is available by using macros, e.g. here is a "function" defined as a macro to
write a byte to the EEPROM on a 16C84:

  #define EEPROM_WRITE(addr, value) do { \
             while(WR != 0)   /* wait till EEPROM idle */   \
                 continue;     \
             EEADR=(addr);     \
             EEDATA=(value);   \
             do                \
                 GIE = 0;        /* disable interrupts */   \
             while(GIE != 0);    /* make sure it worked */  \
             WREN=1;             /* enable writes */        \
             EECON2=0x55;        /* enter password */       \
             EECON2=0xAA;      \
             WR=1;               /* start write cycle */    \
             GIE = 1;            /* re-enable interrupts */ \
             WREN=0              /* disable writes */       \
  } while (0)

Note the backslashes on the end of each line except the last - these are required
since the macro definition is technically only one line.

Note also the 'do { ... } while (0)' that is wrapped around it - this allows you to use
it just like a function call even around flow-control constructs like 'if'/'else', although
the compiler might complain (depending on the warning level you have selected)
about the "constant conditional" in the outermost 'while' loop control expression.
Unfortunately you can't use this is you want to return a value from your macro.

Beware of side-effects in parameters passed in to macros - because macro expansion
uses textual replacement, this macro to find the larger of two values:

  #define max(a,b) ((a)<(b)?(b):(a))

will expand 'max(y++, x++)' into '((y++)<(x++)?(y++):(x++))', which will cause the
larger of the variables to be incremented twice - a real function call would not have
this effect.

Always put parentheses around every mention of a parameter name within a macro,
and around the whole macro if it returns a value:

/* Note this is an example of what NOT to do */
#define max(a,b) aBack to top

How do I use interrupts on a mid-range PIC device?

Just declare a function qualified with the "interrupt" keyword. The compiler will
place it in the right place, and take care of all register saving and restoring.
Check the manual for more details.

Here's an example of a program for a midrange PIC that uses interrupts;

#include        
 
/*      Interrupt demo for PIC; wait for button press on RB0/INT,
 *      turn on a relay on another port bit for a period of time.
 *      For simplicity here, literal constants are used, usually these
 *      should be calculated with compile-time arithmetic.        */
 
static bit              RELAY @ (unsigned)&PORTB*8+7;   // use this bit to drive relay
static unsigned int     relay_timer;                    // timer value for relay driver

void    
main(void)
{       
        RELAY = 1;              // ensure relay is off before enabling output
        TRISB = 0x3F;           // Port B bits 7 and 6 are output
        T0CS = 0;               // Timer increments on instruction clock
        T0IE = 1;               // Enable interrupt on TMR0 overflow
        INTEDG = 0;             // falling edge trigger the interrupt
        INTE = 1;               // enable the external interrupt
        GIE = 1;                // Global interrupt enable
        for(;;)
                CLRWDT();       // Idly kick the dog
}        

void interrupt
isr(void)                       // Here be interrupt function - the name is
                                // unimportant.
{
        if(T0IF && T0IE) {                 // if timer flag is set & interrupt enabled
                TMR0 -= 250;               // reload the timer - 250uS per interrupt
                T0IF = 0;                  // clear the interrupt flag
                if(relay_timer != 0)       // is the relay timer running?
                        relay_timer--;     // decrement it
                if(relay_timer == 0)       // if it has time out
                        RELAY = 1;         // turn the relay off
                PORTB ^= 0x40;             // toggle a bit to say we're alive
        }
        if(INTF && INTE) {                         // did we see a button press?
                RELAY = 0;                 // turn the relay on
                relay_timer = 4000;        // start the timer - 4000 ticks = 1 second
                INTF = 0;                  // clear the interrupt
        }
}
Back to top

How do I access bits in a RAM variable?

You may be able to do this using some simple macros:

#define  testbit(var, bit)   ((var) & (1 <<(bit)))
#define  setbit(var, bit)    ((var) |= (1 << (bit)))
#define  clrbit(var, bit)    ((var) &= ~(1 << (bit)))

These will read/set/clear the bit-th bit in var.

You can also define a union which contains the byte variable and a structure with
bitfields that maps over the byte variable, e.g.

union both {
       unsigned char byte;
       struct {
           unsigned     bit0:1;
           unsigned     bit1:1;  // etc.
       } bits;
}     var;

Using this definition means you can refer to var.byte or var.bits.bit0 for example. This
type of definition is portable and ANSI compliant.

You can take this a bit further: use a union to map bit "variables" onto an existing byte.
First up, define a structure type with bits in it.

typedef struct {
        unsigned        b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
}       bitv;                                                          


Now given a char variable, e.g.

char    myvar;

define a "variable" to be a single bit in that char like this:

#define mybit   (((bitv *)&myvar)->b0)

Now you can refer to mybit and it will access bit 0 of myvar. You can use this just
like you would use a bit variable defined any other way. The code generated will
be just as good as any other way. Use it as follows:

         if(mybit)
               something();
         mybit = 1;

To streamline the process a little, you can define a helper macro.                                                                 

#define _paste(a,b)     a##b
#define bitof(var,num)  (((bitv *)&(var))->_paste(b,num))
                                                         
Now defining a bit "variable" is done like this:         

#define x4      bitof(myvar, 4)
                               
So now x4 represents bit 4 of myvar.
Back to top

How do I load the OSCCAL value for PIC devices?

With the latest versions of HI-TECH C for the Baseline devices, the oscillator calibration
constant is automatically handled by the compiler-generated runtime startup code.
There are several schemes employed by the devices to load the calibration
constant and the appropriate method is chosen by the compiler.

If you are using a windowed device, the calibration constant must be saved from
the last ROM location before erasing, then reprogrammed after erasing the device.

If you are using an ICE, the retlw instruction will not be present and calling the
_READ_OSCCAL_DATA() macro will not work. This macro will work when running
code on a part.
Back to top

How do I program the PIC's ID Locations?

Some 8-bit PIC devices have locations outside the addressable memory area that
can be used for storing program information, such as an ID number. The __IDLOC
macro can be used to place data into these locations. The macro
is used in a manner similar to:

#include 
__IDLOC(x);

where x is a list of nibbles which are to be positioned in to the ID locations.
Only the lower four bits of each ID location is programmed, so the following:

__IDLOC(15F0);

will attempt to fill four ID locations with the decimal values: 1, 5, 15 and 0.

Some devices will permit programming up to seven bits within each ID location. For
these, and only these, devices the __IDLOC7(a,b,c,d) macro is available and can be
used in a similar way.
Back to top

How do I place data in EEPROM?

The macro __EEPROM_DATA() can be used to place values in the EEPROM. The
macro allows for 8 bytes to be defined, but can be called more than once. For example:

#include 

__EEPROM_DATA(1,2,3,4,5,6,7,8);
__EEPROM_DATA(9,10,11,12,13,14,15,16);

PIC32 devices do not implement EEPROM and so this macro is not relevant in this case.
Back to top

How do I ensure declarations are consistent across files?

If you have a variable (or structure, or whatever) that you want to define in one
source file and access in another source file, you can do that using an extern
declaration. This declaration must match the definition (note the two terms used).

The best way to do this is to define a header file(s) which can hold all the declarations
and which can be included into each source file that needs to access the variable.

Let say you have a volatile int variable called IOstate that must be accessible anywhere
in the program. The file main.c, for example, might define the variable:

volatile int IOstate;   // definition of IOstate

Now, create a header file (say vars.h) and in this file add:

extern volatile int IOstate;  // declaration of IOstate

Note that the declaration must include any qualifiers used in the definition. Now
include this header file into any source file that needs to access this variable:

#include "vars.h"

If vars.h is stored in the same directory as your source files, the above directive will find
it and not require the preprocessor search path to be changed.

You should also include the header file into the source file that actually defines the
variable. HI-TECH C compilers using OCG will detect any mismatch in the declarations
regardless, but in case you are not using one of these compilers, this action will
ensure the compiler can detect and warn regarding any mismatch.

You should never place definitions in a header file, other than defining types (typedefs)
or structure/union tags etc.
Back to top

How do I update my compiler?

If you own a HI-TECH C compiler, you can update it without having to purchase a
new license. Microchip's 12 month maintenance subscription
provides not only web access to new versions and patch level updates, but also
priority technical support for nominated HI-TECH C compilers. The subscription
is called High Priority Access.  When purchasing, you will have two options: High
Priority Access Restart (HPR) and High Priority Access (HPA).

High Priority Access Restart is for customers who do not currently have a
maintenancesubscription for their compiler.

High Priority Access Renewal is offered at a discounted rate and is for customers
who are supported by the maintenance subscription for a compiler and are
'renewing' it for another year. (To be eligible for 'renewal' pricing, customers
must renew their HPA before their current expires.)

High Priority Access subscriptions can be purchased through microchipDIRECT.
After purchase you will be contacted so that your license details can be updated
and you can activate any updates.  For any enquiries, contact
swlicensing@microchip.com

Note that 12 months of High Priority Access is included with the HI-TECH Enterprise
Edition and HI-TECH C PRO compilers.
Back to top

What does the error, something like "can't find * words for psect" mean?

There are a number of memory-related error messages that all roughly mean the
same thing. They are all produced by the linker application and have the form:

(491)   can't find 0x%X words for psect "%s" in segment "%s"
(593)   can't find 0x%X words (0x%x withtotal) for psect "%s" in segment "%s"
(1346)  can't find 0x%X words for psect "%s" in segment "%s" (largest unused contiguous range 0x%lX)
(1347)  can't find 0x%X words (0x%x withtotal) for psect "%s" in segment "%s" (largest unused contiguous range 0x%lX)

where the printf-style placeholders will be replaced with names and values, and
the numbers in brackets are the error numbers which uniquely identify the message.
The latter two messages are actually replacements for the first two. They contain
additional information to help you understand what is happening. You will see the
first two messages on earlier versions of the compiler.

These meaning of the error is simply this: The linker was asked to position a block
of something (what we call a psect) in memory and it could not find a free space
large enough to accommodate it.

So if you have 54 words of memory remaining and you write additional code which
will require another 110 words, obviously you will have exceeded the memory of the
device and this error would be issued. In particular you might see something like:

(1346)  can't find 0x110 words for psect "text32" in segment "CODE" (largest unused contiguous range 0x54)

If that was the end of the story there would not be as much confusion over this error
message as there is, so we need to elaborate this a bit further. Often the question is
asked "I have been developing my code and the memory summary told me I have
200h words free, but I added a couple more lines of code and now am getting this error
message. What's going on?"

The issue is much more complicated that just "This is the total number of words unused,
and this is how many more I need." and it is mostly an issue when compiling for the
8-bit PIC devices.

The trick to all this is: A psect cannot be split. The linker cannot place part of a psect
somewhere and the rest somewhere else.

Consider the case when there might be 200h words free, but this space is fragmented
so that there are 4 areas of free memory, each 50h words in length. Now consider if the
size of the psect that needs to be allocated was 60 words long. Allocating an extra
60 words when there is 200 words free sounds like this shouldn't be a problem,
but if each free space is only 50 words in size, none of them will be large enough to
accommodate the psect and this error message will result, e.g.

(1346)  can't find 0x60 words for psect "text24" in segment "CODE" (largest unused contiguous range 0x50)

What is distracting is that the memory summary and MPLAB IDE memory gauge only
report on the total amounts of memory used, hence the total amounts unused. This
information is still useful, as it roughly indicates how full the device is, but it is of no
use when dealing with complex memory allocation issues.

So how is it possible that there can be four areas of 50h words free? Why wasn't
everything allocated so there was one big free space left? There are a couple of
answers to this question.

* The data and program memory on 8-bit PIC devices (10/12/16/18) are banked or paged.
* You may have allocated functions or variables at absolute addresses.

When a psect is placed in memory it typically cannot be positioned so that some of it
is in one page/bank and some is in another (there are some exceptions). This is usually
to allow generation of much more efficient code. For example if a psect containing
variables was to be placed so that it could exist in two banks, then the bank boundary
could fall right in the middle of a variable. The compiler could not assume that each
variable was entirely located in one bank and bank selection instructions would need to
be issued before accessing each byte in the variable. The code size would dramatically
increase.

The situation is worse on some devices. For example the GP RAM on Mid-range and
Baseline PIC devices is not contiguous -- the special function registers are located
in-between each bank, so it becomes impossible to position large psects.

When absolute variables or functions are defined, they are placed at the address specified
by the program. If these locations fall in the middle of a bank or page, this effectively
splits the bank or page into two smaller ones. The smaller the pages or banks, the harder
it is to find space for all the psects.

In some cases other memory must be reserved. For example if you are using an ICD for
debugging, it requires memory that you could normally use for your code and variables to
be reserved for the debugger code. This memory is subtracted from the available memory
when compiling.

If that is not bad enough, there are also some psects that have special requirements when
it comes to their placement. For example a psect may need to be linked above a certain address,
or it may need to be linked at an address multiple (e.g. word aligned or aligned to the nearest
100h words). This really complicates the situation. It is even possible that you may see an error
message something like this.

(1346)  can't find 0x30 words for psect "strings" in segment "CODE" (largest unused contiguous range 0x50)

which at first glance seems to indicate that the linker is not doing its job properly. Let's look at
this error as an example of how to work out exactly where the problem lies. This is a more
difficult case that will show you many aspects of memory allocation.

What does the error actually tell us? The message indicates that the linker is currently positioning
a psect called strings. This psect is 30h words long and the linker has been asked to position it
in the CODE class.

So what is strings? You might be able to guess, however to find out for sure check the section in
the manual called "Compiler-generated Psects." This will tell you what the psect holds so you will
know to what the error relates. It is pointless looking at you RAM usage if the error indicates you
have run out of program memory. Strings holds characters that form part of string literals and is
stored in the program memory.

The name of the segment (class) is usually self explanatory, however the definition of the class is
made by a linker option. Look at the linker options when doing a verbose build, or check the
Linker command line section at the top of the map file. You will see the option which defines the
class. Let's assume we are using a 16F877 device; it might look something line this:

-ACODE=00h-07FFhx4

which says the CODE class represents memory from 0-7FFh, then from 800h-FFFh, 1000h-17FFh
and finally 1800h-1FFFh, that is, there are four memory pages. This is quite different to a single
memory range from 0-1FFFh, so already we have fragmented memory to work with.

Many psects are allocated to the CODE class and anything that is linked in program memory will
consume memory covered by this class. The map file indicates where psects have been linked as
well as their length and link location. Check the space value to ensure that you are looking at
psects that are linked in program memory, not RAM. Check the manual section on Map files for
full information on how to read the map file.

The map file will also contain a section called UNUSED ADDRESS RANGES which shows the
memory spaces still unused. You might see, for example:

UNUSED ADDRESS RANGES

        Name                Unused              Largest block    Delta

        CODE              007B0-007FF              50               2
                          00800-00804              3
                          01FE6-01FFF              1A

This indicates that there are several ranges still available. The first is the largest and it is the
space that was referenced in the error message when it says "(largest unused contiguous
range 0x50)".  You can see that there are two other free spaces, but these are smaller. For
example there is 1Ah words available in the range 1FE6h-1FFFh. So both the error message
and the map file agree and we can see the exact memory reaming, not just the total reported
in the memory summary or memory gauge.

Typically at this point you might find that the memory is virtually full or that it is badly
fragmented and that the psect cannot be positioned in any of the small gaps remaining.
But that is not the case here. There is one contiguous range of memory, 50h words in length,
but the linker cannot place the strings psect in this memory, even though it only needs
30h words. Why? It's time to turn to the psect itself. How is it linked and are there any special
linking requirements?

For the device in question you will not see any linker option in the map file that seems to
place the strings psect. This means that the psect will be positioned anywhere in the class to
which it belongs, which is the CODE class.

Okay, so lets look at how the psect is defined. In the assembly list file we find the definition
for this psect towards the top of the file.

psect   strings,global,reloc=256,class=CODE,delta=2

Check the manual for the meaning of all the assembler PSECT directive flags, but here we see
strings is a global psect (is part of one big strings psect that is built up from all modules). We
can see the option that actually indicates that strings lives in the CODE class. We can see that
the delta for the psect is 2 (which means that it resides in memory that is word addressed).
But the solution to our problem is the reloc flag, which declares that this psect must be linked
at an address which is a multiple of 256 (100h).

So are there any addresses in the remaining spaces that start on a 100h boundary and which
are at least 30h words long? No!

Okay, so now we know how to determine what the problem is. What can we do about it?

If the problem is excessive program memory use, you need to reduce the size of any psect
that is linked into program memory, such as executable code, const data or strings:

* Ensure the optimizers are enabled
* Use the smallest data types you can to reduce the size of code that accesses these objects
* Use unsigned data types, if possible, as these can sometimes be easier to access
* Avoid mixing types in expressions as that can introduce a lot of unnecessary type conversion

For excessive data memory use, you need to reduce the size of any psect that is linked into
the data memory. These are mainly variables:

* Remember that unless an object is qualified as "const" it is located in data memory. large arrays and the like
  should be ideally placed in program memory if possible as there is more of this memory available.
* Use the smallest data types you can to reduce the storage requirements of these objects
* Look at using auto variables rather than globals, if possible, so that variable might be able to share storage
* Use pointers to large objects rather than the objects themselves if they are passed to functions as arguments

If the problem is that the memory is fragmented into many small free ranges:

* Do not define absolute variables or functions
  - if you must, ensure that are placed at the end of a bank or page
* Split large psects these into smaller ones
  - If the psect holds the code associated with a function, split the function into two; reduce
     array or structure sizes, where possible
Back to top

Do I need to do anything to debug with the MPLAB-ICDs?

If you are using the HI-TECH Universal toolsuite, make sure the Debugger
field in the Linker tab of the Build Options dialog is set to Auto. With this setting,
the compiler's debugger option will reflect the settings you make in
MPLAB IDE's Select Tool option, under the Debugger menu. There is nothing else
that you need do.

You can override this by change the setting, but do so with caution. If the ICD is
being used as a debugger, the compiler must reserve memory locations that your
program may otherwise use. There may also be other ICD requirements that need to
be met by the compiler, such as shadow register usage or NOP instructions that
need to be used.

Back to top

How do I position code or variables at a specific location?

There are two ways this might possibly be done.

1) Making the variable or function absolute
2) Placing the variable or function in a custom psect and linking it to the desired location

Version 9.70 compilers and above an use either method. Older STD compilers can only
use method 2. OCG compilers prior to version 9.70 can use method 1 for most objects.

If I have a choice, which should I choose?

Making an object absolute is the easiest way of specifying a link location. However you are
limited to the object being at a known address. Using psects is more complex, but does
allow you to use the features of the linker to allocate memory for the object. You might,
for example have the linker place the object anywhere in an address range, or anywhere
provided it is above a specific address or after some other object.

In either case consider weather you need to do this as it immediately creates non-portable
code. If you must place objects at a known location, try to place the object at a sensible
location. If it is located in the middle of a bank or page, this will severely hamper the ability
of the linker to position other objects and "can't find space" errors may result.

1 Absolute objects

Absolute objects are created by using the "@ address" construct, where "address" is the
location at which you would like the object placed. Here are some examples.

int foobar @ 0x80;

const int marker @ 0x2000;

const char table[] @ 0x100 = { 0, 1, 2, 3, 4 };

int readInput(int a) @ 0x200
{
  // normal function body
}

Always check either the assembly list or map file to ensure that the object has been
located as you expect.

2 Using psects and the Linker

Using the "#pragma psect" directive you can place C code output or variables into 
a custom psect. You can then use linker options to place the new custom psect at 
the desired address. The syntax of pragma psect is:

#pragma psect  original_psect=new_psect

where "original_psect" is the name of the standard psect the code, constants or variables 
were orginally in. The orignal psect can be found by looking in the assembly list file or at
the symbol table in the map file. The names of psects used will vary between compilers,
and may even change between compiler versions.

If you determined that a function output was normally placed in a psect called text, then
the pragma:

#pragma psect text=extfuncpsect
// function definition follows

will place the function in a psect called extfuncpsect. You can then link this psect
independently to other text psects.

Some psects are numbered, such as some text or const psects, so they can be individually
controlled. Some psects have a number in their name to indicate the bank they belong to.
To represent the name of a numbered psect (other than those that contain a bank number)
replace the number with '%%u'. e.g.

#pragma psect text%%u=extfuncpsect
// function definition follows

The pragma will affect everything in the module, so create a new file for the functions or
variables that are to be positioned explicitly.

To position the new custom psect you will need to add an additional command line option 

-L-Pcustom_psect=address

The -L driver option will pass the following option (in this case a -P) to the linker. The linker
option -P will place "custom_psect" at "address". For example, use:

PICC -16f877 main.c serial.c  -L-Pfixed_serial=50h

If you are compiling under MPLAB IDE, then this option should be specified in the Additional
Command-line options field of the Global tab of the Build options dialog.

Consult your manual for more information.

Back to top

What does printf output to?

The printf() function performs two main tasks: formatting of text, and printing this
formatted text to stdout. The exact location of stdout is determined by a second
function called putch(), which is called by printf() to output each character.

By default the putch() function is empty. It should be customised to suit the project
at hand. Often printf() prints to a USART, but it could define stdout as being an LCD
or SPI. Code to initialize the intended destination must be executed before printf() can be
called.

A sample definition of putch() can be found in the putch.c file in the sources directory
of the compiler installation directory. After a copy of this file is customized, it should
be included into your project.
Back to top

How do I create a new project in MPLAB IDE which uses a HI-TECH C compiler?

The easiest way to create a new project in MPLAB IDE is to use the Project Wizard
selectable from the Project menu.

Make sure you select the HI-TECH Universal toolsuite for all modern HI-TECH
compilers. The compiler location is not used and should be left as it appears in the
field, even if it is wrong. You select the compiler to use for a project from the Build
Options dialog once you have created the project.

See the webinar:

http://techtrain.microchip.com/webseminars/ArchivedDetail.aspx?Active=193

for detailed information on the toolsuite and creating projects.

Back to top

What is HPA (High Priority Access)?

HPA is a support subscription, purchased in 12-month blocks, and that allows you
to download updates to your compiler free of additional charge during that
12-month period.

See the FAQ "How do I update my compiler?" for more information
Back to top

How do I fill unused program memory with a known value?

Modern HI-TECH C compilers implimented a --FILL driver option which allows you
to do this. You can access this option in MPLAB IDE Build Options dialog: go to the
Linker tab and enter the appropriate argument in the Fill field. 

This option utilizes the HEXMATE application to fill unused locations, thus it will
only work for HEX files -- it will not fill unused locations in binary file outputs, for
example.

The argument to the driver's --FILL option (or the equivalent field in MPLAB IDE)
are the same as the arguments to HEXMATE's -FILL option. Check your manual
in the Utility section for the format of this option and for other features that HEXMATE
provides.
Back to top

How do I access variables in PIC18 devices' external program space?

The far type qualifier is used to place variables into external program space of
PIC18 devices. Only some devices support the external memory interface.

Accesses to far variables are less efficient than accesses to internal variables and
extensive accesses to these variables will result in larger code sizes.

Here is an example of an unsigned int object placed into the device???s external
code space:

far unsigned int farvar;

Note that a --RAM option is mandatory to specify the external address range where far 
variables will reside. In MPLAB IDE, add the additional memory into the RAM Ranges
field in the Global tab of the Build Options dialog. For example, specify

--RAM=+30000-3FFFF

to the driver, or enter:

+30000-3FFFF

into the RAM Ranges field in MPLAB IDE.

You may also want to set the --EMI option to select which mode your device will
use to access the external memory. In MPLAB IDE, adjust the External Memory field
in the Global tab of the Build Options dialog. Refer to the your manual for more
information relating to this option.

Configuration bits and SFRs may need to be set up to configure the device to use the
external memory.
Back to top

Can I install two or more versions of the same compiler?

Yes.

Compilers will be automatically installed into a directory that is specific to each
compiler version. So under Windows, for example, the 9.63 and 9.64 compilers
would typically live in separate directories.

C:\Program Files\HI-TECH Software\PICC-18\PRO\9.63\
C:\Program Files\HI-TECH Software\PICC-18\PRO\9.64\

Note, however, that a patch-level update will by default try to install itself over
the top of a compiler of the same base release. For example if you tried to install
the 9.63PL1 compiler, it would install into the 9.63 directory, thus overwriting the
previously installed compiler. If you installed 9.63PL2, it would then overwrite the
9.63PL1 compiler.

If you would like to maintain separate copies of different patch levels of the same
base release, you simply need to adjust the default installation directory shown in
the installer. There is no problem having more than one patch level of a compiler
installed.

To select which compiler will actually be used when building a project under MPLAB IDE,
go to the Build Options dialog and select the Driver tab. This will show all available
compiler drivers and allow you to choose the one you want. Select it and move it to the
top of the list.

See the webinar:

http://techtrain.microchip.com/webseminars/ArchivedDetail.aspx?Active=193

for detailed information on selecting a compiler and creating projects.
Back to top

Where can I find the latest MPLAB IDE toolsuite plugin?

The latest MPLAB IDE toolsuite plugin (HI-TECH Universal Toolsuite) for all
HI-TECH C compilers can be downloaded via the following link.
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en535448

More on the Plugin can be checked on this link. 
http://techtrain.microchip.com/webseminars/documents/HiTech_112108.pdf
Back to top

Why do floating-point variables in MPLAB IDE have the wrong value?

MPLAB IDE's Watch window interprets all floating-point variables (whether
defined as 'float' or 'double') as 32-bit values unless you manually change
the properties for each one.

Since the HI-TECH C compilers for PIC10/12/16 and for PIC18 allocate
24 bits for 'float' and 'double' types, unless you explicitly specify otherwise,
this means all floating-point values displayed in the Watch view will be
incorrect. This does not affect the operation of code, merely what values are
displayed when debugging.

To correct the display, right-click on the variable name in the Watch window
and select Properties. Change the Size field to 24 bits. Also ensure that the
Format field is set to IEEE Float (as opposed to MCHP Float) -- this is the only
format used in HI-TECH C. You will need to do this for each floating-point
variable added to the Watch view.

Incidentally, if you meant to use 32-bit floating point types in your project,
adjust the Size of Double and/or the Size of Float fields in the Global tab of
the MPLAB IDE Build Options dialog and recompile.
Back to top

What does the error "(1187) invalid activation request" mean?

Before you can use any version 9 HI-TECH C compilers, it must be installed and
activated. If you have not activated the compiler, or the activation was not successful,
this message can be produced if you try to compile.

You can activate a compiler by selecting:

Start -> Programs -> HI-TECH Software ->  -> Activate or trial PRO mode

If you are performing an off-line activation, until you receive the activation response file
and use this to complete the activation the compiler cannot be run in a licensed mode.

See the webinar:

http://techtrain.microchip.com/webseminars/ArchivedDetail.aspx?Active=193

for more information on activation and creating projects using the HI-TECH Universal
Toolsuite.
Back to top

Is there a fix for this bug?

If you believe you've identified a bug in the compiler, here are some suggestions
to speed a resolution.

Check to ensure you are using the latest version. Customers with a valid HPA
subscription can download the latest version free of charge. Updates can
be downloaded from the Microchip website, here:

http://www.microchip.com/

Please send any support questions to support@htsoft.com or contact your local FAE.
This is the official channels for help requests. The forum is not regularly monitored
and should not be used for this purpose.

In most situations we will require code to reproduce the problem you are having and
devise a fix. If you are unable to cut down your project to isolate the problem, you
may need to zip the entire project and send this in. When making initial contact, please
make sure you indicate the compiler you are using, the compiler version number, and,
if applicable, your serial number.
Back to top

Why are some of my variables missing from MPLAB IDE?

An OCG compiler running in PRO mode may determine that some of your variables
are never used. These variables will be removed from the program. This means they
will not take up memory, not appear in the assembly list or map files, and they will
not appear in the MPLAB IDE Watch view.

Variables that are used, but only in a trivial fashion may also be used. For example
you may assign a value to them, but not read the value later. If there is no
functional effect of using the variable, it may be removed.

If you want the variable to remain, despite the fact that it is not used, qualify it
as "volatile" for debug builds.
Back to top

Why do I get "(924) missing argument to -O option" when compiling under MPLAB IDE?

The command-line options passed to the compiler driver changed in version 9
compilers, and you need to be using a new MPLAB IDE compiler plugin to ensure
these new options are used when compiling.

If you're using a version 9 compiler, in MPLAB IDE choose Select Language Toolsuite
from the Project menu and select the "HI-TECH Universal Toolsuite" rather than
one of the older compiler-specific toolsuites, such as the HI-TECH PICC Toolsuite or
the HI-TECH PICC-18 Toolsuite.

Do NOT specify the path of the compiler in the Location field of this dialog; it is not
used. See the webinar:

http://techtrain.microchip.com/webseminars/ArchivedDetail.aspx?Active=193

for more information on creating projects and using the HI-TECH Universal Toolsuite
in MPLAB IDE.
Back to top

What's with all these PRO, Standard & Lite modes, compiler types, evaluation and full versions?

We have changed the way compilers are bundled. The transition period may lead
to some confusion but the final product range will be simpler to understand and
easier to use.

For some time HI-TECH C compilers just had the one form, such as PICC and
PICC-18. For some devices we introduced a separate Lite compiler, which was a
separate product and a separate executable.

With the Introduction of our OCG technology we introduced a new PRO compiler
and the existing (non-OCG) compiler was then renamed as the STD compiler.
So, for example we had a PICC PRO and a PICC STD compiler, as well as the Lite
compiler. These were all separate compilers and separate executables. You had to
download and install these separately if you wanted to be able to use them all.
In MPLAB, to swap compilers you had to associate your project with a new compiler
and rebuild.

The next step of the transition was releasing just the one product and the one
executable, but one which can operate in three operating modes: PRO, Standard
and Lite. The Standard and Lite modes replace the STD and Lite compilers. If you
owned a license for the STD compiler, that carries forward to the new Standard
mode. All these modes use OCG, but the level of optimizations that are utilised
vary between modes. The Lite mode continues to be available free of charge and
is only limited in the efficiency of the generated code.

For example the PIC10/12/16 compiler version 9.70 can operate in Lite, Standard
or PRO modes. This means there is only one application you need to download and
install to get access to all three modes. You can swap back and forth between modes
(license permitting) simply as a build option in MPLAB IDE.

All HI-TECH C compilers can be evaluated. An evaluation is a time-limited period in
which the compiler can be run in the non-Lite mode without charge. There are very
few restrictions other than the length of time the compiler will operate in that mode.
The compiler will revert to the Lite mode after the evaluation period has ended.

Customers who purchase a PRO license are entitled to use the compiler in Standard
mode (as well we Lite, of course). If you need an old STD compiler for legacy code,
that can usually be provided to you.
Back to top

Why do my variables in the MPLAB IDE Watch view have the wrong value?

See also the FAQ "Why do floating-point variables in MPLAB IDE have the wrong value?"

If this is not applicable the reason may be that the compiler has cached the variable
into a register and MPLAB IDE is reading the variable's original memory location.

The compiler can reduce the code size required to access a variable by storing it in a
register. This cannot always be done, but it can have significant benefits. To make
matters worse, the register chosen may be different at different points in the code.
Unfortunately for those compiler/debugger combinations that still use COFF for
debugging (all compilers except PIC32) will have this problem as COFF does not
support the ability to track variables in more than one location.

This does not affect the operation of the code and often you will see the Watch view
indicate a wrong result, but the program operate correctly.
Back to top

Do you support this device?

If you already have a HI-TECH C compiler and want to know if it supports a particular
device there are a couple of ways you can do this.

1) Run the compiler on the DOS command line with the argument --CHIPINFO.
For example, if you were checking the 9.70 PICC compiler use the following command.

"C:\Program Files\HI-TECH Software\PICC\PRO\9.70\bin\picc.exe"  --CHIPINFO

If you are checking another compiler, use the installed path appropriate for that compiler.

What you will see is a list of supported devices printed to the console.

2) If you have the compiler integrated into MPLAB IDE you can get the same information
from the Build Options dialog. Click the Driver tab of this dialog and ensure the compiler
in question is shown in the Available drivers list. Select it. The list of supported devices will
be shown in the box towards the middle of this dialog. Scroll through and look for the
device you are interested in.
Back to top

What does the error, something like "Cant generate code" mean?

The error means that the compiler tried but was unable to generate output for the
indicated C source. It usually does not indicate that the C code is invalid, but review
the code to be sure.

This error will most likely occur with complex expressions, particularly on devices
with few working registers and simple architectures, e.g. Baseline devices. Remember
that C code that may not look complicated to you may be very difficult to implement
in assembly code.

The solution is to try to simplify the expression, maybe using a temporary variable to
hold an intermediate result. The compiler often has to resort to using compiler-defined
temporary variables to hold intermediate results so this work around is often no less
efficient that what would be otherwise possible.

Please inform support staff of the error as the compiler can often be tweaked to allow
the code to compile, but also consider this may be a warning that you asking too
much of the instruction set.
Back to top

What does the error "activation limit reached" mean when I try to activate a compiler?

A single-user license allows a compiler to be installed (activation is actually the
important issue)  on up to 2 computers. Only one copy of the compiler may be
used at any given time, however. So for example, you might install the compiler
on a desktop machine for day-to-day use, and also install it on a laptop for field
work.

If you attempt to install and activate the computer on more then two computers
you will see this error message appear. If you have had to reinstall the compiler
several times and see this error, you can contact support staff and explain your
situation.

Note that the record of your activations is not permanent. After a time, it is reset
and further activations can be made. This allows you to update your computer or
operating system without having to contact support.
Back to top

How can I reserve memory and prevent it be used by the compiler?

When you compiler for a particular device, all the on-chip memory ranges are
known by the compiler. If required, you can reduce these memory ranges, and
providing the device allows it, specify additional memory to these ranges.

These adjustments can be made using the  --RAM and --ROM  driver options.
If you are using MPLAB IDE, these options have direct counterparts in the Global
tab of the Build Options dialog. Here the RAM ranges and ROM ranges fields
should be used to specify the adjustments.

The arguments required for the driver options and the fields in MPLAB IDE are
identical. You should consult your manual for full details of the arguments. A
typical requirement is removing a range of memory. To do this, you can use:

--ROM=default,-1000-11ff

or enter:

default,-1000-11ff

into the MPLAB ROM ranges field, for example, which will remove the range
from 1000h to 11ffh from the default (on-chip) ranges.
Back to top

Do you support the PIC17 devices?

PIC17 devices are only supported by the older STD compiler. New compilers
using OCG -- either PRO, Standard or Lite modes -- do not support these devices.

PICC STD version 9.60 PL3 was the last official compiler release to support
these devices. If you own a license for a later compiler, you are entitled to use
this compiler.
Back to top

Can HI-TECH C check for MISRA compliance?

No.

You will need to see if there is a static code analysis tool available, such as PC-Lint, that can do
this for you.
Back to top

What are the restrictions in Lite mode?

Essentially none.

Modern Lite mode compilers can compile for the same devices as Standard and
PRO mode compiler, and each device will have present its full amount of memory.
Lite mode compilers even use OCG and so the entire C program is compiled in
one step and the source code does not need many non-standard extensions.

The main difference when using Lite mode is that not many optimizations are
employed and so the code size will be significantly larger than when using
Standard or PRO modes.

There are only a couple of command-line options disabled in Lite mode, but
these do not relate to code features; merely how the compiler can be executed.
Most customers never need to use these options.
Back to top

How can I change license details of a compiler?

Most of the information associated with a license (serial number) can be change
on the HI-TECH website. You will need the user ID and e-mail address that was
sent to you when you registered the product (or it may have been sent if you
ordered a downloadable compiler online). If you own more than one license that
is registered under the same name, then you will most likely have one ID for all
licenses.

The login page can be found here:

http://www.htsoft.com/downloads/log_in.php

and then proceed to the "Your details" page.
Back to top

What does the error "invalid version number" mean when I try to activate a compiler?

This error indicates that you are not entitled to use this version of the compiler.

If you have purchased a license for a compiler, you are entitled to any patch-level
updates to that version. That is, if you purchased a 9.60 PIC STD compiler, you
are entitled to use -- and for no additional charge -- 9.60 PL1 or 9.60 PL2 etc. of
the STD compiler, if they are made available.

If you have a valid HPA (High Priority Access) subscription, you are entitled to use
any update to the compiler you purchased which is released during the
subscription period.

If the update is not a patch level update to a base release version you already own,
or you do not have a HPA subscription, then you will need to purchase a HPA
restart subscription to be able to activate the new compiler.

If you believe this message is in error, please contact support@htsoft.com and
quote your license details.
Back to top

What does the error "invalid activation response" mean when I try to activate off-line?

If you are activating off-line and you receive this error it is most likely that the
activation request file does not correspond to the machine being activated or
that the request file you sent via e-mail was altered by your e-mail client.

The activation request file you send in must be generated by the machine that is
to run the activated compiler. The request file contains information specific to the
Windows installation on the machine and is only valid for that machine. You
should regenerate the activation request file any time you need to reactive to
ensure that the data it contains is accurate.

If you sent the contents of the file in the body of an e-mail message and you
have set your e-mail client to send in HTML format, this would explain the error.
The activation program is expecting plain text for any received requests. If you
send the request file as an attachment, this will work around this issue. Also
check no unusual end-of-line characters could be sent in the request file.
Back to top

How many computers can I install the compiler on?

A single-user license allows a compiler to be installed (activation is actually the
important issue)  on up to 2 computers. Only one copy of the compiler may be
used at any given time, however. So for example, you might install the compiler
on a desktop machine for day-to-day use, and also install it on a laptop for field
work.

If you attempt to install and activate the computer on more then two computers
you will see an error message appear indicating that your activation limit has been
reached. If you have had to reinstall the compiler several times and see this error,
you can contact support staff and explain your situation.

Note that the record of your activations is not permanent. After a time, it is reset
and further activations can be made. This allows you to update your computer or
operating system without having to contact support.
Back to top

Does HI-TECH C support any binary object files or libraries in formats other than HI-TECH's?

Currently, no.

The object files and library file formats are HI-TECH specific and the compiler
cannot read any other formats.
Back to top

How can I use the TO and PD bits to determine the cause of reset on PIC devices?

Some PIC devices have TO and PD bits in the STATUS register that can be used to
determine the cause of a reset. However the state of these bits are soon overwritten
after the reset has occurred and program execution has resumed.

The --RUNTIME suboption "resetbits" can be used to preserve these bits, and the
entire STATUS register, in variables that can be examined later in your program. If you
are using MPLAB IDE, this option can be specified by enabling the Backup reset
condition flags checkbox in the Linker tab of the Build Options dialog.

For full details of the names and types of the variables used, check your compiler manual
in the section called Status Register Preservation.
Back to top

Are administrator rights needs to use the compiler in MPLAB IDE?

Users do not need to have administrator rights to access the compiler from within
MPLAB IDE, but the MPLAB plugin (Universal toolsuite) does need to be able to read
and write certain entries in the registry.

If your user account does not have administrator rights, then you will need to
ensure that the registry entry for:

HKEY_LOCAL_MACHINE  ->  SOFTWARE  ->  HI-TECH Software

has "Full control" set for this any folder and all subregistry folders. In the Windows
Regedit program, right click on the above folder and choose Permissions. Select the
appropriate Group or user name and review the Permissions.
Back to top

What does the error "no file arguments" mean?

This indicates that the compiler was run but with no source files.

If you are using MPLAB IDE, make sure the source file(s) have been added to your
project. Having the file open in the MPLAB text editor does not mean the file is in
the project. If the file is open, right click in the file and select Add to project.

If you are using the command line, ensure the name of the source file(s) are listed
on the command line along with any compiler options.
Back to top

Why dont checksums or fills work when generating a binary output?

Some compiler features, such as those to add checksums or to fill unused memory
locations, are fulfilled by the HEXMATE application, which only works with HEX files.
If you are generating a binary file output, then this file will not contain any codes
inserted by HEXMATE.

If you do require a binary output and these additional compiler features, then it is
best to generate a HEX file and then use a third-party application to convert the
HEX file to a binary format.
Back to top

Does the same serial number work with Windows, OS X and Linux compilers?

Yes.

Normal licensing conditions apply, in that you can only activate up to two compiler
and only one may be in use at any given time, but there are no restrictions as to the
platform on which the compiler can be used.
Back to top

Does the HI-TECH C compiler for PIC18 MCUs support the extended instruction set?

Currently, no.

The extended instruction set allows the device to access additional instructions,
but at the expense of loosing access bank memory. The main reason for the use
of this instruction set is to allow reentracny, which is currently not supported by
the compiler.

Reentrancy may be introduced in future versions and this may well require
utilization of the extended instruction set.
Back to top

What are the nesting limits of function calls on 8-bit PIC devices?

For PIC18 and mid-range PIC devices, the function call depth is the same as the
depth of the hardware return address stack. Check the datasheet for the device
you are using.

Baseline PIC devices have a very small hardware stack depth (2 calls) and to work
around this, the compiler can employ a call mechanism based on lookup tables.
This allows a much larger level of function nesting, with no theoretical limit. Use
of the alternate call mechanism is automatic.

The call graph produced by the compiler (shown in the assembly list file for
compiler versions 9.70 and above, or the map file for earlier compilers) can be
used as a guide to stack depth, but this shows only a static analysis and so may
not reflect actual usage.

See your compiler manual for more information on function calls, and the
fastcall qualifier.
Back to top

How can I create a library?

First, libraries cannot be created using MPLAB IDE; you must use the command
line to build the file. You can use the command line shown in the MPLAB Output
Build windows as a guide to the command line you should use to build at the
DOS command prompt.

Second, you must built the correct library type: LIB or LPP. If you are using a
compiler with OCG and the source code for the library files is written in C (as
opposed to assembly), then you must choose the LPP output type. For all other
cases, choose the LIB type.

To check if your compiler uses OCG, go to the Driver tab in the MPLAB Build
Options dialog. Select the compiler in question from the Available drivers list.
Check to see if Omniscient Code Generation is mentioned in the Selected driver
information and support devices section in the middle of the dialog.

To generate the library file use the option:

--OUTPUT=lpp

or:

--OUTPUT=lib

depending on the library type you require. When building the library, make sure
that the --ASMLIST option is NOT used.

If you want to keep the contents of the library file confidential, use the --SHROUD
option, which will obfuscate the modules used.
Back to top

Is there any limit to the size of objects I can define?

Obviously the amount of memory implemented by the device is the ultimate limit,
but due to the way things are necessarily linked into memory and fragmentation
of memory, there may be additional restrictions in the size of objects. It may be
possible you receive memory errors even with some memory remaining.

When compiling for 16- and 32-bit devices there are few limits:

* The auto data to a function cannot total more than 32k for a function when
using 32-bit devices.
* 32 bit devices are also limited to 64k for non-const non-auto data
* One PSV page is used with 16-bit devices for storage of all const data.

The biggest limitations come with the 8-bit devices:

* There is also no actual function size limit for any new 8-bit compilers. But
note for the PIC10/12/16 compiler (Baseline and mid-range parts) functions that
do cross pages may be slightly less efficient due to longer call and goto
code sequences that must be employed. This is not the case for PIC18 and
enhanced mid-range devices.

* In terms of data objects, all objects must be be able to fit into the general
purpose memory in one data bank. (With midrange and baseline devices,
some of each data bank is taken up by special function registers.) Again, the
exception is for PIC18 and enhanced mid-range PIC devices which can define
objects larger than one bank in size.

The linker never deals with placement of variables; it only deals with placement
of blocks of variables. Like everything else, variables are placed into a psect (section)
which is linked as a whole. A psect cannot be split, which can mean that it may not
be able to be located when there are only small gaps remaining in memory.

See also the FAQ called "What does the error, something like "cant find xxxx
words/bytes for psect in segment yyyy", mean?"
Back to top

How do I interpret the call graph in the assembler list file?

With second-generation OCG compilers (typically version 9.70 and above) the
call graph is shown in the assembly list file. With older compilers this graph is
shown in the map file and, although it represents similar information, is presented
in a different form.

The call graph shows the call hierarchy associated with functions in a program,
i.e. which functions are called by a function.

Following is an example of a call graph for a simple program. The numbers on
the left are just the line numbers in the file and have no other meaning.

   445       ;Call graph:                      Base Space Used Autos Args Refs Density
   446       ;_main                                                1    0  752   0.00
   447       ;                                    7 BANK0    1
   448       ;              _init
   449       ;              ___wmul
   450       ;              _wakeup
   451       ;              _ctrl_s0
   452       ;              _ctrl_s1
   453       ;              _null_funct
   454       ;              _inpSWITCH_s4
   459       ;              _inpADC_s0
   460       ;              _inpADC_s1
   461       ;              ___bmul
   464       ;  _inpADC_s0                                         0    0   40   0.00
   477       ;              _next_state
   478       ;  _inpADC_s1                                         0    0   50   0.00
   479       ;              _ADC_start
   480       ;              _next_state
   481       ;              _get_sec_state
   502       ;    _ADC_start                                       2    0   10   0.00
   503       ;                                    0 COMMO    1
   504       ;                                    0 BANK0    1

Shown in this call is call hierarchy as well as information relating to the
placement of auto and parameter variables.

* Base: The start address of this block in the compiled stack
* Space: The memory space in which this block of the compiled stack will
  reside (data/program etc)
* Used: How many bytes were used in this space
* Autos: The number of autos and temporary variables defined in this function
  that use memory in the compiled stack
* Args: The number of parameters defined in this function that use memory in
  the compiled stack
* Refs: The total number of references to local objects in this function
* Density: Is not currently implemented

main() is the root of a call graph (note that the assembly form of the function
name, _main, is used). On line 446 it is shown along with a summary of objects it
defines (autos plus parameters, number of references) in lines 446 and 447. Here
we see that an auto variable was allocated to that block of the compiled stack
that resides in bank 0 RAM. It is placed at an offset of 7 in this block of the
compiled stack.

Lines 448 to 461 show all the functions that main() calls, or may call.

Then for each of the functions that main() calls, their information in shown.
Line 464 shows that inpADC_s0() does not define any local objects (hence there
is no breakdown of where objects are allocated), but this function does
call next_state().

The process continues. For our example function ADC_start(), you can see it
defines 2 bytes of auto and temporary objects. One byte is allocated to bank 0;
the other to common memory.

Your compiler manual has a full description of the call graph in the Assembler chapter.
Back to top

How do I interpret the pointer reference graph in the assembler list file?

The pointer reference graph is shown in the assembly list file for compiler
versions 9.70 and above. This graph shows every pointer in your program,
along with each target the pointer can reference. Here is an example. The
numbers on the left are just the line numbers in the file and have no other
meaning.

433       ;Pointer list with targets:
434       ;task_st_tab   const PTR FTN()void [8][4] size(1); Largest target is 0
435       ;               -> ctrl_s0(), ctrl_s1(), null_funct(),
436       ;               -> inpSWITCH_s0(), inpSWITCH_s1(),
437       ;               -> inpSWITCH_s2(), inpSWITCH_s3(),
438       ;               -> inpSWITCH_s4(), inpADC_s0(),
439       ;               -> inpADC_s1(), outLEDS_s0(), outLEDS_s1(), 
440       ;task_ptr      PTR struct task_def size(1); Largest target is 36
441       ;               -> task(BANK0[36]), 
442       ;timer_intr@req_ptr    PTR unsigned char  size(1); Largest target is 1
443       ;               -> task.ctrl(BANK0[1]), 
444       ;timer_intr@task_tmr_cnt_ptr   PTR unsigned int  size(1); Largest target is 2
445       ;               -> task.timer_count(BANK0[2]), 


The top line shows the pointer’s name, and type. The size of the pointer is indicated.
Remember that this size is determined from how the pointer is used, not from its
definition. The largest target is also shown. This is important when determining the
pointer’s size as a pointer may be required to increment over an array, for example,
and so must be large enough to access all addresses occupied by the array. The
name of each target is printed along with the memory class in which it is located, and
its size.

For example, we can see that task_st_tab is an array of pointers to a functions. The
address of this array is 1 byte wide. All the functions that the array elements can
reference are listed.

task_ptr is a pointer to a strcture. This pointer is 1 byte wide and it only ever points
to a structure called task. The structure is 36 bytes wide.
Back to top

Does HI-TECH C support the use of the malloc-style functions?

HI-TECH C compilers for 16- and 32-bit devices support dynamic memory
allocation functions like malloc etc.

8-bit compilers do not support these functions. As these devices have small
amounts of RAM and this memory is banked, it is totally inappropriate to implement
dynamic memory allocation on these devices.
Back to top

Where I can find information about compiler messages?

All error, warning and advisory messages have a unique number which is typically displayed
at the start of the message. For example:

example.c: 5: (751) arithmetic overflow in constant expression (warning)

The unique message number here is 751. This number can be used to control the behaviour of
the message using a number of compiler options, or the #pragma warning directive.

All messages are documented in the "Error and Warning Messages" chapter of the user manual.
This documentation will also indicate which compiler application produced the message -- it
is not much good looking for a problem in C code if the message is produced by the assembler,
for example.

Back to top

Why don't extended ASCII characters work in 9.70 compilers?

To comply with ANSI standards, 9.70 compilers no longer support the extended character
set in const char arrays. Instead, they need to be escaped using the backslash character, as
in the following example:

#include 

void main(void) {
   const char name [] = "Bj\xf8k" ;
   printf("%s's Resum\xe9",name) ; \\ will evaluate to "Bjørk's Resumé"
}

The ANSI table of extended characters can be found at the following website:
http://ascii-table.com/ansi-table.php

A helpful guide on C character sets can be found at:
http://www.dinkumware.com/manuals/?manual=compleat&page=charset.html
Back to top

Why don't the line numbers in an error message match the actual line with the problem?

In many cases an error or warning is reported for a line that follows the line that contains
the error. For example, consider these lines; the first is missing a semi-colon at the
end:

input = read()
input += offset;

There will an expression error produced, but the error will indicate the second line. This
is reasonable as the C language allows statements to be spread over multiple lines, so there
is nothing actually wrong with the first line of code. Once the second line is parsed, it then
becomes obvious that something is wrong. The error will be flagged at the line at which
things first go wrong.

If you are seeing error messages that are out by a number of lines, one thing you can check
is that your source files are using the correct "new line" characters. If you are compiling
under Windows, there should be CR-LF sequence at the end of each line. If, for example
the LF character was stripped somehow from a line, IDEs, like MPLAB, would still interpret
the remaining CR as a new line but the compiler will not. Since it is legal to have two
statements on the one line, seeing a multi-statement line is not flagged as an error, but if
there is an error later in the code, the line number count will not be accurate.

To see the characters used by a source file you will need to use a text editor that can display
them or dump the file in binary.
Back to top

When migrating to OCG what do I need to do to allow C variables to be accessed by assembly code that assumes these variables are in certain banks?

Bank qualifiers are not normally needed when writing program for an OCG compiler,
however if there is assembly code that assumes these variables are in a certain bank
then the C variables must be qualified using the bank qualifiers (bank0, bank1,
bank2 etc). Note that the bank0 qualifier did not exist in older STD compilers
(bank 0 was the default destination), but OCG compilers do have a bank0 qualifier,
which must be used if required.

The second thing that must be done is to ensure the qualifiers are honoured by
setting the --ADDRQUAL option to "require", or set the Address qualifiers selector
to "Require" in the Compiler Tab of the MPLAB IDE Build Options dialog. Without this,
qualifiers will be ignored by the compiler.

If the variables are not qualified and are placed in banks other than those expected
by the assembly code, fixup errors may occur, or the code may fail. Projects are  more
portable if the assembly code always selects the bank of any object and applies the
correct file address mask. In this way, there are no assumptions about the location of
the objects accessed and the C variables do not need to be qualified.

This FAQ is relevant for customers migrating to, or from, an OCG-based compiler.
Check the "Selected driver information and supported devices" field under the Driver
Tab in the MPLAB IDE Build Options dialog to see which compilers are based on OCG.
Back to top

When writing code that is to be portable between OCG and non-OCG compilers how do I define absolute variables that may be used in multiple source files?

If you are using the SFR variable definitions (which are absolute variables) in the header
files that come with the compilers, then there is nothing you need to do. The header
files that ship with the compiler are updated to ensure they are compatible with that
compiler version.

If you have defined you own header files, if you have copied and modified a compiler
header file, or if you simply defined absolute variables and use these variables in multiple
source files, then there may be changes required if you need the same code to compiler
on both OCG and non-OCG compilers.

For non-OCG compilers the variables must be defined in each source file as being static,
e.g.

static volatile unsigned char MY_REG @ 0x30;

Errors relating to the variables being defined more than once may result otherwise. For OCG
compilers you can use either static, extern or no storage qualifier.

This FAQ is relevant for customers migrating to, or from, an OCG-based compiler.
Check the "Selected driver information and supported devices" field under the Driver Tab
in the MPLAB IDE Build Options dialog to see which compilers are based on OCG.
Back to top

Do I need to do anything to source code that contains a #pragma psect directive when porting this code to an OCG compiler?

The #pragma psect directive was present in non-OCG compilers to allow C objects to
be placed into user-defined psects which could then be linked at locations specified
by the programmer. In early versions of OCG compiler (prior to version 9.70) the
#pragma psect directive was not implemented, but was re-implemented in versions
9.70 and above. OCG-compilers do allow objects to be defined as absolute, thus
bypassing the need to use this pragma in many instances.

If you are using a version 9.70 compiler, you can continue to use this pragma,
although the name of the default psect may have changed. (To check this, comment
out the pragma, compile and check which psect the object is normally placed in using
either the map or assembly list files.) Alternatively you can make the object absolute.
See your manual for more details, but the following illustrate examples of absolute
objects.

int input @ 0x10;  // place input at address 10h
const data[] @ 0x2000 = { 0, 1, 2, 3 };  // place array at 2000h in program memory
int myFunc(int a) @ 0x500
{
  // function entry point located at 500h
}

This FAQ is relevant for customers migrating to, or from, an OCG-based compiler.
Check the "Selected driver information and supported devices" field under the Driver
Tab in the MPLAB IDE Build Options dialog to see which compilers are based on OCG.
Back to top

Do I need to do anything to a project that uses a make file or build script when porting this to an OCG compiler?

If you are not compiling using an IDE then there may be changes required to the
build process. Your IDE should handle the new build process, but it is always prudent
to confirm the Build Options if a project swaps to a new compiler.

If you are using a two-step compilation process (i.e. compiling each source to an
intermediate file (step 1), then linking (step 2)) then there are things you need to be
aware of. The intermediate file format used with OCG compilers is a p-code file, using
a .p1 extension and created using the driver option --PASS1. Non-OCG compilers use
a traditional intermediate file format of an object file, using an .obj extension and
created using the driver option -C.

Some compiler options are not required for OCG builds, for example the --CP option
(some pointer sizes), -Lx (printf libraries) and -Bx (memory models). Most other options
have the same meaning in both compiler types.

If the project uses user-defined libraries these will need to be updated. See the dedicated
FAQ regarding this.

This FAQ is relevant for customers migrating to, or from, an OCG-based compiler. Check
the "Selected driver information and supported devices" field under the Driver Tab in the
MPLAB IDE Build Options dialog to see which compilers are based on OCG.
Back to top

Do I need to do anything to a project that includes user-defined libraries when porting this to an OCG compiler?

The library file format for non-OCG compilers is the .lib file, which consists of
separate .obj files packaged together into an easily accessible bundle. This same
file format is used by OCG compilers, but for assembly source code only. If the
library is build from C code routines then an alternate library format must be used.

The new format supported by OCG compilers is the .lpp file, which consists of
separate .p1 files packaged together in the same way as .lib libraries. These new
library files can be built in a similar way to the older style (either using LIBR directly
or simply using the compiler driver and the --OUTPUT option. MPLAB IDE cannot be
used to create libraries.) See your manual for more details and see also the FAQ
regarding using a make file or build script for information on the file formats.

Do not mix the source code used to build a library. The .lpp libraries must be built
from C source only; .lib libraries must be built from assembly source only. The .lpp
libraries are passed to the code generator application; .lib libraries are passed to the
linker application.

Regardless of the source code used to generate your libraries, you must rebuild the
libraries to use them in the OCG compiler. This may be true when migrating any
project to any other compiler version. If your original library source code is written in C,
then you must use the new .lpp file format for the libraries; libraries built from
assembly code must still use the old library format. The assembly code itself will almost
certainly require modification when porting to an OCG compiler. See other FAQs
regarding these requirements.

This FAQ is relevant for customers migrating to, or from, an OCG-based compiler.
Check the "Selected driver information and supported devices" field under the Driver Tab
in the MPLAB IDE Build Options dialog to see which compilers are based on OCG.
Back to top

What do I need to do to assembly code that references a function's auto or parameter block symbol ?a_xxxx or ?_xxxx when porting this code to an OCG compiler?

Due to changes in the compiler it was necessary to change the ?a_ symbols. The new
symbols begins with ??_. What the symbol represents is identical for pre 9.70 compilers.
For example assembly code which accessed the symbol ?a_readInput would now
access ??_readInput. The ?_ symbols were untouched.

Compilers versions 9.70 and above removed the restriction of having the compiled stack
located in one block -- they allow the stack to be allocated into multiple memory areas
(such as multiple banks) and so one symbol cannot be used represent this base address
any longer. For these compilers use the alternate form of addressing for all auto and
parameter objects. For example, to access the auto variable "i" defined in the function
main, use the assembly symbol main@i.

This FAQ is relevant for customers migrating to, or from, an OCG-based compiler.
Check the "Selected driver information and supported devices" field under the
Driver Tab in the MPLAB IDE Build Options dialog to see which compilers are based
on OCG.
Back to top

What do I need to do to assembly code that references 'btemp'-type temporary variables when porting this code to an OCG compiler?

The temporary variables defined by non-OCG compilers (btemp, wtemp, ttemp and
ltemp) were usually placed in un-banked memory (if possible) and were used by the
code produced by the compiler to hold some function parameters, many return values
and intermediate results of some expressions. OCG compilers may not use these
variables at all, or use them in a lesser role. They are now never used for function
parameters or return values; instead memory is allocated in the auto-parameter block
for those functions which require these variables.

If assembly source code uses these symbols and the code can be called from, or calls
C code, then the symbols specified in the calling convention must be honoured.
Specifically, this will be the case if these symbols are used in relation to function
parameters (either loading parameters for another function, or reading the parameters
of its own parameter area) or in relation to function return values (either reading the
return value from another function or loading the return value into its own return
location). Check your compiler manual for more details on the calling convention
employed.

If the "btemp" variables are being used for any other purpose it is recommended that
you choose different names and actually define the symbols yourself, if you are not
already doing so. This will ensure that there is no interaction with the variables used
by the compiler and will ensure that memory is reserved for your variables even if the
compiler does not perform this task.

This FAQ is relevant for customers migrating to, or from, an OCG-based compiler.
Check the "Selected driver information and supported devices" field under the Driver
Tab in the MPLAB IDE Build Options dialog to see which compilers are based on OCG.
Back to top

What do I need to do to assembly code that reserves data memory when migrating this code to an OCG compiler?

As the code generator is involved in memory allocation of data memory objects, it
must be aware of any memory that will be required by assembly code. As the code
generator does not read assembly code this information is provided to it by the
compiler driver which scans the assembly files before calling the code generator.

The driver will scan assembly modules for any psects that are located in data memory,
and which are both flagged as being abs and ovrld. The memory requirements of these
psects can be easily determined (without the linker having to be run) and this
information passed to the code generator. These memory locations will then not be
used by any objects defined in C code.

Here is an example of a psect that contains a directive to reserves 10 bytes of memory
at address 110h.

PSECT myAsmObjects,class=BANK2,abs,ovrld,space=1
  ORG 110h    ; an ORG makes sense in an abs-ovrld psect
myObject:
  DS 10       ; reserve 10 bytes

The space flag must be set to 1 for RAM-based memory. The class should ideally match
an existing class (see the map file for a list of all classes defined for the device), but is
not mandatory.

No linker options are needed to link this psect as it is absolute (always linked at address
zero). Always check the map file to ensure your code worked as expected -- check the
address of the symbol myObject, for example, in the symbol table.
Back to top

What does 'No valid installed HI-TECH compiler drivers' when building with MPLAB IDE?

If you have installed, activated and been using your HI-TECH C compiler and this
message has just occured, the most likely reason is that you have changed the target
device for the project and the new device is not supported by the installed compilers.
Back to top

What could cause corrupted variables or code failure when I am using interrupts?

If you have a variable used in both main-line and interrupt code, make sure it is
qualified "volatile". This will prevent the compiler from using cached copies of the
variable and performing other optimizations. The compiler will also attempt to access
the variable atomically, but this is not always possible if the assembly instruction set
does not permit this.

You can check the assembly list file to see the assembly code used to access variables
and determine if the access is atomic. If it is not, consider disabling the interrupts
when it is accessed in main-line code.
Back to top

What could cause pins in a port to change from values I assign to them?

If you are using the port as an output, make sure that you configure it to be digital,
not analog. If it is set to analog, writing to one port pin can change the state of other
pins. Check the datasheet for the device you are using for more information on how
to set up the port.

Note also that some pins are multiplexed between the ports and other peripherals
and so may not be available as I/O if you are using those peripherals.
Back to top

What could cause glitches on an output port?

If you have defined your own variables to reside at the port locations, make sure
you qualify these variables as "volatile". Without this, bits within the port, or the
entire port byte value itself, may not be accessed atomically (in one instruction).
For example, the most efficient way to write a bit on 8-bit devices is to set the bit,
then optionally clear it if required. this takes the least amount of code, but can lead
to the bit changing state twice.

There could also be problems with cached copies of the port value being used if
you should read from the port. For example:

volatile unsigned char LEDBANK @ 0x00C;   // this maps to PORTA

If you are using the definitions for the ports that become available after including
 then these are already correctly qualified and you do not need to modify
these definitions.
Back to top

Where can I find the call graph produced by OCG compilers?

The latest 9.70 version compilers now place the call graph in the assembly list file
rather than in the map file. This is because the call graph is now produced by the
code generator, not the linker application. The information contained in the new call
graph is very similar to that which was contained in the map file, however the format
has changed and more information is provided.

The --CALLGRAPH option (or the Callgraph selector in the Linker tab of the MPLAB IDE
Build Options) no longer has any function with the new compilers.
Back to top

Do I need to do anything to C source code that contains a #pragma interrupt_level directive when porting this code to an OCG compiler?

The exact operation of this pragma has changed between non-OCG compilers and
OCG compilers, but the pragma is used to convey the same meaning and typically
code does not need to be changed when migrating.

This pragma would be used with non-OCG compilers to indicate that a function is
allowed to be called from main-line and interrupt code because the programmer
has taken special steps to ensure that there will be no reentrancy issues. The
pragma suppresses the error message that would otherwise occur.

When using an OCG compiler, this pragma is used to indicate that the function
duplication that would normally take place when a function is called from main-line
and interrupt code should not be performed, again due to the fact that the
programmer must have taken steps to ensure that reentrancy issues have been
dealt with.
Back to top

How do I fix errors relating to 'illegal conversion of pointer types' or 'illegal conversion of integer to pointer'?

The latter message will be produced if you convert an integer (either literal or variable)
to a pointer type, for example:

int * ip = 0x1234;

If you cast the type of the integer in the above, so you have:

int * ip = (int *)0x1234;

the warning will go away, but the problem will still occur. (This is the problem with
casts -- they mask all manner of problems in code. See the FAQ "When should I cast
expressions?")

See the FAQ "What do I need to do to C code that assigns an integer to a pointer when
migrating this code to an OCG compiler?" for more information on how to fix code
like this.
Back to top

When should I cast expressions?

Expressions can be explicitly case using the cast operator -- a type in round brackets,
e.g. (int). In all cases, conversion of one type to another must be done with caution and
only when absolutely necessary.

Consider the example:

unsigned long l;
unsigned int i;

i = l;

Here, a long type is being assigned to a int type (the assignment will truncate the value
in l). The compiler will automatically perform a type conversion from the type of the
expression on the right of the assignment operator to the type of the lvalue on the left of
the operator. This is called an implicit type conversion.

You should not use a cast in this expression. The compiler knows the types of both
operands and will perform the indended operation. If you do use a cast there is the
potential for mistakes if the code is changed. For example, if you had:

i = (int)l;

the code will work the in the same way, but, if in future, the type of i is changed to a
long, for example, then the programmer must remember to adjust the cast, or remove
it, otherwise the contents of l will continue to be truncated by the assignment.

Only use a cast in situations where the types the compiler will use are not the types that
you would like it to use. For example consider the result of a division assigned to a floating
point variable:

int i, j;
float fl;

fl = i/j;

In this case integer division is performed, then the result is converted to a float format. So if
i contained 7 and j contained 2, the division will yield 3 and this will be implicitly converted to
a float type (3.0) and then assigned to fl. If you wanted the division to be performed in a float
format, then a cast is necessary:

fl = (float)i/j;

for example (either i or j can be cast before the division). The result assigned to fl now be 3.5.

An explicit cast may suppress warnings that might otherwise have been produced. This can also
be the source of many problems. The more warnings the compiler produces, the better chance
you have of finding potential bugs in your code.
Back to top

What do I need to do to C code that assigns an integer to a pointer when migrating this code to an OCG compiler?

The ANSI Standard indicates that integer constants (either literals or integer non-pointer
variables) may be assigned to pointers, but what happens after that is implementation
defined. That is to say, it is not clear what will happen if you dereference the pointer or
perform other operations on it.

You will also notice in the Standard that pointers are only considered valid when they
point to an object. You can be guaranteed that a pointer points to an object if you assign
it the address of an object (using the unary & operator) rather than assigning an integer
value.

Non-OCG compilers work in a very basic fashion with regard to pointers and some code
that may work on these compilers may fail in OCG compiler, as predicted by the Standard.
The OCG compilers perform a number of optimisations that are based on information
obtained from each pointer's target list. These optimisations can be defeated if the
information regarding targets is not complete.

Regardless of which compiler you use, always take the address of an object when assigning
to a pointer. In some instances it may be necessary to create a dummy object whose
address can be taken, if no other object exists.

The information the compiler needs to fully understand a pointer target is:

* the base address of the target
* the size of the target
* the memory space in which the target lies; and
* the type of the target

Let's look at special examples where you might be tempted to assign integers to pointers.

Let's say you want to use a pointer to calculate a checksum of all locations in bank 2 data
memory (from addresses 110h to 16fh) on a mid-range PIC device. We assume here that
every memory location holds a significant value, but that there could be many C objects
that reside in bank 2, and we are not sure which object these are. First create a dummy
object which does reside at the addresses of interested and in the desired memory space:

extern unsigned char ram_dummy[0x60] @ 0x110;   // defines type, size, memory space and address

The object is made extern so that it does not have memory reserved for it, and being absolute,
it can exist "over the top" of other objects in this bank. Form this object the compiler can
determine all four of the above attributes. Now you can use this object:

const char * cp;                  // cp is made const since we should not use it to write

cp = &ram_dummy;                  // address taken and assigned
while(cp != &ram_dummy[0x60])    // pointer comparison
  total += *cp++;                 // pointer deference

Note the pointer is assigned an address which is derived from a C object.

Note also the pointer comparison in the while() statement. The ANSI standard also indicates
that addresses may only be compared when they point to the same object. Again, you should
compare pointers with the address of some object, not an integer constant cast to be a pointer.

If you wanted to do a similar thing, but with objects in program memory, the procedure is the
same. Note that not all devices can directly read their own program memory, and may
implement program memory which is word-addressable. If arrays are located in this memory,
the values read using a pointer will be the data values in the array. You could not use this
method to calculate a checksum of the instructions in a block of program memory. You would
need to use flash read function to do that, if they exist for the target device.

Let's say we want to read from address 2000h to 2fffh, and assuming there is no single C object
that resides at these addresses, first create a dummy object which is located here and in the
desired memory space:

extern const unsigned char dummy[0x1000] @ 0x2000;  // defines type, size, memory space and address

Here the const qualifier implies the program memory space. As there is no initial values, this
object does not contribute to the output hex file and so will not overwrite any other objects.
Now you can use this object:

const unsigned char * cp;         //cp is made const since we should not use it to write

cp = &dummy;                      // address taken and assigned
while(cp != &dummy[0x1000])       // pointer comparison
  total += *cp++;                 // pointer deference

OCG compilers do understand the special case of an assignment of 0 (zero) to a pointer. This is
a null pointer, has special meaning, and is an address that is guaranteed not to point to any object.

If you need to take the address of an object defined in assembly code, then write an appropriate
C declaration for the assembly object, then use this C object as the target.
Back to top

Can I access C pointers from assembly code written for an OCG compiler?

Pointer variables defined in C code will have a size and format which is determined
by the compiler after analysing the entire C project. This pointer sizes and formats
can change from one build to another as the C program is developed. This would
make it very difficult to access C pointers from assembly code as the size and format
is not fixed.

The 9.70 (PIC10/12/16 9.70PL1 introduced this for mid-range devices) compilers will
fix the pointer class so that it has maximum size and can access all objects from all
memory spaces.

For all PIC10/12/16 devices, the size of these pointers is 2 bytes. For Baseline and Mid-
range PIC devices, the most significant bit is set if the address is that of a data memory-
based object; clear if it is that of an object in program memory. For Enhanced Mid-range
PIC devices, the state of this bit is reserved: set indicates a program memory address;
clear the address of an object in data memory.

This encoding enables the pointer to be accessed correctly from assembly code, but
will mean that any code that manipulates and dereferences the pointers may be
larger and slower than necessary, so it is recommended that pointers are not accessed
by assembly code if at all possible. Assembly code may create variables which can be
used to hold addresses, if required.
Back to top

Why don't my interrupts work after the PIC32 device awakes from sleep/idle mode?

If the PIC32 device enters sleep mode and it is to be woken by the watch-dog timer
(WDT) then this FAQ may explain why interrupts are disabled after waking. 

When the device is awoken from sleep mode using the WDT it triggers a non-
maskable interrupt (NMI).  These interrupts are hard-wired to vector the PC to the
reset vector (i.e. 0xBFC0000 in KESG1 boot flash memory).  The compiler generated
startup code will test for a NMI and jump to a handling routine.  The default routine
is simply an ERET instruction which sets the PC to the instruction following the WAIT
instruction in the program code which was used to enter sleep mode in the first
place.  

After the NMI has been "serviced" in the above manner the system coprocessor (CP0)
STATUS register will have undergone some changes. Firstly the NMI bit in the CP0
STATUS register (STATUS<19>) will be set.  This merely indicates that entry through
the reset vector was due to an NMI. It should be cleared by the user's code once the
NMI has been serviced. Secondly the BEV bit (STATUS<22>) will be set.  This bit controls
the location of exception vectors and when set all exceptions are vectored to the
bootstrap exception vector (i.e. 0xBFC00380 in KESG1 boot flash memory).  This bit
should also be cleared in the user's code after the NMI has been serviced.  Lastly the IE
bit (STATUS<0>) will be clear which disables all interrupts.  These last two conditions
effectively disable interrupts.

Here are a couple of suggests to restore interrupts after a waking from sleep mode.

1) After the code which entered sleep mode test the STATUS bit and adjust the
STATUS register accordingly, e.g.:

if (cp0_Status | 0x00080000
        cp0_Status ^= 0x00480001;

2) Create an interrupt function to service the NMI and modify the Status register. e.g:

void interrupt nmi(void) @ NM_INTERRUPT
{
    cp0_Status ^= 0x00480001;
}

For more details about NMI's and waking from sleep/idle with the WDT please consult the
relevant datasheet and family reference manual. 
Back to top

What optimizations are present in OCG compilers?

The optimizations in OCG compiler can broadly be broadly grouped into:

1) C-level optimizations -- which are performed on the source code before conversion
         into assembly; and
2) Assembly-level optimizations -- which are performed on the assembly code generated
         by the compiler

Of the C-level optimizations, these can be considered as those that:

a) Simplify or change the C expressions; and
b) Allocate variables to registers

An example of where the code expression may be simplified is this: Consider if the original
C code read:

a = b + c;

but the compiler is able to determine that the variable "c" at this point will always hold the
value 5. The code expression is essentially changed so that it reads:

a = b + 5;

This may result in more efficient code after it is built by the compiler. These sorts of
optimizations are inherent in the compilation process and currently cannot be disabled.
They may reduce both code and data size.

Allocation of variables to registers is done after analysing the code and finding where each
variable is used and modified and after determining the cost associated with moving the
variable from memory to a register. The compiler is able to determine the exact register usage
of each routine, and any unused registers will be considered available for variables. A variable
may move from one register to another within a function; it may spend some of its duration in
a register and some in its allocated memory location, or its entire duration in a register.
Registers can typically be accessed with less code compared to reading from memory.

The global optimization level may have some impact on the register allocation. The level of this
optimizer (1-9) affects how hard the compiler tries to force variables into registers. Note that
even if the global optimizer is disabled, there may still be use of registers for variables in a
program. On devices that have few registers (e.g. all 8-bit PIC devices, especially Mid-range
PIC devices) the global optimizer has a very limited effect and often it makes little difference to
code or data size.

As C-level optimizations are performed before debug information is produced, they tend to have
less impact on debugging intformation. Note, however, if a variable is located in a register
MPLAB IDE may indicate incorrect values in the Watch view. This is due to a limitation in the file
format used to pass debug information to the IDE (COFF). Check the assembly list file to see if
registers are using in the routine being debugged.

Of the assembler optimizations, the actions performed include:

i) In-lining of small routines
ii) Proceedural abstraction
iii) Jump-to-jump type optimizations
iV) Peephole optimizations

These optimizations can often interfere with debugging in tools such as MPLAB IDE and it may be
necessary to disable them, if possible. The assembler optimizations can drastically reduce code size,
although typically have little effect on RAM usage.
Back to top

Where can I find the old compiler versions?

Previous versions of the compiler are archived at the below mentioned webpage. 
These versions can be downloaded after logging into the website:
http://htsoft.com/downloads/archive.php

The latest versions of the compiler can be downloaded from the website 
http://htsoft.com/
Back to top

What version of the Compilers work with Vista/Windows 7?

Vista/Windows 7 support was introduced with the below mentioned versions of the compiler. 
Compilers released as an upgrade to these versions also support these operating systems. 
PICC STD 9.60PL2
PICC PRO 9.60PL1
PICC18 STD 9.51PL2
PICC18 PRO 9.61PL1
dsPICC STD 9.60PL2
PICC32 PRO 9.60

e.g. 
PICC PRO v9.61 & any version above it will work with vista/Windows 7
PICC18 PRO v9.62 & any version above it will work with vista/Windows 7

PICC PRO v9.60 & any version below it will won't work with vista/Windows 7
PICC18 PRO v9.61 & any version below it will won't work with vista/Windows 7
Back to top

How do I register my Compiler on microchipdirect.com?

Apart from the activation & installation the compiler you also need to register your product. 
You need to register your order on microchipdirect.com https://www.microchipdirect.com/loginuser.aspx
Register the product using this guide 
http://www.microchip.com/HPA/#hpa

Your MicrochipDirect Account will show the details related to your products. Your Serial number is the Compiler 
Serial number which should be something like a PICC-xxxxx or PIC18-xxxxx

Step by Step guide to Register your Product:
Go to microchipdirect.com >> Login / Register >> Services >> Register your Product >>  
Register New Product >>  Fill in these details (Select Product Category / Purchased From/Purchased Date 
/ Serial Number) >> Submit >> Click on the link (Register Support Contract)
>>Please Provide Following Information (HPA Serial Number / Development Tool Serial Number)

Orders placed via MicrochipDIRECT are fulfilled as follows: 
*	Products are warranted to Microchip datasheet and current errata per
applicable Microchip Terms and Conditions of Sale.
*	Custom product, packaging, or marking is available upon request only
*	Mixed date code shipments may be sent. 
*	Date codes may be greater than two years.
*	Microchip Quality System and Customer Service cannot support:
*	Conformance to specific customer quality specifications
*	Requests for information or qualification data
*	Specific environmental information requests
*	Special terms and conditions
Back to top

What does the error "Could not find space xbytes for auto/param block" mean?

The auto/param block (APB) referred to in the error message, contains all the
autos, parameters and temporary storage used by the program.  This block is
limited in size to no more than one bank and may not even cross bank boundaries.
In order to reduce the size you'll need to:
1) Reduce the size or number of function parameters, for instance rather than
passing a structure by value pass a pointer to the same instead
2) Change the storage class of some of your local variables to static or make
them global
3) Where possible reuse local variables and parameters
4) Use types which are no bigger than what they need to be, for instance the
counter variable in for loop over 100 objects need only be as large as a char
5) Reduce the size/ number of secondary data types (arrays etc) in your code. Having too
many of these secondary data types would lead to these errors

There are a few instances where the PRO compiler will use more temporary
storage than the standard.  Some of these instances are as:
  1) Evaluating function calls whose result is used immediately in evaluating
  the parameter to another function call.
  2) Nested tertiary operators and tertiary operators used to evaluate    function parameters
  3) Functions requiring reentrancy: these are duplicated by the compiler for
  each root call graph they appear in. Hence they will have duplicate
  APBs.

The compiler will as much as possible attempt to overlap the
APB's of individual functions.  Sometimes however these APBs don't always
completely overlap with others.  These functions sit on the critical path of
the program call graph.  If you reduce the APB of such functions you'll also
reduce the APB of the program.  You can identify these functions in the call
graph provided in the map file.  These functions will be marked with an
asterix. For more details about the APB, the call graph and the critical path have a
look at the manual.
Back to top

How can I create a delay in my program?

If an accurate delay is required, or if there are other tasks that can be performed during the delay,
then using a timer to generate an interrupt is the best way to proceed.

If these are not an issue, then you can use the compiler’s in-built delay psuedo-functions: _delay,
__delay_ms or __delay_us. These all expand into in-line instructions or a (nested) loop of instructions.
The delay amount must be a constant (cannot be a variable) and less than approximately 50659,000.
The delay amount is the number of instruction cycles that will be executed by the delay.
Earlier versions of the compiler only implemented a two-nested-loop delay and so the maximum delay
amount was considerably less. Note that these code sequences may use the CLRWDT instruction.
Back to top

Why are SFRs undefined in my assembly code?

If you want to use SFRs in assembly code, you should always include a header files that defines the
SFR symbols to use. For PIC10/12/16, use  for assembly modules, or  for
in-line assembly. There are also  and  header files as well.

The symbols defined by these file do not have a leading underscore character, so you can use STATUS or
PORTA, etc. Other symbols are defined for bits and which specify the register name and bit offset.
The symbols are different in the two header files. For aspic.h, TMR0IF is defined as INTCON, 2;
in caspic.h TMR0IF_bit defines the same bit. Either can be used directly as the bit operand to an
instruction, e.g. bsf TMR0IF.

There may or may not be assembly-domain SFR symbols "left over" from the compilation process that
you might be able to use in your assembly code, but you should not rely on these being present.
Always include the header files mentioned above so that you can guarantee that the symbols you
require are defined.
Back to top

What does a can't find space for a swtext psect mean?

See the FAQ 'What does the error, something like "can't find * words for psect" mean?' for general
information about what this error means.

A common cause of out-of-space messages that deal with the swtext psect is that the C code
contains a switch statement that has too many cases. The swtext psect holds switch statement
instructions that are jumps to each case label. The 'computed goto' limitations on base-line/
mid-range devices, demand that this psect wholly fit within a 100h boundary. Special options
associated with this psect ensure that these demands are met or an error will be produced.
Back to top

How do I install Mac and Linux compilers

The non-Windows compiler installers are in the form of an executable script file that have
a ".run" extension, e.g. picc-9.81.7612-osx.run. When running, they install and activate the
compiler, prompting you for information as they proceed.

The installer must be run from the command line. If you are installing on an Apple Mac
computer, first run the Terminal application. The terminal will open in your home directory.
Ensure the installer (.run) file is in your home directory, using the FInder to copy it if necessary.
Alternatively, you can leave the installer where it is and navigate your way to the enclosing folder
in the Terminal application. For example, if the installer was in your Downloads folder, you
would type (note that commands and names are case sensitive):

cd Downloads

Run the installer by typing "./" then the compiler's name. (The command "ls" will list the names
of files in the current directory and you can select the name with the mouse cursor, then copy
and paste the name using the clipboard.) For example:

./picc-9.81.7612-osx.run

The installer will first print the license agreement. Read this, hitting the "space" key until all the
agreement has been seen and you see the prompt "Do you accept the terms of the licence
agreement?" Type "y" to accept, or "n" to quit.

The installer will ask for the directory in which to install the compiler. The default directory path
is printed in square brackets, but you will probably want to change this. Type the new path using
forward slashes to separate directories; do not use the "~" character. You may wish to install it in the
Applications folder, or somewhere in your own account if you are the only account holder to use it.
Below are two examples, the second assuming the account name is "john".

/Applications/hitech/picc/9.81
/Users/john/hitech/picc/9.81

The directories will be created if they do not exist. It is recommended that you include the compiler
type and version number in the directory structure, particularly if you plan to update to later versions of the
compiler. You can have more than one compiler installed at the same time.

The installer will next prompt you for your serial number. Enter only the digits of your serial number. If you
do not have a serial number and wish to evaluate the compiler, enter "demo". If you want to permanently
run the compiler is the free Lite mode, enter "lite".

Activation should take place automatically over the Internet and you should see the installer confirm that
installation and activation was successful.

The compiler can be invoked by running the compiler driver (either "picc" or "picc18" for the PIC10/12/16
or PIC18 compilers, respectively). For example, if you had installed the compiler in the Applications folder,
as above, you can run the compiler with the commands:

/Applications/hitech/picc/9.81/bin/picc --ver

which will print the version number and quit; or:

/Applications/hitech/picc/9.81/bin/picc --help

which will print help for the driver options, then quit; or

/Applications/hitech/picc/9.81/bin/picc  --chip=16f877  main.c  isr.c 

which will build and link the two source files indicated for the PIC16F877 device. The last example assumes
that you were in the same directory as the source files when you issued the command.

The procedure is identical for Linux installations, although the directory paths will be different.
Back to top