HI-TECH FAQs 22 How do I create an array of pointers in ROM? 25

advertisement
HI-TECH FAQs
22
How do I create an array of pointers in ROM?
25
Why don’t 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?
151
How do I integrate a HI-TECH compiler into MPLAB IDE?
161
What does the MPLAB IDE message "No installed HI-TECH compiler driver supports this device" mean?
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 I can't 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?
752
Why am I getting a reply email from support@htsoft.com to log in a query to Microchip support page instead?
1. 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) a
Back 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 maintenance subscription 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 1800h1FFFh, 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 whether 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.htsoft.com/downloads/mplab.php
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
How do I integrate a HI-TECH compiler into MPLAB IDE?
To use the latest HI-TECH compilers, you need to be using the HI-TECH Universal Toolsuite. This is the MPLAB IDE
plugin that controls the compiler. This toolsuite is installed when you install the compiler.
The webinar: http://techtrain.microchip.com/webseminars/ArchivedDetail.aspx?Active=193 contains detailed information
on the toolsuite plugin, and creating projects in MPLAB IDE. This toolsuite is installed when you install a compiler, but
updates can be installed independently from the compiler and are available from here:
http://www.htsoft.com/portal/UniversalToolsuite
Back to top
What does the MPLAB IDE message "No installed HI-TECH compiler driver supports this device" mean?
This message occurs if the "HI-TECH Universal Toolsuite" does not detect any functional, compatible HI-TECH C
Compilers that support this particular device. For a compiler to be detected and listed as available, it must:
* Be compatible with the universal toolsuite
- i.e. the compiler must be version 9.50 or higher
* Be installed correctly and activated
- New OCG compilers will revert to Lite mode if not activated, but still appear in the list
- Older compilers will expire and not appear in the list
* Support the specific device used by your project
- Run the compiler from command line with --chipinfo option to see the
supported devices
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. All patch level updates are free of charge if you have a valid license to the base release
version. Updates can be downloaded here: http://www.htsoft.com/downloads/updates.php
Support staff may also be able to supply a release candidate version of the next release in some situations. This will not
be an official release, but will have completed basic testing and will typically only contain bug fixes or support for new
devices. Contact support@htsoft.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.
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 Toolsuitein 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. If you do not have a HI-TECH C compiler installed, or you want to check the devices supported by
the latest compiler, go to the HI-TECH C website: http://www.htsoft.com/products/compilers/supporteddevices.php
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 (onchip) 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
theDOS 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 whenusing 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:
* For Baseline and mid-range devices, a function must fit entirely within a program memory page. This is not true of
functions for Enhance mid-range device, which can be as large as memory allows. There is also no function size limit with
PIC18 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 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 (block) 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 xxxxwords/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. OCGcompilers 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 unbanked 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 I can't 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 nonmaskable 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 Midrange 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
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
As examples:
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
Register the product using this guide.
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 may 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 critical paths in the Call Grpah section of the assembly
list file. Consult your manual for more information.
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.
Some new compilers also implement a _delaywdt inline function, which may use the CLRWDT instruction. For compilers that use
this function, the _delay function is guaranteed not to 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.7612osx.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
Why am I getting a reply email from support@htsoft.com to log in a query to Microchip support page instead?
The HI-TECH Compiler support system, previously accessed through http://www.htsoft.com/
or support@htsoft.com has moved to Microchip Support website http://www.microchip.com/support
as of 31 January, 2012.
Request for assistance on Microchip support system can be logged in three simple steps:
1. Go to www.microchip.com/support, select the My Tickets tab.
2. Click the 'Add a ticket' button and enter your question and other details.
3. Submit the ticket.
For information about using the support site and the support system features, view the videos here:
http://www.microchip.com/aboutsupport
The Microchip support system will provide better knowledgebase, efficient search tools,
and easier access to Code example, FAQ’s, Compiler download page, Application codes, Webinars/ Videos etc.
There will still be a dedicated Compiler Analysis and Assistance team to assist with compiler related issues as well as priority support
for those on HPA.
Back to top
Download