#ext.defineeWAITING0xff00func_change_up();if(sh

USB.org - Defined 1.0 Class Codes
Defined 1.0 Class Codes
USB Class Codes&&&&&&&&&&&&&&&&&&&&
June 15, 2016
USB defines class code information that is used to identify a device?s functionality and to nominally load a device driver based on that functionality. The information is contained in three bytes with the names Base Class, SubClass, and Protocol. (Note that ?Base Class? is used in this description to identify the first byte of the Class Code triple. That terminology is not used in the USB Specification).&There are two places on a device where class code information can be placed.One place is in the Device Descriptor, and the other is in Interface Descriptors. Some defined class codes are allowed to be used only in a Device Descriptor, others can be used in both Device and Interface Descriptors, and some can only be used in Interface Descriptors.&The table below shows the currently defined set of Base Class values, what the generic usage is, and where that Base Class can be used (either Device or Interface Descriptors or both).
This base class is defined to be used in Device Descriptors to indicate that class information should be determined from the Interface Descriptors in the device. There is one class code definition in this base class.& All other values are reserved.
This value is also used in Interface Descriptors to indicate a null class code triple.
Base Class
Use class code info from Interface Descriptors
This base class is defined for Audio capable devices that conform to the Audio Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values. Values outside of that defined spec are reserved. These class codes may only be used in Interface Descriptors.
Base Class
Audio device
This base class is defined for devices that conform to the Communications Device Class Specification found on the USB-IF website.&That specification defines the usable set of SubClass and Protocol values. Values outside of that defined spec are reserved.& Note that the Communication Device Class spec requires some class code values (triples) to be used in Device Descriptors and some to be used in Interface Descriptors.
Base Class
Communication device class
This base class is defined for devices that conform to the HID Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values.&& Values outside of that defined spec are reserved. These class codes can only be used in Interface Descriptors.
Base Class
HID device class
This base class is defined for devices that conform to the Physical Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values.& Values outside of that defined spec are reserved. These class codes can only be used in Interface Descriptors.
Base Class
Physical device class
This base class is defined for devices that conform to the Imaging Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values.&& Values outside of that defined spec are reserved.
Base Class
Still Imaging device
This base class is defined for devices that conform to the Printer Device Class Specification found on the USB-IF website.& That specification defines the usable set of SubClass and Protocol values.& Values outside of that defined spec are reserved.& These class codes can only be used in Interface Descriptors.
Base Class
Printer device
This base class is defined for devices that conform to the Mass Storage Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values.&Values outside of that defined spec are reserved.&These class codes can only be used in Interface Descriptors.
Base Class
Mass Storage device
This base class is defined for devices that are USB hubs and conform to the definition in the USB specification.& That specification defines the complete triples as shown below.& All other values are reserved.& These class codes can only be used in Device Descriptors.
Base Class
Full speed Hub
Hi-speed hub with single TT
Hi-speed hub with multiple TTs
This base class is defined for devices that conform to the Communications Device Class Specification found on the USB-IF website.&That specification defines the usable set of SubClass and Protocol values.Values outside of that defined spec are reserved. These class codes can only be used in Interface Descriptors.
Base Class
CDC data device
This base class is defined for devices that conform to the Smart Card Device Class Specification found on the USB-IF website.&That specification defines the usable set of SubClass and Protocol values.Values outside of that defined spec are reserved. These class codes can only be used in Interface Descriptors.
Base Class
Smart Card device
This base class is defined for devices that conform to the Content Security Device Class Specification found on the USB-IF website. That specification defines the usable set of SubClass and Protocol values. Values outside of that defined spec are reserved.&These class codes can only be used in Interface Descriptors.
Base Class
Content Security device
This base class is defined for devices that conform to the Video Device Class Specification found on the USB-IF website.&That specification defines the usable set of SubClass and Protocol values.&Values outside of that defined spec are reserved.&These class codes can only be used in Interface Descriptors.
Base Class
Video device
This base class is defined for devices that conform to the Personal Healthcare Device Class Specification found on the USB-IF website.&That specification defines the usable set of SubClass and Protocol values.&Values outside of that defined spec are reserved.&These class codes should only be used in Interface Descriptors.
Base Class
Personal Healthcare device
&&The USB Audio/Video (AV) Device Class Definition describes the methods used to communicate with devices or functions embedded in composite devices that are used to manipulate audio, video, voice, and all image- and sound-related functionality. That specification defines the usable set of SubClass and Protocol values. Values outside of that defined spec are reserved. These class codes can only be used in Interface Descriptors.&&Base Class SubClass Protocol Meaning 10h01h&02h&03h&&00h Audio/Video Device ? AVControl Interface00h Audio/Video Device ? AVData Video Streaming Interface00h Audio/Video Device ? AVData Audio Streaming Interface&
Class 11h (Billboard Device)
This base class is
defined for devices that conform to the Billboard Device Class Specification
found on the USB-IF website. That specification defines the usable set of
SubClass and Protocol values. Values outside of that defined spec are reserved.
These class codes can only be used in Device Descriptors.
Base Class
Billboard Device
This base class is defined for devices that diagnostic devices. This class code can be used in Device or Interface Descriptors. Trace is a form of debugging where processor or system activity is made externally visible in real-time or stored and later retrieved for viewing by an applications developer, applications program, or, external equipment specializing observing system activity. Design for Debug or Test (Dfx). This refers to a logic block that provides debug or test support (E.g. via Test Access Port (TAP)). DvC:& Debug Capability on the USB device (Device Capability)&
Base Class
USB2 Compliance
Device.& Definition for this device can
be found at
Debug Target vendor
defined. Please see
for more info.
GNU Remote Debug
Command Set. Please see
for more info.
Vendor defined Trace protocol
Vendor defined Dfx
protocol on DbC.
Vendor defined Trace
protocol over General Purpose (GP) endpoint on DvC.
GNU Protocol protocol
over General Purpose (GP) endpoint on DvC.
Vendor defined Dfx
protocol on DvC.
Vendor defined Trace
protocol on DvC.
This base class is defined for devices that are Wireless controllers.&Values not shown in the table below are reserved. These class codes are to be used in Interface Descriptors, with the exception of the Bluetooth class code which can also be used in a Device Descriptor.
Base Class
Bluetooth Programming
Interface.& Get specific information from .
UWB Radio Control
Interface.& Definition for this is found in the Wireless USB
Specification in Chapter 8.
Remote NDIS.&
Information can be found at:
Bluetooth AMP
Controller. Get specific information from .
Host Wire Adapter
Control/Data interface.& Definition can be found in the Wireless USB
Specification in Chapter 8.
Device Wire Adapter
Control/Data interface.& Definition can be found in the Wireless USB
Specification in Chapter 8.
Device Wire Adapter Isochronous interface.& Definition can be found in the Wireless USB
Specification in Chapter 8.
This base class is defined for miscellaneous device definitions. Values not shown in the table below are reserved.& The use of these class codes (Device or Interface descriptor) are specifically annotated in each entry below.
Base Class
Active Sync
device. This class code can be used in either Device or Interface
Descriptors. Contact Microsoft for more information on this class.
Palm Sync. This class code can be used in either Device
or Interface Descriptors.
Association Descriptor. The usage of this class code triple is defined in the
Interface Association Descriptor ECN that is provided on . This class code may only be used in Device Descriptors.
Wire Adapter
Multifunction Peripheral programming interface. Definition can be found in
the Wireless USB Specification in Chapter 8. This class code may only be used
in Device Descriptors
Cable Based
Association Framework. This is defined in the Association Model addendum to
the Wireless USB specification. This class code may only be used in Interface
Descriptors.
RNDIS over
Connecting a
host to the Internet via Ethernet mobile device. The device appears to the
host as an Ethernet gateway device.
This class code
may only be used in Interface Descriptors.
RNDIS over WiFi.
Connecting a
host to the Internet via WiFi enabled mobile device.& The device represents itself to the host as
an 802.11 compliant network device.
This class code
may only be used in Interface Descriptors.
RNDIS over WiMAX
Connecting a
host to the Internet via WiMAX enabled mobile device.& The device is represented to the host as an
802.16 network device.
This class code
may only be used in Interface Descriptors.
RNDIS over WWAN
Connecting a
host to the Internet via a device using mobile broadband, i.e. WWAN
(GSM/CDMA).
This class code
may only be used in Interface Descriptors.
RNDIS for Raw
Connecting a
host to the Internet using raw IPv4 via non-Ethernet mobile device.& Devices that provide raw IPv4, not in an
Ethernet packet, may use this form to in lieu of other stock types.
This class code
may only be used in Interface Descriptors.
RNDIS for Raw
Connecting a
host to the Internet using raw IPv6 via non-Ethernet mobile device.& Devices that provide raw IPv6, not in an
Ethernet packet, may use this form to in lieu of other stock types.
This class code
may only be used in Interface Descriptors.
RNDIS for GPRS
Connecting a
host to the Internet over GPRS mobile device using the device?s cellular
USB3 Vision
Control Interface
Machine Vision
Device conforming to the USB3 Vision specification. This standard covers
cameras and other related devices that are typically used in machine vision,
industrial, and embedded applications.
Reference:
This class code
may only be used in Interface Descriptors.
USB3 Vision
Event Interface
USB3 Vision
Streaming Interface
STEP. Stream Transport Efficient Protocol for
content protection.
RAW. Stream Transport Efficient Protocol for Raw content protection.
Command Interface in IAD
The DVB Common Interface (DVB-CI)
specification describes a system whereby a removable CI Conditional Access
Module (CICAM), given the appropriate usage rights, unscrambles protected
pay-TV content and routes it over the same interface back to a TV receiver
for display. An interface association for a DVB-CI function will contain a
DVB-CI Command Interface for command, control, and status information, it may
contain a DVB-CI Media Interface for audiovisual data streams, and it may
also contain a CDC EEM interface to provide bridged networking to the CICAM.
Reference: https://www.dvb.org/standards/dvb-ci-plus
Command Interface in Interface Descriptor
Media Interface in Interface Descriptor
This base class is defined for devices that conform to several class specifications found on the USB-IF website.& That specification defines the usable set of SubClass and Protocol values.& Values outside of that defined spec are reserved.& These class codes can only be used in Interface Descriptors.
Base Class
Device Firmware Upgrade.& Device class definition provided on .
IRDA Bridge device.& Device class definition provided on .
USB Test and Measurement Device.& Definition provided in the USB Test and Measurement Class spec found on .
USB Test and Measurement Device conforming to the USBTMC USB488 Subclass Specification found on www.usb.org.
This base class is defined for vendors to use as they please.& These class codes can be used in both Device and Interface Descriptors.
Base Class
Vendor specific
Site sponsored by USB Implementers Forum, Inc., creators of USB technology.epoll_wait,
epoll_pwait
an I/O event on an epoll file
descriptor
#include &sys/epoll.h&
int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);
int epoll_pwait(int epfd, struct epoll_event *events,
int maxevents, int timeout,
const sigset_t *sigmask);
DESCRIPTION
The epoll_wait() system call waits for events on the
instance referred to by the file descriptor epfd.
The memory area
pointed to by events will contain the events that will be available
for the caller.
Up to maxevents are returned by epoll_wait().
maxevents argument must be greater than zero.
The timeout argument specifies the number of milliseconds that
epoll_wait() will block.
Time is measured against the
CLOCK_MONOTONIC clock.
The call will block until either:
a file descript
the call is interrupted or
the timeout expires.
Note that the timeout interval will be rounded up to the system clock
granularity, and kernel scheduling delays mean that the blocking
interval may overrun by a small amount.
Specifying a timeout of -1
causes epoll_wait() to block indefinitely, while specifying a timeout
equal to zero cause epoll_wait() to return immediately, even if no
events are available.
The struct epoll_event is defined as:
typedef union epoll_data {
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
/* Epoll events */
epoll_data_
/* User data variable */
The data field of each returned structure contains the same data as
was specified in the most recent call to
(EPOLL_CTL_ADD,
EPOLL_CTL_MOD) for the corresponding open file description.
events field contains the returned event bit field.
epoll_pwait()
The relationship between epoll_wait() and epoll_pwait() is analogous
to the relationship between
and : like
, epoll_pwait() allows an application to safely wait until
either a file descriptor becomes ready or until a signal is caught.
The following epoll_pwait() call:
ready = epoll_pwait(epfd, &events, maxevents, timeout, &sigmask);
is equivalent to atomically executing the following calls:
pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
ready = epoll_wait(epfd, &events, maxevents, timeout);
pthread_sigmask(SIG_SETMASK, &origmask, NULL);
The sigmask argument may be specified as NULL, in which case
epoll_pwait() is equivalent to epoll_wait().
RETURN VALUE
When successful, epoll_wait() returns the number of file descriptors
ready for the requested I/O, or zero if no file descriptor became
ready during the requested timeout milliseconds.
When an error
occurs, epoll_wait() returns -1 and
is set appropriately.
epfd is not a valid file descriptor.
EFAULT The memory area pointed to by events is not accessible with
write permissions.
The call was interrupted by a signal handler before either (1)
any of the requested events occurred or (2) the timeout
EINVAL epfd is not an epoll file descriptor, or maxevents is less
than or equal to zero.
epoll_wait() was added to the kernel in version 2.6.
Library support
is provided in glibc starting with version 2.3.2.
epoll_pwait() was added to Linux in kernel 2.6.19.
Library support
is provided in glibc starting with version 2.6.
CONFORMING TO
epoll_wait() is Linux-specific.
While one thread is blocked in a call to epoll_pwait(), it is
possible for another thread to add a file descriptor to the waited-
upon epoll instance.
If the new file descriptor becomes ready, it
will cause the epoll_wait() call to unblock.
For a discussion of what may happen if a file descriptor in an epoll
instance being monitored by epoll_wait() is closed in another thread,
In kernels before 2.6.37, a timeout value larger than approximately
LONG_MAX / HZ milliseconds is treated as -1 (i.e., infinity).
for example, on a system where sizeof(long) is 4 and the kernel HZ
value is 1000, this means that timeouts greater than 35.79 minutes
are treated as infinity.
C library/kernel differences
The raw epoll_pwait() system call has a sixth argument, size_t
sigsetsize, which specifies the size in bytes of the sigmask
The glibc epoll_pwait() wrapper function specifies this
argument as a fixed value (equal to sizeof(sigset_t)).
This page is part of release 4.15 of the Linux man-pages project.
description of the project, information about reporting bugs, and the
latest version of this page, can be found at
Pages that refer to this page:Frequently Asked Questions (FAQ) about C on the Microchip PIC
Frequently Asked Questions (FAQ) about C on the Microchip
These are questions which are frequently asked on various Microchip
and PIC-related forums which generally apply to the Hi-Tech C
compilers (now known as XC8) and the MPLAB C18 compiler.
these are just general C questions that have nothing in particular to
do with PICs or any specific compiler, and some are general PIC
questions.
What's the best way to get forum help with a code
Create a minimal, self-contained example that demonstrates the
It should be a single C file -- no header files unless the
problem specifically involves header files, and no
external dependencies so that anyone can compile it.
Remove any code
(including commented-out code) that is not related to the problem.
Use standard C types like
char and int, not typedefs like DWORD or UINT8.
Include your
configuration fuse settings in the code.
If the code compiles and
runs, test the code in the
simulator to confirm that it exhibits the problem.
Attach the C file
to your forum post.
Tell us which PIC you're using.
Tell us which compiler you're using.
Tell us which version of the compiler you're using.
Tell us about any non-standard build options you're using
(large memory model, large stack model, modified linker file,
Tell us if it's a lite or student version of
the compiler.
If it's a Hi-Tech/XC8 compiler, tell us if you're using PRO or
Cut and paste any error messages into your post.
Type code into the forum.
Cut and paste code into the forum.
Put the code into your message with code tags.
Show an example of the problem.
How can I remap a group of pins on different ports into a single
structure?
If you have pins scattered on different ports or pins that are
not in the desired order on one port, and you're hoping to
define something that lets you do lcd.data = 42, you
C places all of the members of a structure in address
C does not support the concept of writing to
scattered memory addresses in a single operation.
There is no simple or clean mechanism to logically rearrange
port pins.
The most straightforward technique is to write a
function that encapsulates the necessary operations on the
port pins.
See the following three questions for further
discussion.
How can I make an array of port pins?
How can I declare a pointer to a port pin?
You can't.
The C language does not permit taking the address of a bit or of
a bit-field member of a structure.
This means you can't have pointers to bits or arrays of bits,
whether or not they're port pins.
How can I pass a port pin as an argument to a
You can't, because you can't take the address of a port pin (refer
to the previous question).
You can pass the value of a
port pin to a function just like any other integer, but the
function won't be able to modify the port pin.
You can pass a reference to a port pin as an argument
to a function, or
make an array of port pin references, by
using the address of the port (not the pin)
and an identifier for the pin.
void set_port_pin(volatile unsigned char *port, unsigned char pin) {
*port |= 1U <<
set_port_pin(&LATA, 7);
This will set RA7 to 1.
Refer to your compiler's header file for
the correct type to use for port.
Note that this type of code is grossly inefficient on a PIC, and
will use far more code space and execution time than simply
setting the pin value directly or through a macro, which is the
preferred solution.
If you need a further layer of abstraction that lets you refer to
the ports themselves indirectly (e.g., a PC program that sends
commands controlling the state of arbitrary port bits), place the port
addresses in an array:
volatile unsigned char * const lats[] =
/* an enum that defines indices into the ports array */
MY_LATA = 0,
MY_LATB = 1,
MY_LATC = 2
void set_port_pin(unsigned char port, unsigned char pin) {
*ports[port] |= 1U <<
set_port_pin(MY_LATB, 5);
Why am I getting a syntax error when I use a
You probably have a semicolon at the end of your #define.
#define is not a statement, and does not end in a semicolon.
#define just does si if you have a
semicolon in your #define text, the preprocessor will insert
that semicolon into your C code, possibly in a place where a
semicolon is a syntax error.
What do these MPLAB C18 warnings mean?
When compiling code that assigns pointers or passes them as
function arguments, C18 tends to provide spurious warnings
on valid code, or worse, fails to provide warnings on
invalid code.
These are the most commonly encountered
issues with C18 pointer warnings:
type qualifier mismatch in assignment
This means that an assignment (or passing an argument to a
function) attempted to add, remove, or modify a qualifier.
In C18, the qualifiers are const, volatile, rom, ram, near,
The most common source of this warning is mismatching a near
and far qualifier on a call to a C library function.
example, a call to printf() will usually elicit this
If you are compiling with the default (small)
memory model, the format string argument to
printf() is qualified as "near rom", while the printf()
function was actually compiled with the large memory model
which uses "far rom" pointers,
resulting in the qualifier mismatch.
In this particular case, the warning is
spurious, because the compiler simply converts the 16-bit
near pointer to a 24-bit far pointer, and everything
works as expected.
The warning can be suppressed by
adding a (const far rom char *) cast to the format
string, or by compiling with the large memory model, or
by recompiling the C library with the small memory model.
In other cases, this warning probably indicates an
error in your code, though bugs in the compiler cause
it to elicit this warning on certain valid
code sequences, such as:
const void *
suspicious pointer conversion
This is generally caused by a sign mismatch in a pointer
assignment or function call.
A common cause is using
unsigned char for strings (strings are char, not unsigned
char). For example:
void func(char *string);
unsigned char data[10];
func(data);
Another common cause is passing a pointer to an incompatible type,
to a plain
rom unsigned char array[2][3];
void func(rom unsigned char *ptr);
func(array);
or passing an integer to a function expecting a pointer:
void func(int *ptr);
func(foo);
This warning can also be elicited by valid code, such as:
unsigned char *
memcpy(vp, ccp, 0);
To work around this bug, simply cast ccp to the type that memcpy()
memcpy(vp, (const void *)ccp, 0);
A cleaner, safer solution is to wrap function calls that trigger
spurious warning in macros:
#define memcpy(a,b,c)
memcpy((a),(const void*)(b),(c))
#define memcmp(a,b,c)
memcmp((const void*)(a),(const void*)(b),(c))
#define strcpy(a,b)
strcpy((char*)(a),(const char*)(b))
Of course these casts, like any casts, can mask errors in your
But C18 gives you the unfortunate choice between casting and
having warnings for valid code.
type mismatch in assignment
This generally means an error in your code, such as:
b = 0x1234;
It can also be elicited by valid code such as:
const void *
Why am I getting a syntax error on a declaration in this
simple code?
void main(void)
Because most PIC C compilers support the C90 standard, which does not
permit mixing statements and declarations.
This feature was added to
the C99 standard.
C90 requires that all declarations appear at the
beginning of a block.
How can I save a float, int, double, long, array, or structure to
void eeprom_write_block(void *ptr, unsigned short addr, unsigned char len)
unsigned char *data =
while (len--)
eeprom_write_byte(addr++, *data++);
/* examples of usage: */
struct { }
unsigned char array[10];
eeprom_write_block(&s, 10, sizeof s);
eeprom_write_block(&c, 20, sizeof c);
eeprom_write_block(&d, 30, sizeof d);
eeprom_write_block(array, 40, sizeof array);
Note that this code takes advantage of C's void type to eliminate
casting or the need for different functions for saving different
A similar method is used to read:
void eeprom_read_block(void *ptr, unsigned short addr, unsigned char len)
unsigned char *data =
while (len--)
*data++ = eeprom_read_byte(addr++);
These routines assume you have a routine that can read and write byte
to your EEPROM.
How can I share a global struct or other type among different C
In globals.h:
/* declare an int */
extern int global_
/* declare a struct type */
struct tag {
/* declare a struct */
extern struct tag global_
/* declare a string that's initialized elsewhere */
extern const char string[];
In globals.c:
#include globals.h
/* define the int */
int global_
/* define the struct */
struct tag global_
/* define the string */
const char string[] = "Hello, world.";
In main.c:
#include globals.h
#include &stdio.h&
void main(void)
/* use the globals */
global_struct.b = 42;
global_int = 0x4242;
printf("%s\n", string);
How can I find what's causing the weird behavior in my
MPLAB C18 program?
Some common causes of strange behavior:
C18's interrupt declaration scheme is extremely error prone,
and none of the errors described below will result in a
compiler diagnostic.
Interrupt declaration errors are one of the most
common causes of weird behavior.
Erroneous interrupt
declarations can appear to work correctly, but then subsequently fail when
modifying other parts of the code, upgrading the compiler, or moving to a different processor.
Ensure you haven't mixed up
#pragma code addresses, or interrupt
vs. interruptlow keywords, or defined a low-priority interrupt
with #pragma interrupt, or enabled low-priority interrupts with
only a high-priority handler, or vice versa, or omitted the
necessary #pragma code and #pragma interrupt statements, or
configured a specific interrupt at one priority with the code that
handles it defined at the other priority.
If you're using assembly
language springboard functions, ensure these are actually present
in your code.
Spending too much time in the ISR
Don't use delays, write to slow peripherals like LCDs, write to
EEPROM, or perform other time-consuming tasks in the ISR.
If you have an
interrupt that occurs more quickly than one of these tasks, your
application never gets out of the ISR and your main code never runs.
Manipulating GIE and/or GIEL in the interrupt handler.
enabled and disabled automatically by the PIC; enabling them in the
ISR can cause unexpected reentrancy.
Inappropriate modifications to the linker file
If you've modified the linker file to create an object larger than
256 bytes, make sure you've followed all of the instructions
, especially the part about accessing the object
through a pointer.
Writing past the end of an array
Writing through an uninitialized pointer
Not using the c018iz variant of the startup code
when standard C zeroing behavior is expected.
Not compiling with the large memory model on a 128K PIC
Using a PIC with the fast interrupt errata
The easiest workaround for this errata is to use the interruptlow
keyword on the high-priority interrupt.
Compiling for extended mode with the PIC configured in standard
mode, or vice versa.
How can I debug a software stack overflow in MPLAB
Start by reading about how the software stack is implemented in the
Calling Conventions chapter of the user's guide.
Generally, PICs with at least 512 bytes of RAM have a 256 byte
stack by default, and PICs with less RAM have a 64 byte stack by
Check your PIC's generic linker file in bin/LKR to
see how large the stack is and where it's located.
Look for large objects that use stack space.
Things that are
allocated on the stack include function arguments and local
variables in functions which do not have the static or
rom qualifiers.
Identify large structures and arrays and
move them off of the stack by making them static or
global, or pass a pointer to the object rather than passing the entire
Some library functions, such as the
printf() family, can use more than 64 bytes of stack space, which
alone can blow the stack on parts with 64 bytes of stack space.
If you're still getting a stack overflow, here are some
techniques to find it:
Set a breakpoint at the
beginning of your program.
When you hit the
breakpoint, fill the stack with a known value, such as
This can be done in MPLAB IDE by opening the
File Registers window, right clicking, and selecting
Fill Registers.
Let your program continue running
until it starts misbehaving.
Stop your program and
inspect the stack area in the File R if
all of your known values have been overwritten, you
know you have a stack overflow.
Set a complex breakpoint on the last memory address of
the stack.
This will cause the debugger to halt at the
point of the stack overflow.
To set a complex breakpoint
in the MPLAB IDE Simulator, select Debugger... Complex
Breakpoints... Add Breakpoint... Data Memory.
last address of the stack memory (for example, if your 256
byte stack is at 0x100, enter 0x1FF), and ensure the
breakpoint type is Write.
Other debuggers might
have slightly different methods for creating a complex
breakpoint (or may not support complex breakpoints).
Since FSR1 is the stack pointer, you can inspect it at
various points in your program to see how much stack has been
What is the best way to declare a C18 interrupt service routine
#pragma code isr=0x08
#pragma interrupt isr
/* interrupt handling code here */
#pragma code
This avoids the assembly language springboard function which
wastes code space
increases interrupt latency
This technique can generally only be used when not using interrupt
priorities, which are generally .
If you need interrupt priorities, this is how to declare the two
interrupt handlers:
#pragma interrupt high_isr
high_isr(void)
/* high priority interrupt handling code here */
#pragma interruptlow low_isr
low_isr(void)
/* low priority interrupt handling code here */
#pragma code high_vector=0x08
high_vector(void)
_asm GOTO high_isr _endasm
#pragma code low_vector=0x18
low_vector(void)
_asm GOTO low_isr _endasm
#pragma code
Yes, you really need five pragmas and four functions to declare two
ISRs in C18.
And because the vectors have to be defined as functions,
there will be a wasted RETURN instruction in each of them -- C18 isn't
smart enough to optimize the RETURNs out.
Should I use interrupt priorities on the PIC18?
Probably not.
By default (IPEN = 0), the PIC18's interrupts operate
in PIC16 compatibility mode.
This means there is a single interrupt
vector at address 0x08, and no interrupts will vector to address 0x18.
Even in compatibility mode, interrupts take advantage of the fast
register stack, which makes zero-cycle context save/restore possible,
so there is no inherent disadvantage to using compatibility mode.
disadvantages to using interrupt priorities are many:
More interrupt setup code
More complex ISR declaration
Higher latency for high-priority interrupts due to the
necessary springboard GOTO
Much higher latency for low-priority interrupts since they
can't use the fast register stack
Increased code space usage due to all of the above.
More hardware and software stack space is required.
Even ignoring the disadvantages of interrupt priorities, few
applications actually need them to perform correctly.
A well-written
interrupt handler can process all of its interrupts quickly enough to
prevent any interrupts from being lost.
A typical example of a situation that needs interrupt priorities is
high-speed clock coming in on an INT pin that has very tight timing
requirements.
In such a case, it makes sense to enable interrupt
priorities, and configure the INT interrupt as the only
high-priority interrupt.
Using multiple high-priority interrupts is
not much different than using compatibility mode, and thus is generally
pointless.
Why is my C18 interrupt behaving strangely or not running as
fast as I expect?
The most common cause is calling a function from the interrupt handler.
C18, calling a function from the interrupt handler triggers a
worst-case context save.
This results in interrupt latency of 50
instruction cycles or more, and total interrupt context save/restore
overhead of 100 cycles or more.
This makes high-speed interrupts
impossible.
Note that the worst-case context save occurs even if the called
function has no parameters or local variables, or even if the function
is never actually called.
The mere presence of a function call
statement in the ISR triggers the worst-case scenario on every
interrupt.
The easiest solution to this is simply not to call any functions from
the interrupt handler, which will give best-case context saving.
There is a more
involved solution available if you absolutely must call
functions from the ISR ().
Other possible causes are listed
When should I use volatile?
The volatile qualifier originates with the as-if rule in C:
In the abstract machine, all expressions are evaluated as specified
by the semantics. An actual implementation need not evaluate part of
an expression if it can deduce that its value is not used and that no
needed side effects are produced (including any caused by calling a
function or accessing a volatile object).
The critical part here is, An actual implementation need not evaluate
part of an expression if it can deduce that its value is not used.
For example,
PORTA = 1;
for (i = 0; i < 10; i++)
PORTA = 2;
Your expectation might be that 1 would be written to PORTA, then a
delay, then 2 would be written to PORTA.
But the compiler is free to
just do PORTA = 2, or even to generate no code at all.
because a compiler can look at the code and realize there are no
needed side effects from assigning 1 to PORTA or from the loop.
But PORTA works as expected because it is declared as volatile in the
compiler' every operation on PORTA must be carried out
exactly as stated by the programmer:
An object that has volatile-qualified type may be
modified in ways
unknown to the implementation or have other unknown side effects.
Therefore any expression referring to such an object shall be
evaluated strictly according to the rules of the abstract
volatile tells the compiler to do exactly what the programmer said to do.
To correct the code fragment above, i must also be volatile to
ensure the delay loop is executed exactly as stated.
volatile is also relevant in interrupt handlers in cases like this:
int interrupt_
int main(void) {
interrupt_flag = 0;
while (interrupt_flag == 0)
/* wait for interrupt */
/* do stuff */
The compiler can look at that code and realize that interrupt_flag is
0, and will always remain 0, so there is no need for it to generate
any code at all for main(), even though you might have an interrupt
handler somewhere that sets interrupt_flag to 1.
The solution is to
make interrupt_flag volatile, so that the compiler understands that it
may be modified in ways unknown to the implementation.
Note that volatile does not provide atomic access.
previous example, it will take multiple CPU instructions to compare
interrupt_flag against 0 on an eight-bit processor.
The volatile
keyword does not prevent an interrupt from occurring in the middle of
this sequence of instructions, which means interrupt_flag may take on
an unexpected value with a properly timed interrupt.
Atomic access
requires additional protection, such as disabling interrupts around
the comparison.
Should I just make everything volatile to be safe?
With a modern C compiler, you have to forget about the idea that
the compiler is going to blindly follow your instructions step by
You have to think in terms of what side effects your program
generates.
In an embedded program, side effects are almost
exclusively caused by reading or writing the processor's special
function registers.
If you're blinking an LED, sending data over a
UART, or writing to internal EEPROM, you are accessing a special
register that is declared as volatile, so all of these things are
guaranteed to happen.
But other concepts, like assigning a value to a
variable, or the passage of time caused by a delay loop, are not side
For example:
int main(void)
PORTA = a +
The only side effect in this program is writing 5 to PORTA.
PORTA is volatile, we are guaranteed that will happen.
What we aren't
guaranteed is that some memory location called a will have the
value 1 written to it, or that the processor's multiply instruction
will be used in calculating the value to be written to PORTA.
compiler is smart enough to replace the above with
int main(void)
PORTA = 5;
we've achieved the same result with less code space and faster
execution time.
There is one situation where you'd want to declare a and
b volatile in the above code:
when you're debugging.
If your compiler is smart enough to optimize all of the assignments
away, you won't be able to step through the assignments in the
debugger to make sure they're working the way you want.
volatile keyword temporarily during debugging can work around this, as
can choosing a lower optimization level during debugging.
I just upgraded C18 and there's no linker script for my
processor?
Recent versions of C18 (after 3.20 or so) include a slightly more
powerful linker which does not require including a linker script in
your project.
The linker now has a single generic linker
script per processor type, which can be used to build a
standard, extended mode, or ICD the IDE passes options to
the linker describing the build type and processor type, and the linker
chooses the appropriate script automatically.
If you have a non-standard requirement like a bootloader, you can
still include a linker script in your project.
The generic linker
scripts are located in the bin/LKR subdirectory of the compiler.
How can I pass a pointer to a two-dimensional array to a
function, or declare a pointer to a two-dimensional array?
With a two-dimensional array, the compiler needs to know how many
elements are in a column to move from one row to the next, but
movement within a row is always by a single element, so the compiler
doesn't need to know the number of rows.
Thus the pointer declaration
must include the number of columns in the array:
char array[2][3] = { "19", "42" };
void func(char (*p)[3])
puts(p[1]);
// prints "42"
func(array);
char (*p)[3];
What is Fosc?
How is Fosc related to the clock speed?
Does the PLL change Fosc?
Fosc is a term that's not used consistently throughout the data
When you're looking at the electrical specifications, Fosc means the
actual frequency of the external (or internal) clock.
When you're looking at the configuration bits, Fosc means the type of
the oscillator (e.g., XT, HS), which isn't related to the clock speed at all.
When you're looking at something that affects software, such as the
equations for setting up the PWM or UART or I2C baud rate, Fosc means
the CPU clock speed, which might or might not be the same as the
oscillator speed.
The CPU clock speed is the
oscillator speed scaled up or down by the chain of oscillator dividers
and multipliers.
For example, if you're using a PIC with a 4 MHz
external oscillator and no PLL, Fosc is 4 MHz.
If you're using a PIC
with an 8 MHz internal oscillator and a 4x PLL, Fosc is 32 MHz.
is the instruction clock, which is Fosc / 4 on an 8-bit PIC (each
instruction takes four clock cycles).
Why does the UART suddenly stop receiving data?
Transmit still
You are getting overrun errors.
An overrun error occurs when the
UART's receive FIFO is full, and another byte of data arrives.
this happens, the UART turns off its receiver, and sets the OERR bit.
The OERR bit is read-only and cannot be cleared in software.
restart the UART and clear OERR, it is necessary to clear and then set
Overrun errors are caused by software bugs.
Unlike framing errors,
they are not caused by noise, baud rate mismatches, or other external
Contrary to popular belief, you do not
need to check for overrun errors in your software.
Overrun errors are
not possible in correctly-written software.
To avoid overruns, receive serial data in an interrupt, not in a busy
loop, and ensure your interrupt handler has .
Why is my port pin not behaving the way I expect?
Most likely because you haven't disabled the analog features on the
When a pin is attached to the A/D converter, it will default to
analog mode.
Such pins are generally labeled as ANxx.
Pins on PORTA
are almost always analog, while pins on other ports might also be
Some 18F PICs, such as the 18F4550 family, have analog pins
on PORTB, but these pins can sometimes be made to default to
digital with one of the configuration words.
Some PICs also have comparators that default to enabled and
need to be disabled to allow use of their pins in digital mode.
When a pin is in analog mode, a digital read from the port will always return
The pin will still work as a digital output, but because the pin
reads 0, it will be particularly susceptible to read-modify-write
Consult the A/D converter chapter of your data sheet on how to disable
analog features.
There Microchip has used a wide
variety of techniques in different PIC families.
Note that simply
turning off the A/D con each analog pin must be
configured for digital use.
If you have disabled analog features and are still not seeing the
expected behavior, it might be the .
Can I sleep in an ISR?
When an interrupt occurs on a PIC, two things happen:
The program counter is pushed on the stack
The PIC branches to the interrupt vector address.
That's it.
The PIC does not store any internal state indicating
that it's in an ISR; it continues executing code exactly the
same way as it did before it entered the ISR.
The ISR is purely a
software concept that the PIC knows nothing about.
This means you
can execute a SLEEP instruction or do anything else in an ISR that
you could do in your non-ISR code.
Whether sleeping in the ISR is
a good idea or not depends on the application.
With C18, how can I place some data at a specific address in ROM without
using a linker script?
Use #pragma romdata.
For example:
#pragma romdata mac_addr=0x800
rom unsigned char mac_addr[] = { 1, 2, 3, 4, 5, 6 };
#pragma romdata
Why am I getting a syntax error at the end of my header file?
Because the file doesn't end in a newline.
What do the different MPLAB C18 memory
models do?
They do not make more RAM or ROM available.
not fix a can not fit the section error, or any other
compiler or linker error.
The default model is the small model (MPLAB IDE refers to this as the
small code model).
This should be used on any PIC
with 64KB or less of program memory.
The large model should be enabled when using a PIC with more than 64KB
of program memory.
The only effect the large model has is to
make pointers to rom 24 bits instead of 16 bits.
If you don't
use the large model on a PIC with more than 64KB, the code will
compile and link successfully, but if you have pointers to any objects
at addresses above 64K, accesses to those objects will fail, since a
16-bit pointer can't point at an address above 64K.
The large model increases the amount of code space used since the
larger pointers have more overhead.
MPLAB IDE also incorrectly refers to a data model option.
does n this option refers to an optimization that
places all data in the access bank (small data model).
default, C18 uses all available banked RAM (large data model).
While certain unusual applications that use very little RAM could
benefit from this optimization, it should normally be at the default
(off) setting.
What is read-modify-write (RMW)?
Consider the following code:
A reasonable compiler will generate a BSF (bit set file register)
instruction for each of these C statements.
The BSF instruction does
not simply set the value of a single bit.
Internally, the PIC
reads all eight bits from the port, sets the desired bit, and writes
all eight bits back out to the port.
For a single BSF instruction by
itself, this doesn't cause an issue.
But when two BSFs on the same
port happen back-to-back, the first BSF may not work as expected.
The problem occurs when the second BSF reads back the state of the
If the voltage on RB0 has not yet risen to the level the PIC
considers a logic 1 (Vih), the PIC will read back a 0 for RB0, set bit
1 for RB1, and write the result back out to the port.
This leaves RB0
at 0, and RB1 at 1, which is not the desired result.
RMW can become more of an issue with higher PIC clock frequencies,
because the amount of time between instructions is smaller, requiring
the port output to have a faster rise time to avoid being read back in
the wrong state.
There are several different fixes for the RMW these are listed
in order of best to worst:
On the PIC18, PIC24/dsPIC, and enhanced midrange parts
(PIC16F1xxx, PIC12F1xxx, PIC10F3xx), port latch registers are available.
Reading from a latch register does not read back the state of the port pins,
so BSF instructions can safely be used back-to-back.
PICs, all writes should be done to these LAT registers, and all
reads from the PORT registers.
Never write to the PORT registers.
If using a baseline or standard midrange part (PIC10/12/16
parts other than those listed above), first ensure that all analog
features have been disabled on the pins in question.
read of an analog pin is always zero, so trying to set two analog
pins high will always result in the first one being set back
Note that disabling the A/D converter does not
disable the analog
look for registers like
CMCON, ANSEL, ANSELA, etc.
If the problem persists, use a shadow register for the port.
For example:
unsigned RB0:1;
unsigned RB1:1;
unsigned RB2:1;
unsigned RB3:1;
unsigned RB4:1;
unsigned RB5:1;
unsigned RB6:1;
unsigned RB7:1;
portb.bits.RB0 = 1;
portb.bits.RB1 = 1;
PORTB = portb.
With the shadow register, the write to the actual port is a full eight
bits (no BSF instructions are used), so there is no RMW issue.
Insert a delay between writing to each port pin.
This gives the port
pin time to reach Vih so that its state will be read back correctly on
the next BSF.
The problem with this approach is that it's not trivial
to determine how much of a delay is necessary, and changes made down
the road to the PIC's clock speed or board layout can cause RMW issues to
unexpectedly reappear.
Section 9.10.2 of the
additional discussion and timing diagrams that explain what happens in
each clock cycle.
Why does the PIC's flash and/or EEPROM
get erased, have all FFs, or contain corrupted values when powering the PIC on or off?
Because the PIC is browning out:
operating at a voltage below the
allowed minimum.
The brownout itself does not cause flash or EEPROM
corruption, but when the PIC is in brownout, it is
operating in an undefined state.
This means that the program counter
can take on a random value which will cause random code to be
Murphy's Law says that the most likely place for this
random code execution to occur is in your flash or EEPROM write
The fix is to prevent the PIC from browning out.
This can be done
with an external supervisor chip such as the MCP100, or by enabling
the PIC's brownout reset feature.
If you use the PIC's brownout
reset, ensure that you select a reset voltage that is within the PIC's
rated operating range.
Some PICs, especially those that come in
low-voltage variants, have a wide range of BOR voltage options,
some of which will not actually protect against brownout.
Brownout cannot be worked around in software.
How does the PORTB change interrupt work?
How can I tell which pin caused the PORTB interrupt?
How can I clear the RBIF flag?
When the PORTB change interrupt is enabled, the PIC continuously
compares the value on each of the PORTB change pins with the the last
PORTB values read by your software.
When the current pin value of any
pin doesn't match the last read value, RBIF is set.
On many PICs, the PIC does not keep track of which pin change set RBIF
(enhanced midrange parts are the exception); this has to be determined
in software.
One common method is to XOR the current PORTB value with
the previous value:
if (RBIF) {
unsigned char changes,
static unsigned char last_
portb = PORTB;
changes = portb ^ last_
last_portb =
/* process the bits in "changes" */
This code leaves a bit set in changes for each pin that changed
Note that the RBIF flag is cleared after reading the value of
Reading PORTB updates the PIC's change-detection
latch with the current value of PORTB so that it no longer sees a
mismatch between the current pin state and the last-read state.
long as this mismatch condition is present, RBIF cannot be
The PORTB change interrupt has a
major design error in may PICs and is not
recommend for use as a general-purpose interrupt.
It should only be
used as a wake-from-sleep source.
What does higher order function calls not supported yet in the
presence of the overlay storage class mean?
C18 does not permit using function pointers while compiling in the
overlay mode.
If you want to use function pointers, don't
compile in overlay mode (-sco) or don't use the overlay
The not supported yet in the error me they
will not ever be supported, since C18 development has been halted.
Where can I find the settings for the
MPLAB C18 #pragma config directive?
In MPLAB 8 IDE, look under Help...Topics...PIC18 Config
In MPLAB X IDE, look under Help...Help
Contents...C18 Toolchain...C18 Configuration Settings.
Another option is to run the compiler from the command line:
mcc18 --help-config -p=18f87k22 | more
Note the the configuration settings are built in to the compiler and
are not in the processor's header file.
Why am I getting a syntax error on my
#pragma config FOSC = ... directive?
Because you have a #define FOSC ..." directive somewhere in your code.
How can I fix an undefined symbol:
_putch error when using printf() with a Hi-Tech/XC8 compiler?
Hi-Tech's printf() does not send its output to any particular
device by default.
It calls putch() for that purpose, and you must
provide an implementation of putch() that sends the output where
This can be a UART, LCD, etc.
A simple implementation
that sends the output to the UART is:
putch(char c)
while (!TXIF)
printf() does not initialize the UART o you must
do that yourself.
Why does a simple function return an
incorrect value in MPLAB C18?
Because there is no function prototype in scope at the point the
function is called.
This means C18 assumes the return value of the
function is int (this is standard C behavior), and if the return value isn't actually
int, you'll get garbage as the return value.
C18 has an interesting rather than passing
all return values on the stack, it uses different registers depending on
the type of the return value.
So the garbage value that's returned probably
won't even be related the correct return value at all.
How can I combine two bytes into an
There are several different ways to do this.
The best way is to
use shifting:
unsigned int i
unsigned char a,
i = (a << 8) |
This creates an int with a as the most significant byte
and b as the least significant byte (LSB).
This has two major
advantages over other approaches:
You can easily tell which byte is
the MSB by looking at the code.
This code does the same thing on
any standard C compiler or any processor.
On the surface, this code might appear to be inefficient since it
involves shifting the MSB eight bits -- an especially bad idea on a
But because of C's
rule, this code does not have to be interpreted
literally by the compiler.
Any reasonable compiler will recognize
this common idiom and simply assign a to the upper byte of
If you're using MPLAB C18 in its default non-standard mode
(integer promotions disabled), the above code won't work, because C18
doesn't convert a to an int as standard C requires.
can either enable integer promotions, or add a cast:
i = ((unsigned int)a << 8) |
There are two additional approaches:
Use a union:
unsigned char a,
u.byte.a = 42;
u.byte.b = 24;
// u.i now contains a and b assembled into an int
This approach has several problems:
It isn't obvious which byte is the MSB and which is the LSB.
You can call one byte lsb and the other msb,
but you have to read the
compiler's implementation details to know which is which.
On different compilers and processors, which byte is the MSB
will vary.
The code will compile, but will give incorrect
Writing into one member of a union and reading from a different
member is implementation defined behavior in C.
This means
that you have to read the compiler's implementation documentation
to determine whether this approach will even work.
Use a pointer:
unsigned char buff[2];
buff[0] = 42;
buff[1] = 24;
i = *(unsigned int*)
As well as being the least readable, this approach suffers from some of the same problems as the union
It isn't obvious which byte in buff is the MSB and which is the LSB.
On different compilers and processors, which byte is the MSB
will vary.
How can I split an integer into two bytes?
unsigned int i
unsigned char a,
a = (i >> 8) & 0xFF;
b = i & 0xFF;
Just like the code to , this code does
exactly the same thing on any compiler and processor, and it's obvious
which byte is the LSB (b) and which is the MSB (a).
The union and pointer
approaches described in that link can also be used for this task, but they
suffer from the same disadvantages.
Why am I getting call of function
without prototype even though I have a prototype?
Because you really don't have a prototype.
You might have something like
void func();
which is not a function prototype.
C requires that a function prototype
specify the number and types of the function's parameters.
are no parameters, void must be explicitly specified:
void func(void);
What does can't find 0x108 words (0x108 withtotal) for psect
bss in segment RAM mean?
Hi-Tech's STD compilers for the PIC18 sometimes require a certain
amount of manual memory management
(this is not true with the PRO
compilers or XC8 compilers).
Here is some background and a
workaround for the error:
Given these qualifiers:
uninitialized
static storage duration (at file scope and/or using
the static keyword)
type char (including arrays)
size greater than 256 bytes
If an object is ((1 and 2 and 3) or (1 and 2 and 4)), it is
placed in the bigbss psect.
Any remaining objects which are
(1 and 2) are placed in a bss psect.
Each C module has one bss psect of at most 256 bytes.
each module can have no more than a total of 256 bytes of bss
this restriction may require moving objects into separate
E.g., two int[65] arrays could not appear in one
module, because their total size is 260 bytes, and they do not
meet the requirements that would place them in the bigbss
But if each array is placed in a separate .c file, the
program should build successfully.
Another restriction is that a bss psect cannot straddle a bank boundary.
Thus e.g. a PIC
with 512 bytes of RAM could not have three int[65] arrays,
even in separate modules.
Even though their total size is
only 390 bytes, there is no way to place them without
straddling banks.
Objects in bigbss can straddle banks, and
do not have per-module size restrictions.
But there is no way
to force an object into bigbss.
If your error relates to the data psect (initialized
data) rather than a bss psect, the above workaround doesn't
The compiler has a hard limit of 256 bytes for the entire
program's data psect.
The workarounds for this issue are:
Replace initialized data with data that's assigned initial
values at runtime.
Make initialized data const where possible.
Wrap initialized data in a super- a single
initialized
object that's larger than 256 bytes will be placed in a
bigdata psect.
What does stack frame too large mean?
MPLAB C18 has a limitation on how much stack data can be accessed in
a single frame (one function). This is about 120 bytes in standard
mode and about 95 bytes in extended mode. This limitation cannot be
overcome by increasing the stack size.
One workaround is to make any
large auto objects in the function static, which takes them off
the stack.
Why is the Hi-Tech/XC8 compiler issuing
variable 'x' is not used warnings even though the variables
are being used?
This warning might be more clear if it
stated that the variable's value is not used.
As was noted in the discussion of the
keyword, the compiler
is only looking for the side effects caused by your program.
effects are limited to reads and writes to the processor's volatile special
function registers.
Any other code that doesn't cause side effects
may be optimized away, resulting in unexpected warnings.
For example, given this code:
void main(void)
unsigned char a,
PICC-18 9.80 will warn that b is not used and that the b =
a assignment generates no code.
Looking at the list file, no code
is generated for main().
This is because the program has no
side effects (it does not write to any volatile special function
registers), so the compiler is permitted to optimize the entire program
Even though b is assigned to and appears to be
used in the code, its value is never used, so there is no
reason to generate code for it.
Now consider this code:
void main(void)
unsigned char a,
This compiles with no warnings, because the value of b is used
to write to PORTA, which is a volatile object that causes side
However, if you look at the list file, you'll see that
compiler still didn't blindly follow the code:
t.c: 71: PORTA =
3968,volatile
All of the references to a and b have been removed, and
the compiler correctly generates code only for the necessary side
loading 1 into PORTA.
What does 'The Extended CPU Mode
configuration bit is enabled, but the program was not built
using extended CPU instructions.' mean?
Newer PIC18s have a feature called the extended instruction set.
When this feature is enabled, it adds some new instructions and
changes the behavior of many existing instructions.
This feature
was added in an attempt to reduce the code size generated by the
C18 compiler.
While it did succeed in that goal, Microchip has
deprecated the C18 compiler, and now supports only the XC8 compiler
for 8-bit PICs.
XC8 does not support the extended instruction set,
and probably never will, meaning the extended instruction set is
effectively obsolete.
The extended instruction set is enabled/disabled with the
configuration fuse bit XINST, which may be enabled by default on
certain PICs.
As a consequence, if XINST is not explicitly disabled,
the PIC will operate in extended mode.
Non-extended code running in
extended mode will have various 'weird' behaviors that will depend on
various factors, such as where the compiler happens to place objects
With XC8, extended mode should always be disabled with
#pragma config XINST = OFF
If you are using the free/lite/academic version of C18, it also does
not support the extended instruction set, and it should be disabled as
shown above.
Only the paid version of C18 supports the extended
instruction set.
When the extended instruction set is enabled, it is
also necessary to provide the --extended command-line option (or the
equivalent in the IDE) to enable the generation of the appropriate
Why is the preprocessor calculating an
incorrect value?
The preprocessor doesn't evaluate expressions in C
it simply replaces macro(s) with their associated text.
compiler evaluates the resulting replaced text.
There are two common errors when using the preprocessor to insert
numeric expressions into code:
Integer overflow:
#define SECONDS_PER_DAY
(60 * 60 * 24)
long week = SECONDS_PER_DAY * 7;
This expands to:
long week = (60 * 60 * 24) * 7;
The expected result is 604800, which fits easily into a
long, but the actual result is something else.
This is because the
expression 60 * 60 * 24 is 86400, which does not fit into a 16-bit
int, and thus overflows giving a garbage value.
The fact that the
result is being assigned to a long isn' 60 and 24 are ints,
so the multiplication is done with int arithmetic.
Use 60L to force
long arithmetic.
Note that MPLAB C18 has integer promotions disabled by default, which
means expressions may be evaluated with char arithmetic, making
overflows even more likely.
You can enable integer promotions to
get standard C behavior.
Missing parentheses:
#define CATS
#define DOGS
#define ANIMALS
CATS + DOGS
int pairs = ANIMALS / 2;
This expands to:
int pairs = 2 + 42 / 2;
giving the unexpected result 23 instead of 22.
Since the preprocessor
does simple text substitution, ANIMAL is not any sort of
variable, and doesn't get any special treatment when the
compiler evaluates it.
C's precedence rules cause the unexpected
The fix is to always enclose expressions in parentheses:
#define ANIMALS
(CATS + DOGS)
int pairs = (2 + 42) / 2;
Copyright &
John Temples (pic at xargs dot com)

我要回帖

更多关于 ext.define 的文章

 

随机推荐