When I started programming in JAL it struck me that there were so few
JALV2 include files, in particular not for some of my favourite PICmicros
(such as the 16F690 and 12F683).
The Inc2Jal utility to generate device definition files was designed
for the original Jal compiler, was not updated for JalV2 and the device
files it generated for my preferred PICs gave compile errors.
Possible ways to resolve this issue might have been to update the generated
device files manually or make Inc2Jal up-to-date for JalV2.
I didn't like either of these (Inc2Jal is written in Pascal, which I hadn't
used for many years).
Since I already had a Rexx script to scan MPlab files for my Xwisp2
program I decided to take that route for a replacement of Inc2Jal.
I named the new script Dev2Jal because it uses the .dev files of
MPlab as base in stead of the .inc files like Inc2Jal.
The advantages of automated generation of device files are pretty obvious, such as:
The advantages of a consistent naming convention are also obvious:
This document gives some design information and some instructions for the use of these JalV2 device files. The sources of information are the xxxx.dev files and xxxx.lkr of MPLAB, supplemented and corrected with information from the datasheets.
With the design of the device files I had in mind a structure as shown below.
+----------+ +------------------+ | device | | general | | specific |---| include | | include | |chipdef_jallib.jal| +----------+ +------------------+ | +---------------+---------------+------------- | | | +----------+ +----------+ +----------+ +------- | function | | function | | function | | | include | | include | | include | | etc |'delay_..'| | 'adc_...'| |'lcd_....'| | +----------+ +----------+ +----------+ +-------
These device files are now part of the central JalV2 library repository JalLib at code.google.com, which uses the same structure.
The device files are the base for other include files and contain:
Including a device file doesn't change anything to the PIC. For example pins which are input after power-on or reset remain input, etc. Required changes are the responsibility of the application program or function libraries. For convenience reasons every device file contains a procedure to disable all analog modules of the PIC and to change all pins which are analog by default to digital I/O: enable_digital_io().
The defaults for the configuration bits may be slightly different than their specifications in the datasheet. You can find the default configuration bits settings in the top of the device file.
The file 'chipdef_jallib.jal' which comes with these device files replaces the file 'chipdef.jal' which comes with the compiler distribution. It is included by each of the device files and contains:
With the statement 'pragma target chip = .....' in every device file the compiler assigns a value to the variable 'target_chip'. The program may reference this variable with a symbolic name. This symbolic name consists of 'pic_' followed by the type of the PIC, which makes it possible to use the same source file to generate a hex file for different types of PICs, as the following example shows:
include 16f88 if (target_chip == PIC_16F88) then -- (not for 16f87) .... -- 16F88 unique code end if
By changing the include statement to 16f87 (or any other) the statements between 'if' and 'end if' will be skipped by the compiler.
The list of targets in chipdef_jallib.jal makes sure that every possible target name and the corresponding value of target_chip is known by the compiler.
Note: The original chipdef.jal file of the compiler package specifies a different value for 'target_chip' and not for all PIC type. Therefore it has to be replaced when using this set of device files.
Function specific include files offer facilities to ease the use of PIC peripherals (such as USART, ADC), external devices (such as LCDs, sensors), or extensions to the Jal language such as for data formatting, mathematical functions, etc.
Function specific include files should be included explicitly as required by the application program, this is not done by the device files.
In most cases the function include files require some statements to couple function specific registers and pins with the device. Read the comments in the library sources and the library documentation for instructions. Most libraries contain comments with user instructions in the header of include files and just ahead of the procedures and functions in these files.
The device files define static device (PICmicro) specific matter. This allows writing elementary programs, such as for a blinking LED, which are almost device independent. Differences are mostly in the fuse settings.
The device files are also the base for extensions, such as libraries for more complicated functions like displaying text on an LCD display or handling analog devices.
Below a simple blink-an-LED program (LED on pin 1 of Port A) for a PIC16F886 using a 20 MHz resonator. In addition to the device-specific information obtained from the include file '16f886.jal' some run-time information is needed, like the speed and type of the oscillator and some other 'environmental' variables. No extra function libraries are required.
-- ------ Blink-an-LED on pin A1 of a PIC16F886 -------- include 16f886 -- target is a PIC16F886 -- Notes: - The extension .jal is -- added by the compiler! -- - No other includes needed. pragma target clock 20_000_000 -- oscillator frequency (in Hz) -- required for delays pragma target OSC HS -- high speed external oscillator pragma target WDT Disabled -- watchdog off pragma target MCLR External -- external chip reset pragma target LVP Disabled -- no low voltage programming enable_digital_io() -- disable analog module(s) alias led is pin_A1 -- declare alias for pin_A1 alias led_direction is pin_A1_direction -- and for its direction led_direction = output -- make LED-pin output forever loop -- endless loop led = on -- there is light! _usec_delay(250000) -- spin 1/4 seconds led = off -- flip (on->off,off->on) _usec_delay(250000) -- spin 1/4 seconds end loopWhen loaded in a 16F886 with 20 MHz resonator or crystal an LED connected (with series resistor!) to pin 3 (RA1) should blink twice a second.
Unfortunately MPLAB of Microchip is not particularly consistent in its choice of names! The datasheets and the various informational files in MPLAB not infrequently use different names for the same entity! As a rule the device files use the names as used by the datasheets. However the device files have been generated from the MPLAB information files, not from the datasheets! So it is possible that some names may not be conform to the datasheet. When you find such a deviation not mentioned in this document, please report to the Jallib team, and most likely the next release will contain the corrected name.
For all registers of the chip a name is declared and where appropriate
also the individual bits or groups of bits are declared.
Subfields of registers have the name of the register as prefix, like
var volatile bit INTCON_GIE at INTCON : 7Some aliases are declared for easy migration or conversion of existing JalV2 libraries and programs to the Jallib environment.
There are exceptions to the rules above.
The aim of 'normalization' (using a consistent naming) is:
For all ports and port pins a device independent alias is declared and a similar direction declaration, as the following examples show:
var volatile byte PORTA at <addr> var volatile byte TRISA at <addr> var volatile byte PORTA_direction at TRISA var volatile bit pin_A0 at PORTA : 0 var volatile bit pin_A0_direction at TRISA : 0etc. (for all other existing pins and ports)
Although the smaller PICs have no 'official' PORTA and TRISA registers, the device files contain aliases for these. So even with the smaller PICs you can use the names PORTA, pin_A0, etc.
var volatile byte GPIO at <addr> var volatile byte PORTA at GPIO var volatile byte TRISIO at <addr> var volatile byte TRISA at TRISIO var volatile byte PORTA_direction at TRISIO var volatile bit pin_A0 at GPIO : 0 var volatile bit pin_A0_direction at TRISIO : 0etc. (for all other existing pins)
Pins which can be input-only may have no corresponding _direction variable, for example pin_E3 of the 18F4550.
Since frequently the upper and lower 4 bits ('nibble') of a port are used as a unit, these are declared as pseudo variables.
PORTx_low - bits 0..3 PORTx_high - bits 4..7 PORTx_low_direction PORTx_high_directionThis allows nibbles to be used as a regular variables, and also to set pin directions by 4 at a time:
PORTA_high = "7" -- lower nibble remains unchanged PORTA_low_direction = all_output -- direction upper nibble unchangedSeveral function libraries in the Jallib collection use this facility.
Note: Nibbles are always declared even if the register doesn't have the nibble fully populated (or not populated at all!) with pins.
When a pin is multiplexed (has a different function depending on
control registers or configuration bit settings), aliases are declared
to make the pin accessible by a more functional name.
For example: of the 16F88 pin_B6 is usable as analog input for the ADC
module as channel 5 and therefore pin_B6 has been given an alias name
pin_AN5.
You can find the 'AN5' name in the datasheet.
Of course also for the pin_B6_direction an alias is declared and
called similarly pin_AN5_direction!
Libraries (for this example the ADC library) will use the alias
names in stead of the physical pin names.
Another PIC may have pin_AN5 associated with a different physical pin,
but by using the alias name the ADC library becomes indenpent of the
physical pin configuration
and and makes it to a large extent device independent.
If you want to use another name for a port, nibble or individual pin you can also specify an alias in your program. For example when you have a red LED connected to pin 0 of PortA, you could specify:
alias led_red is pin_A0and use 'led_red = on' or 'led_red = off' assignments in your program.
Pin aliases in the device files are declared in this
way and therefore also make use of the port shadowing provided by
the device files.
This way of aliasing - using the keyword 'alias' - is only
available since JalV2 compiler version 2.4l.
You should avoid direct pin and I/O port manipulation, because it will be overruled by the automatic shadowing mechanism (see the chapter about Shadowing). For example do not specify:
var bit led_red at portA : 0With this specification a 'led-red = on' will have the desired result, but it will not update the shadow register. Any next operation which uses the shadowing mechanism will override the previous direct control operation.
Some pin alias names are not acceptable for the JalV2 compiler, in which a special name is used. For example PICs with USB support have a D+ and D- pin. These are declared (for the 18F4550) as:
alias pin_D_POS is pin_C5 alias pin_D_NEG is pin_C4Some function pins can be on one or another pin of a PIC, controlled by a register or a configuration bit setting. In these cases the name has to be suffixed to prevent duplicate names. The 16F737 for example can have the CCP2 bit on pin_B3 or pin_C1, controlled by a configuration bit (fuse_def CCP2MUX).
alias pin_CCP2_RB3 is pin_B3 alias pin_CCP2_RC1 is pin_C1The program or library has to detect the actual use of the CCP2 pin.
Some PICs, mainly in the baseline series, are missing some addressable ('memory mapped') registers. For example the 12-bit core PICs (10Fs, 12F5x, etc) have no memory mapped TRISx registers, in stead these PICs have a TRISx instruction to set the direction of ports or pins. This would make it impossible for function libraries and application programs to use statements like:
PORTA_direction = all_outputThe device files contain pseudo variables which mimic the existence of memory mapped registers. This makes it possible to use statements like the one above.
For example: even though a 16F59 has no addressable TRISC register, you can still specify:
pin_C5_direction = output
Names of registers of MSSP modules have been normalized as follows:
SSPADD SSPBUF SSPCON -- first or only control register SSPCON2 -- second control register (if present) SSPSTAT
SSP1ADD SSP1BUF SSP1CON -- first or only control register SSP1CON2 -- second control register (if present) SSP1MASK SSP1STAT
SSP2ADD SSP2BUF SSP2CON -- control register second module SSP2CON2 -- second control register (if present) SSP2STAT
For the selection of the ADC channel the ADC library has to set the
appropriate bit(s) of the ANSEL register(s), depending on the type of
PIC.
The baseline and midrange PICs have a couple of different ANSEL registers
configurations.
This would make it complicated to build a device independent ADC library.
This is (partly) solved by declaring aliases for the channel selection
bits in ANSEL registers.
Another example for the 10F222:
Names of registers and subfields of ADC modules have been normalized as follows:
When the ADCONx_VCFG subfield is a multi-bit field it is declared
both as a multi-bit field ADCONx_VCFG and as enumerated bits
(ADCONx_VCFG0 and ADCONx_VCFG1).
While most PICS with more than 8 ADC channels have a 4-bits subfield
ADCONx_CHS, some PICs have the channel selection bits scattered over
more than 1 subfield.
For example the 16F7x7s have a 3-bits CHS field plus a single CHS3 bit
to be able to support channel 8 and up.
In this and similar cases a pseudo variable ADCONx_CHS has been declared
which takes care of the scattering of channel selection bits.
So an ADC library can always address the variable ADCONx_CHS as multibit
'binary' field, regardless if the bits are scattered over the register or not.
Some register subfields of timer control registers have inconsistent
names in the MPLAB .dev files.
For these subfields the following naming convention has been chosen:
Port shadowing is a technique to prevent the Read-Modify-Write
('RMW') problem with I/O ports of PICmicro's.
This is a problem related to its hardware design.
Search the Internet for "PIC" and "read-modify-read" and you'll get many
hits to more or less interesting articles!
None of the explanations are repeated here.
And you don't absolutely need to understand the problem, since by using
the Jallib device files you won't face the problem when you follow some
simple rules and avoid a few pitfalls.
With port shadowing for the baseline and midrange PICs
(10F, 12F, 16F) a RAM location is used as replacement for the port for
output.
The 18F series have a special register for this purpose (LATx).
Although the techniques are slightly different, the general rules are:
reading is done from the port directly, while writing is done to the
shadow register of which the contents is subsequently passed to the
real port.
With the Jallib device files shadowing is automatic, as long
as you use the following names:
Note: The value for both Portx_low and Portx_high is passed with
reading from (and must be passed with writing to) in the lower nibble
(bits 3..0) of a constant or variable.
Portx_low is read from or written to bits 3..0 of Portx,
Portx_high is read from or written to bits 7..4 of Portx.
The configuration bits or groups of bits is such a large variety that it
is almost impossible to obtain a uniform naming convention.
Only for the oscillator specification the MPLAB information files contain
more than 140 different descriptions!
Because of synonyms this number could be normalized to a much smaller
number!
The first part is the oscillator type, the [optional] second part indicates
a related subfunction.
For example it may indicate if the OSC2 pin is CLKOUT or I/O, or if PLL is
active for the 18F series.
Descriptions in MPLAB which do not fit in the normalization scheme are copied
almost literally.
Notes:
When a fuse_def statement causes compile-time error messages you
probably should use an alternative method to specify the configuration-
word(s) or -byte(s) explicitly with bit patterns.
For example for the PIC16F690 the following group of statements:
PICs with 16-bits core (the 18F series) have such a large set and
variety of configuration bits that explicit specification is probably
the best way to make sure all configuration bits are set correctly for
your program.
As an example see the following list for a simple blink-a-LED program
with an 18F242.
Notes:
The meaning of configuration bits can in most cases be found in the
DataSheet of the specific chip, in the section 'Special Features of the
CPU'.
This info can certainly be found in the Programming Specifications of the chip.
For your convenience the MicroChip document numbers are mentioned in the
heading of the device files.
The compiler - at the moment of this writing version 2.4l - has a
number of requirements for device specifications.
The most important from a user perspective are the following:
The device files specify the amounts of available shared and unshared
memory (RAM, GPR) in bytes.
For user program memory (variables, constants) the compiler allocates
memory first in unshared RAM then in shared RAM.
Some specific compiler 'internally' used bytes can be and should
be allocated in shared RAM for optimum performance.
Most PICS have both shared and unshared RAM and then there is no
issue, but some PICs have only shared memory while some others have no
shared memory at all.
This complication is solved in the device files as follows:
The compiler supports a maximum of 4 memory banks for baseline and
midrange PICs.
When a PIC has more memory banks the device file declares only 4 of
these, memory in the other banks is unusable.
Example: 16F59.
(to be done)
These device files are part of the central JalV2 repository 'Jallib'
(http://jallib.googlecode.com).
Other libraries of Jallib have been or are being converted to use the names
in these device files.
You are strongly recommended to use only this combination of include files.
Using these device files in combination with other libraries may cause
problems, especially with libraries for the old (pre JalV2) compiler.
The ANSx and ANSELx bits have a given prefix 'JANSEL' (a pseudo
register name being a contraction of JALLIB-ANSEL).
The name of the channel selection bit has the form AN
As example below the declaration of ANS bit of the 16F886.
This PIC has as ADC channels 0..4 and 8..13.
var volatile byte ANSEL at { 0x188 }
var volatile bit JANSEL_ANS4 at ANSEL : 4
var volatile bit JANSEL_ANS3 at ANSEL : 3
var volatile bit JANSEL_ANS2 at ANSEL : 2
var volatile bit JANSEL_ANS1 at ANSEL : 1
var volatile bit JANSEL_ANS0 at ANSEL : 0
-- -------------------------------------------------
var volatile byte ANSELH at { 0x189 }
var volatile bit JANSEL_ANS13 at ANSELH : 5
var volatile bit JANSEL_ANS12 at ANSELH : 4
var volatile bit JANSEL_ANS11 at ANSELH : 3
var volatile bit JANSEL_ANS10 at ANSELH : 2
var volatile bit JANSEL_ANS9 at ANSELH : 1
var volatile bit JANSEL_ANS8 at ANSELH : 0
As you can see the prefix JANSEL is not restricted to bits 0..7 of ANSEL
but is also used for channel numbers higher than 7, controlled by
another register.
The 16F724 and 16F727 have 21 ADC channels spread over 4 ANSELx
registers, but these can controlled with the names JANSEL_ANS0 through
JANSEL_ANS20.
var volatile byte ADCON0 at { 0x7 }
var volatile bit JANSEL_ANS1 at ADCON0 : 7
var volatile bit JANSEL_ANS0 at ADCON0 : 6
In this case the channel selection bits are in register ADCON0
(the 10Fs have no ANSEL register), but the ADC library doesn't need
to know, because it uses the JANSEL alias.
Note: in reality the channel selection of the 10F220/222 is
somewhat more complicated, but the ADC library takes care of that!.
Names of other ADC registers and subfields
Names of Timer fields
Miscellaneous remarks about names
When you hit compilation errors related to undefined names, scan the
device file of the used PIC to search for the Jallib name of the
registers and their subfields.
About Port Shadowing
PORTx -- all bits of port x
PORTx_low -- low order nibble of port x (bits 3..0)
PORTx_high -- high order nibble of port x (bits 7..4)
pin_xy -- single bit 'y' of port 'x'
(in which 'x' is a port-letter and 'y' a bit number).
Naming convention for configuration bits (fuses)
Fuse_Def OSC (oscillator)
LP -- Low Power crystal on OSC1,OSC2
XT -- Crystal or Resonator on OSC1,OSC2
HS -- High Speed Crystal or Resonator on OSC1,OSC2
HS_PLL -- HS with (hardware) PLL active
EC_CLKOUT -- External Clock (TTL) signal on OSC1, ClockOut on OSC2
EC_NOCLKOUT -- External Clock (TTL) signal on OSC1, OSC2 is I/O
EC_CLKOUT_PLL -- EC_CLKOUT with PLL active
EC_NOCLKOUT_PLL -- EC_NOCLKOUT with PLL active
RC_CLKOUT -- (external) Resistor/Capacitor oscillator on OSC1, ClockOut on OSC2
RC_NOCLKOUT -- (external) Resistor/Capacitor oscillator on OSC1, OSC2 is I/O
INTOSC_CLKOUT -- Internal oscillator, OSC1 is I/O, ClockOut on OSC2
INTOSC_NOCLKOUT -- Internal oscillator, OSC1 and OSC2 are I/O
Several other keywords could be possible, for example for PICs:
The datasheet will specify the possibilities, scan the device files for
the keyword which applies.
Fuse_Def WDT (watchdog)
ENABLED -- Watchdog enabled
DISABLED -- Watchdog disabled
Fuse_Def WDTPS (Watchdog postscaler)
P32768 -- 1 : 32768
P16384 -- 1 : 16384
P... -- 1 : ...
P.. -- 1 : ..
P2 -- 1 : 2
P1 -- 1 : 1
Fuse_Def MCLR (reset)
EXTERNAL -- /MCLR pin enabled
INTERNAL -- /MCLR pin is digital I/O
Fuse_Def PWRTE (Power-up Timer Enable)
ENABLED -- Power up timer enabled
DISABLED -- Power Up timer disabled
Fuse_Def BROWNOUT (Brown Out detect)
ENABLED -- BOD enabled, SBOREN disabled
RUNONLY -- BOD enabled in run, disabled in sleep
CONTROL -- SBOREN controls BOR function
DISABLED -- BOD and SBOREN disabled
Fuse_Def VOLTAGE (Brown Out voltage)
V20 -- 2.0 Volt
V27 -- 2.7 Volt
V42 -- 4.0 Volt
V45 -- 4.5 Volt
... etc (whatever voltages are applicable)
Fuse_Def LVP (Low Voltage Programming)
ENABLED -- LVP on, enabled
DISABLED -- LVP off, disabled
Fuse_Def CP (Code Protection)
ENABLED -- Code memory read protection on
DISABLED -- Code mewmory read protection off
Fuse_Def CPD (Data Code Protection)
ENABLED -- Data (EEPROM) memory read protection on
DISABLED -- Data (EEPROM) memory read protection off
Fuse_Def WRT (Program Memory Self-Write Protection)
NO_PROTECTION -- All program memory writable
ALL_PROTECTED -- Writing of program memory prohibited
Rxxxx_yyyy -- Protected memory range
-- (only specific ranges can be write protected)
Fuse_Def IOSCFS (Internal Oscillator Frequency Select)
F4MHZ -- 4 MHz
F8MHZ -- 8 MHz
pragma target OSC HS
pragma target WDT Disabled
pragma target PWRTE Enabled
pragma target MCLR External
pragma target CP Disabled
pragma target CPD Disabled
pragma target BROWNOUT Enabled
pragma target IESO Disabled
pragma target FCMEN Disabled
is equivalent with:
pragma target fuses 0b11_0011_1110_0010
pragma target fuses 0 0b0000_0000 -- (n/a)
pragma target fuses 1 0b0010_0010 -- not switchable, HS osc, no PLL
pragma target fuses 2 0b0000_0001 -- BOR disabled, PWTR disabled
pragma target fuses 3 0b0000_0000 -- watchdog disabled
pragma target fuses 4 0b0000_0000 -- (n/a)
pragma target fuses 5 0b0000_0001 -- CCP2 on RC1
pragma target fuses 6 0b1000_0001 -- no bg debug, no LVP, STVREN
pragma target fuses 7 0b0000_0000 -- (n/a)
pragma target fuses 8 0b0000_1111 -- no code protection
pragma target fuses 9 0b1100_0000 -- no data protection
pragma target fuses 10 0b0000_1111 -- no code write protection
pragma target fuses 11 0b1110_0000 -- no other write protection
pragma target fuses 12 0b0000_1111 -- no table read protection
pragma target fuses 13 0b0100_0000 -- no boot block write protect
(n/a) mean not applicable to this specific PIC, but may be specified
(as all zeroes).
Compiler requirements
Memory allocation
For the compiler 'shared' means: accessible in all banks.
Memory which is accessible in more than one bank but not in all
is declared as unshared RAM.
Analog modules
Miscellaneous