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) var volatile bit led is pin_A1 -- define alias for pin_A1 var volatile bit led_direction is pin_A1_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 loop
When 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 the datasheets! Therefore it is possible that some names may not be conform the datasheet. When you find such a deviation, please report to the Jallib team!
For all registers of the chip a name is defined and where appropriate also the individual bits or groups of bits are declared. Also some aliases are declared for easy the migration or conversion of existing JalV2 libraries and programs to the Jallib environment.
There are also exceptions to the rules above.
For example the interrupt bits of Timer 0 are declared as TMR0IE and
TMR0IF for all devices, even though some datasheets use the names
T0IE and T0IF.
This is just an example, see below for more.
This 'normalization' is done to be able to use all libraries for all
types of PICmicros.
As side-effect also programs can be migrated to other types of PICs more
easily.
For all ports and port pins a device independent alias is defined and a similar direction definition, as the following examples show:
var volatile byte PORTA at <addr> var byte PORTA_low -- low order nibble var byte PORTA_high -- high order nibble var volatile bit pin_A0 at PORTA : 0 var volatile byte TRISA at <addr> var volatile byte PORTA_direction at TRISA var volatile bit pin_A0_direction at TRISA : 0
etc. (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 byte PORTA_low -- low order nibble var byte PORTA_high -- high order nibble var volatile bit pin_A0 at GPIO : 0 var volatile byte TRISIO at <addr> var volatile byte TRISA at TRISIO var volatile byte PORTA_direction at TRISIO var volatile bit pin_A0_direction at TRISIO : 0
etc. (for all other existing pins)
Some PICs, especially 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 TRISx instructions 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_output
The device files contain pseudo variables which mimic the existence of memory mapped registers, and now you can 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
Since frequently the upper and lower 4 bits ('nibble') of a port are used as a unit, these are defined as pseudo variables.
PORTx_low - bits 0..3 PORTx_high - bits 4..7 PORTx_low_direction PORTx_high_direction
This 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 unchanged
Several function libraries in the Jallib collection use this facility.
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
When you have used Jal before with other device files or libraries you may notice some differences in the naming convention:
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:
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).
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.
If you want to use other names for ports, nibbles or individual pins you must specify an alias. For example when you have a red LED connected to pin 0 of PortA, you could specify:
var bit led_red is pin_A0and use 'led_red = on' or 'led_red = off' in your program.
You should avoid direct pin and I/O port manipulation, because it will be overruled by the automatic shadowing mechanism. 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.
Shadowing is also bypassed when you initialise the alias with the declaration. So declaring and initialising an alias as follows:
var bit led_red is pin_A0 = offis bad practice! Initialize an alias separatedly after the declaration.
The configuration bits or groups of bits is such a large variety that it is almost impossible to obtain a naming convention which covers it all.
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.
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 - as HS, PLL active EC_CLKOUT - External Clock (TTL) signal on OSC1, OSC2 is ClockOut EC_NOCLKOUT - External Clock (TTL) signal on OSC1, OSC2 is I/O EC_PLL - as EC, PLL active RC_CLKOUT - RC oscillator on OSC1, OSC2 is ClockOut RC_NOCLKOUT - RC oscillator on OSC1, OSC2 is I/O EXTOSC_CLKOUT - External oscillator on OSC1, ClockOut on OSC2 EXTOSC_NOCLKOUT - External 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 (other keywords may be used as well)
ENABLED - Watchdog enabled DISABLED - Watchdog disabled
P32768 - 1 : 32,768 P16384 - 1 : 16,384 P... - 1 : ... P.. - 1 : .. P2 - 1 : 2 P1 - 1 : 1
EXTERNAL - /MCLR pin enabled INTERNAL - /MCLR pin is digital I/O
ENABLED - Power up timer enabled DISABLED - Power Up timer disabled
ENABLED - BOD enabled, SBOREN disabled RUNONLY - BOD enabled in run, disabled in sleep CONTROL - SBOREN controls BOR function DISABLED - BOD and SBOREN disabled
V20 - 2.0 Volt V27 - 2.7 Volt V42 - 4.0 Volt V45 - 4.5 Volt ... etc (whatever voltages are applicable)
ENABLED - LVP on, enabled DISABLED - LVP off, disabled
ENABLED - Code memory read protection on DISABLED - Code mewmory read protection off
ENABLED - Data (EEPROM) memory read protection on DISABLED - Data (EEPROM) memory read protection off
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)
F4MHZ - 4 MHz F8MHZ - 8 MHz
Notes:
When a fuse_def statement causes compile-time error messages you may simply delete it and specify the fuse-word(s) or -byte(s) explicitly with bit patterns in stead of using fuse option pragma statements. For example for the PIC16F690 the following group of statements:
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 Disabledis equivalent with:
pragma target fuses 0b11_0011_1110_0010
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.
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
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.4j - 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.
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.
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.