Jallib Tutorial Book
Jallib Tutorial Book
Jallib Tutorial Book
Contents
1
Back to basics...
Topics: This is a brief introduction to exploring the basic tutorials. As a beginner, we recommend
that you should experiment with and fully understand these first steps before going any
• Installation
further. If you're a more advanced user, these tutorials may help you with the testing of
• Getting Started
new chips, or... when things go wrong and you can't figure out why, by guiding you "back
• Blink A Led (Your First to basics".
Project)
• Serial Port and RS-232 Don't worry, everything's gonna be alright...
for communication
6 | Jallib | Back to basics...
Jallib | Back to basics... | 7
Installation
Jallib Group
Jallib Group
Getting Jallib
The Jallib repository is maintained at http://justanotherlanguage.org/downloads. It's safer to ignore the "Automated
weekly build..." files in this download directory (these, as the prefix implies, are updates to the repository
automatically compiled by the server and are probably untested). Look instead for the latest version of the release file
which has the annotation "Don't know which to choose? Take this one!". These are the tested releases and, while we
can't guarantee that there won't be any bugs at all, will provide a reasonably trouble-free installation.
The release files are all ZIP archives, which can be easily unpacked on most modern operating systems (Windows/
Linux/MacOSX). Jallib releases also all come complete with a pre-compiled binary version of the JALv2 compiler for
both Windows and Linux in the top-level compiler directory and a full set of documentation (including a copy of this
tutorial) in the top-level doc directory, so there's nothing to stop you getting started straight away.
Windows Install:
1. Download the latest stable Jallib release installer executable from http://justanotherlanguage.org/downloads, This
will install JALv2 + JalEdit
2. Update your installation (very important) - Download jallib-pack or jallib-pack-bee from http://
justanotherlanguage.org/downloads, copy the .zip contents into your Jallib installation directory.
3. Run the setup file
4. Run JalEdit.exe from the "jaledit" directory
5. (optional) Click Tools Menu -> Environment Options -> Programmer, Then Set the Programmer Executable Path
You should see something like this under Windows:
8 | Jallib | Back to basics...
Linux Install
Note: All instances of filenames or paths within square brackets below (eg:- [filename.tar.gz])
are for illustration only. You will need to change these examples to suit your specific installation. Do not
just copy and paste the examples!
Note: Two commands (tar/unzip) are shown below for unpacking the Jallib file. You only need to
use one or the other, not both. Which one you use depends upon the suffix of the file. If the filename ends
in ".tar.gz", use the tar command. If the filename ends in ".zip", use the unzip command.
1. Go to http://justanotherlanguage.org/downloads and select the link for the latest, stable version of Jallib (see:-
Getting Jallib, above)
2. Change directory ("cd [/target/directory]") to the location where you intend to install JALv2
3. Download the package with: $ wget [link location of the jallib-pack] or simply use your
favorite browser to download the package and then move it into your chosen installation directory.
4. Either untar the package with: $ tar xzf [filename.tar.gz]
5. Or unzip the package with: $ unzip [filename.zip]
You should see something like this under Linux:
Getting Started
Matthew Schinkel
Jallib Group
PIC16F877 or PIC16F877A seem to be the most popular mid-range PIC at the moment (in the image above). You
should be able to find them at your local electronics store for around $10. This microcontroller has many features and
a good amount of memory. It will be sufficient for most of your projects. We will build our first project on this chip.
I warn you however, you may eventually want to move to an 18F PIC for more memory, for example, you can run a
SD Card, but you cannot use FAT32. I only suggest 16f877A because it will be easy to find at a store.
There are many low-end PIC’s to choose from, PIC16F84, PIC16F88 are smaller chips for around $5. There are also
very low end 8 pin PIC’s such as 12F675 for $1.
If you’re looking for speed, functionality, and a whole lot of memory space, you can go with a PIC18Fxxx chip. I
suggest one of the following: 18f452, 18F4620, 18F4550. These PIC’s will also work in our getting started “blink a
led” tutorial with the same circuit diagram. If you can, get a 18F PIC. My current favorite is the 40 pin 18f4620.
You will notice that the better 18F series chips are actually cheaper then the outdated 16F chips.
Here’s a price chart from the manufacturer’s sales website:
If you want to use another editor that supports the JAL syntax or you are using another operating system than
Windows, you can make use of Visual Studio Code for your JAL development.
12 | Jallib | Back to basics...
When using a PICkit2 or a PICKit3, you can use the standalone PICKit2 or PICKit3 software from Microchip. This
software can be downloaded from the Microchip archive site (scroll down to the bottom of the site) but
this software is no longer supported. The interface of this standalone software for the PICKit3 looks like this.
Luckily there are still people who spend effort in supporting newer PICs for this software. In order to upgrade your
PICKit2 or PICKit3 software so it supports more PICs, you have to do the following:
Jallib | Back to basics... | 13
• Download a new data file named PKPlusDeviceFile.dat that contains the newer PICs from Anobium on
GitHub
• Go to the directory on your computer where the PICKit2 of PICKit3 software is located. You will
find a data file with the name PK2DeviceFile.dat. Rename this file or delete it and copy the file
PKPlusDeviceFile.dat to this directory
• Rename the file PKPlusDeviceFile.dat to PK2DeviceFile.dat. Now start the PICKit2 or PICKit3
standalone application
An alternative when using a PICkit2, a PICKit3, a PICKit4 or a SNAP programmer from Microchip, is to use the
Integrated Programming Environment (IPE) from Microchip. This environment is part of MPLABX and can be
downloaded for free. Note that not all programmers are capable of programming all PICs except for the PICKit4.
The PICKit2 and PICKit3 cannot program all newer PICs - but the dat file update mentioned previously will help to
support more PICs - and the SNAP cannot program all older PICs since the SNAP programmer only supports Low
Voltage Programming (LVP). All these programmers make use of the In Circuit Programming feature of
the PIC. The following image shows a screenshot of the IPE environment where two programmers are connected to
the computer, a PICKit3 and a SNAP.
OK, enough of this boring stuff, lets build something! Start with the Blink A Led Tutorial.
14 | Jallib | Back to basics...
In this tutorial we are going to learn how to connect our first circuit and blink our first led.
Where to we start?
Let’s make a led blink on and off, how fun is that!
So, you’ve followed the installation guide and now have a Programming language (JALv2) + Libraries (JALLIB) +
Editor. We will be using JALEdIt for our first example.
Get out your PIC microcontroller (we will now refer to it as a PIC). You can use PIC’s 16f877, 16f877A, 18F2550 ,
18F452 or 18F4550 for this project since the port pin outs are the same for all of them. I will use 16f877A for this
blink a led project.
Now check PC connectivity to your programmer. Open your programming software on your PC, check the settings
within your software to change the serial port number and programmer type (if available). Your programmer software
may tell you that your board is connected, if not, put your PIC in your programmer and do some basic tests such as
“read chip”, “blank / erase chip”
Jallib | Back to basics... | 15
If you are using Micropro, click on “file” -> “port”, and “file” -> “programmer” -> (your programmer type). If you
do not know the programmer type, you will have to guess until Micropro says something like “K149-BC board
connected”, Put your PIC in your programmer and choose your PIC type from the “Chip Selector” text box. Now do
some basic read/erase tests.
And here’s what it looks like. Notice the additional orange wire to the left of my PIC, this ensures that I always put
my PIC in the correct position after programming. Do not connect your power 5v supply till your circuit is complete
and checked over at least twice. You will burn your PIC if power is on while building your circuit. You will want an
on/off switch for your power supply.
Your circuit is done, and it looks pretty, but it doesn’t do anything :o(..
compiler – holds the jalv2.exe compiler program to convert your JAL code to microcontroller hex code
JALEdIt – JAL text editor where you will write your code. Note that you can also use Visual Studio Code for writing
your code.
lib – A set of libraries to make things work
sample – Working examples.
Create yourself a folder called workspace, and in that folder create a folder called blink_a_led (eg. C:
\jalv2\workspace\blink_a_led\)
--
-- Adapted-by:
--
-- Compiler:2.5r5
--
-- This file is part of jallib (https://github.com/jallib/jallib)
-- Released under the ZLIB license (http://www.opensource.org/licenses/zlib-
license.html)
--
-- Description:
-- Simple blink-a-led program for Microchip pic16f877a
-- using an external crystal or resonator.
--
--
-- Sources:
--
-- Notes:
-- - Creation date/time: Sat Jan 8 17:03:04 2022
-- - This file is generated by 'blink-a-led.py' script! Do not change!
--
-- ------------------------------------------------------
The PDF datasheet for this PIC and for all others can be downloaded from the microchip website. Here is the
datasheet for this PIC https://www.microchip.com/en-us/product/PIC16F877A , and here is the pin out diagram from
the datasheet:
As you can see, we are using the pin RA0/ANO at pin #2. RA0 is the pin name we are looking for. AN0 is another
name for this same pin (used in the analog to digital tutorial), but we can ignore it in this tutorial. In the JAL language
RA0 is written as pin_A0
Now let’s read the details of this pin in the datasheet on page 10. As you can see RA0 is a TTL Digital I/O pin. We
are checking this to make sure it is not a open drain output. Open drain outputs (like pin RA4) require a pull-up
resistor from the pin to V+
Now write code for pin A0. We are writing an “alias” only because in the future we can refer to pin 2 (A0) as “led”.
This way we no longer need to remember the name of the pin (except for the directional register in the next line of
code we will write).
--
-- You may want to change the selected pin:
alias led is pin_A0
20 | Jallib | Back to basics...
-- ------------------------------------------------------
--
include 16f877a -- target PICmicro
--
-- This program assumes that a 20 MHz resonator or crystal
-- is connected to pins OSC1 and OSC2.
pragma target clock 20_000_000 -- oscillator frequency
--
pragma target OSC HS -- crystal or resonator
pragma target WDT DISABLED -- watchdog
pragma target DEBUG DISABLED -- no debugging
pragma target BROWNOUT DISABLED -- no brownout reset
pragma target LVP DISBLED -- no low voltage programming
--
-- The configuration bit settings above are only a selection, sufficient
-- for this program. Other programs may need more or different settings.
--
--
enable_digital_io() -- make all pins digital I/O
--
-- A low current (2 mA) led with 2.2K series resistor is recommended
-- since the chosen pin may not be able to drive an ordinary 20mA led.
--
alias led is pin_A0 -- alias for pin with LED
--
pin_A0_direction = OUTPUT
--
forever loop
led = ON
_usec_delay(250_000)
led = OFF
_usec_delay(250_000)
end loop
--
Let's Try It
Put your PIC back into your circuit, double check your circuit if you haven’t already, and make sure your PIC is
facing the correct direction. Apply power to your circuit.
It’s alive! You should see your led blinking! Congratulations on your first JALv2 + JALLIB circuit!
Here's a youtube video of the result: http://www.youtube.com/watch?v=PYuPZO7isoo
I strongly suggest you do this tutorial next: Serial Port & RS-232 for communication.
Jallib | Back to basics... | 23
In this tutorial we are going to learn how use TX & RX pins for serial communication to your PC, and also learn
communicate with another PIC or external device via RS-232.
At one time, there was a wide range of devices that used the serial port such as a mouse, keyboard, old GPS, modems
and other networking.
In our case, we will use a serial port to send data to our PC, or to send data a second PIC. I find it most useful for
troubleshooting my code, and for sending other readable information to my PC without the use of additional hardware
such as a LCD. LCDs & displays can be an expensive addition to your circuit.
What is RS-232?
RS-232 is the data transfer standard used on serial ports. Basically this is composed of one start bit, some data bits,
parity bit, and one or two stop bits. The transfer speed as well as the number of start, stop and data bits must match for
both the transmitter and receiver. We will not need to cover the way in which it is transferred since the PIC does it for
us. We will only need to know the following:
1. The number of start bits (always 1)
2. The Parity (usually no parity)
3. The number of data bits (usually 8)
4. The number of stop bits (1 or 2)
5. The data transmission speed
6. The port number on your PC
You will be able to choose the transmission speed yourself. The Jallib library we will be using will use 1 start bit, 8
data bits, no parity, and 1 stop bit. Your other device, such as your PC will also need to know this information.
What do I need?
In the first part of this tutorial I will show you how to hook your serial port up to your PC. I will show you how to
connect it to another PIC later on in this tutorial. I feel that connectivity to your PC is quite important. You will need:
1. A PIC that has TX and RX Pin names. Most PIC's have them. Check your pinout diagram in the PIC's datasheet.
24 | Jallib | Back to basics...
2. A serial port board. You can buy one on the net, or build your own. See Here for more information. A serial port
board is needed for voltage conversion. Serial ports output voltages up to 12v and go lower than 0v.
3. A regular RS-232 Cable (make sure it is not a null modem cable, they look the same). You can check what type of
cable you have with your multimeter. Put your multimeter on each pin of your cable starting with pin 1. Check for a
zero ohm reading. This will check that the pins are the same at both ends. Null modem cables have some pins crossed.
Now press "Open" in RealTerm and turn on your circuit. If you now see "Hello serial world......" showing in within
RealTerm on your PC, you are able to receive data.
If your circuit doesn't work, your serial port board may have TX and RX switched (you can try switching your TX/
RX wires around), or you may have selected the wrong port number, some PCs have more than one serial port.
Now click on RealTerm's "send" tab, type in the number "65" in the first box and press "Send Numbers". If it sent ok,
the PIC will echo this value back to you. You will see the ASCII character "A", which is the same as decimal 65. You
can see a full ASCII chart at asciitable.com.
Now please change your RealTerm settings to receive decimal numbers by clicking on the "Display" tab, and choose
"int8" under "Display As" at the left side. You will now continuously see the number "46" come in, and try sending
the number "65" again. You will get the same number back on your screen.
Jallib | Back to basics... | 27
This code will set your baudrate (speed), it will include the correct library file "serial_hardware", and it will initialize
the library with "serial_hw_init()". You can change the speed if you wish, but you must change the speed in
RealTerm as well.
Now we can put some code that will send data to your PC. If you want to send the number 65 to your PC, you must
use this code:
serial_hw_data = 65
This code works because it is a procedure/function within serial_hardware.jal, and you have already included the
serial_hardware library. serial_haredware.jal can be found in the "lib" folder of your jallib installation. You can open
that file and read notes within it for more information and for other usable variables, functions and procedures.
Let's make your code send the number 65 when the led turns on, and send the number 66 when your led turns off. Just
place your code after your "led = on", and after "led = off"
forever loop
led = on
serial_hw_data = 65 -- send 65 via serial port
_usec_delay(250000)
led = off
serial_hw_data = 66 -- send 66 via serial port
_usec_delay(250000)
end loop
Or, if you wish to send Ascii letters to your PC instead, you could use the following:
forever loop
led = on
serial_hw_data = "A" -- send letter A via serial port
_usec_delay(250000)
led = off
serial_hw_data = "B" -- send letter B via serial port
_usec_delay(250000)
end loop
Both of the above loops will continuously send the decimal number's 65 and 66 via your serial port each time your led
turns on or off. Your completed code should look like this:
include 16f877a -- target PICmicro
--
-- This program assumes a 20 MHz resonator or crystal
-- is connected to pins OSC1 and OSC2.
pragma target clock 20_000_000 -- oscillator frequency
-- configuration memory settings (fuses)
pragma target OSC HS -- HS crystal or resonator
pragma target WDT disabled -- no watchdog
pragma target LVP disabled -- no Low Voltage Programming
forever loop
led = on
serial_hw_data = 65 -- send 65 via serial port
_usec_delay(250000)
led = off
Jallib | Back to basics... | 29
Awesome, now that you can send data to your pc! This was an important step since it will greatly help you with your
troubleshooting by sending you readable information such as text, numbers and other types of data.
If you feel your programming skills are not as good as they should be, practice practice practice! Continue using the
language reference described in the document jalv2.pdf in the 'compiler' directory of your Jallib installation.
led = on
_usec_delay(250000)
led = off
_usec_delay(250000)
end loop
Here is your completed code:
include 16f877a -- target PICmicro
--
-- This program assumes a 20 MHz resonator or crystal
-- is connected to pins OSC1 and OSC2.
pragma target clock 20_000_000 -- oscillator frequency
-- configuration memory settings (fuses)
pragma target OSC HS -- HS crystal or resonator
pragma target WDT disabled -- no watchdog
pragma target LVP disabled -- no Low Voltage Programming
var byte x
end loop
As you can see, this code will do the following:
Jallib | Back to basics... | 31
1. delay 1 second
2. send the number 65 via serial port
3. see if there is data waiting for us, if so, get it and blink the led (the number of times of the data received)
4. loop back to the start
So, turn it on, you will start getting decimal numbers: "65 65 65 65 65" or ascii: "AAAAAA" in RealTerm. Now send
your PIC the number 5, you will see your led blink 5 times. Now isn't that awesome!
2
PIC internals
Topics: This chapter covers main and widely used PIC microcontroller internals (also referred as
PIC peripherals in datasheets), like PWM, ADC, etc... For each section, you'll find some
• ADC - Analog-to-Digital
basic theory explaining how things works, then a real-life example.
Conversion
• I²C (Part 1) - Building an
I²C slave + Theory
• I²C (Part 2) - Setting up
and checking an I²C bus
• I²C (Part 3) -
Implementing an I²C
Slave
• PWM Intro - Pulse Width
Modulation
• PWM (Part 1) - Dimming
a led with PWM
• PWM (Part 2) - Sound
and Frequency with
Piezo Buzzer
• SPI Introduction
• USB (Part 1) -
Introduction
• USB (Part 2) - The PIC
as a serial port
34 | Jallib | PIC internals
Jallib | PIC internals | 35
Analog-to-Digital Conversion is yet another nice feature you can get with a PIC. It's basically used to convert a
voltage as an analog source (continuous) into a digital number (discrete).
Want 6 analog pins, no Vref ? Then PCFG bits must be set to 0b1001. What will then be the analog pins ? RA0,
RA1, RA2, RA3, RA5 and RE0. "What if I want 7 analog pins, no Vref ?" You can't because you'll get a Vref pin, no
choice. "What if I want 2 analog pins being RE1 and RE2 ?" You can't, because there's no such combination. So, for
this PIC, analog pins are dependent from each other, driven by a combination. In this case, you'll have to specify:
• the number of ADC channels you want,
• and amongst them, the number of Vref channels
Now, let's consider 16F88. In this case, there's no such table:
Mmmh... OK, there are ANS bits, one for each analog pins. Setting an ANS bit to 1 sets the corresponding pin to
analog. This means I can set whatever pin I want to be analog. "I can have 3 analog pins, configured on RA0, RA4
and RB6. Freedom !"
Analog pins are independent from each other in this case, you can do what you want. As a consequence, since
it's not driven by a combination, you won't be able to specify the number of ADC channels here. Instead, you'll use
set_analog_pin() procedure, and if needed, the reverse set_digital_pin() procedure. These procedures
takes a analog pin number as argument. Say analog pin AN5 is on pin RB6. To turn this pin as analog, you just have
to write set_analog_pin(5), because this is about analog pin AN5, and not RB6.
Remember: as a consequence, these procedures don't exist when analog pins are dependent as in our first
case.
Caution: it's not because there are PCFG bits that PICs have dependent analog pins. Some have PCFG
bits which act exactly the same as ANS bits (like some of recent 18F)
Tip: how to know if your PIC has dependent or independent pins ? First have a look at its datasheet, if
you can a table like the one for 16F877, there are dependent. Also, if you configure a PIC with dependent
pins as if it was one with independent pins (and vice-versa), you'll get an error. Finally, if you get an error
like: "Unable to configure ADC channels. Configuration is supposed to be done using ANS bits but it
seems there's no ANS bits for this PIC. Maybe your PIC isn't supported, please report !", or the like, well,
this is not a normal situation, so as stated, please report !
Once configured, using ADC is easy. You'll find adc_read_high_res() and adc_read_low_res()
functions, for respectively read ADC in high and low resolution. Because low resolution is coded on 8-bits,
adc_read_low_res() returns a byte as the result. adc_read_high_res() returns a word.
Jallib | PIC internals | 37
Example 1: 16F877, with only one analog pin, no external voltage reference
-- beginning is about configuring the chip
-- this is the same for all examples for about 18F877
include 16f877
-- setup clock running @20MHz
pragma target OSC HS
pragma target clock 20_000_000
-- no watchdog, no LVP
pragma target WDT disabled
pragma target LVP enabled
include print
include delay
const serial_hw_baudrate = 115_200
include serial_hardware
serial_hw_init()
ADCON0_ADCS = 0b11
-- Now we can include the library
include adc
-- And initialize the whole with our parameters
adc_init()
forever loop
end loop
Example 2: 16F877, with 2 analog pins, 1 external voltage reference, that is, Vref+
This is almost the same as before, except we now want 2 (analog pins A0 and A1) + 1 (Vref+ A3), so yes we are
using 3 analog pins here.
The beginning is the same, here's just the part about ADC configuration and readings. We use a for loop to go over
the 2 analog pins A0 and A1:
-- Step 1: ADC input pin setup we wil use channel 0 and 1 (2 channels)
pin_AN0_direction = input
pin_AN1_direction = input
-- Step 2: Set A0 and A1 analog input and A3 as Vref
ADCON1_PCFG = 0b0011
-- Step 3: Use Frc as ADC clock
ADCON0_ADCS = 0b11
-- Now we can include the library
include adc
-- And initialize the whole with our parameters
adc_init()
forever loop
end loop
end loop
40 | Jallib | PIC internals
i2c is a nice protocol: it is quite fast, reliable, and most importantly, it's addressable. This means that on a single 2-
wire bus, you'll be able to plug up to 128 devices using 7bits addresses, and even 1024 using 10bits address. Far
enough for most usage... I won't cover i2c in depth, as there are plenty resources on the Web (and I personally like
this page).
Example: consider the following address (8-bits long, last bit is for operation type)
0x5C => 0b_0101_1100 => write operation
The same address for read operation will be:
0x93 => 0b_0101_1101 => read operation
Note: Jallib currently supports up to 128 devices on a i2c bus, using 7-bits long addresses (without
the 8th R/W bits). There's currently no support for 10-bits addresses, which would give 1024 devices on
the same bus. If you need it, please let us know, we'll modify libraries as needed !
OK, enough for now. Next time, we'll see how two PICs must be connected for i2c communication, and we'll check
the i2c bus is fully working, before diving into the implementation.
2
some PICs have MSSP, this means they can also be used as i2c hardware Master
Jallib | PIC internals | 41
In previous tutorial, we saw a basic overview of how to implement an i2c slave, using a finite state machine
implementation. This time, we're going to get our hands a little dirty, and starts connecting our master/slave together.
In this circuit, both PIC have a LED connected, which will help us understand what's going on. On a breadboard, this
looks like that:
42 | Jallib | PIC internals
The master is on the right side, the slave on the left. I've put the two pull-ups resistors near the master:
Jallib | PIC internals | 43
Green and orange wires connect the two PICs together through SDA and SCL lines:
The goal of this test is simple: check if the i2c bus is properly built and operational. How ? PIC 16F88 and its SSP
peripheral is able to be configured so it triggers an interrupts when a Start or Stop signal is detected. Read this page
(part of an nice article on i2c, from previous tutorial's recommendations).
How are we gonna test this ? The idea of this test is simple:
1. On power, master will blink a LED a little, just to inform you it's alive
2. On the same time, slave is doing the same
3. Once master has done blinking, it sends a i2c frame through the bus
4. If the bus is properly built and configured, slave will infinitely blink its LED, at high speed
Note master will send its i2c frame to a specific address, which don't necessarily need to be the same as the slave one
(and I recommand to use different addresses, just to make sure you understand what's going on).
What about the sources ? Download latest jallib pack, and check the following files (either in lib or sample
directories):
• i2c_hw_slave.jal : main i2c library from the lib directory
• 16f88_i2c_sw_master_check_bus.jal: code for master from the sample directory
• 16f88_i2c_hw_slave_check_bus.jal : code for slave from the sample directory
The main part of the slave code is the way the initialization is done. A constant is declared, telling the library to
enable Start/Stop interrupts.
const SLAVE_ADDRESS = 0x23 -- whatever, it's not important, and can be
-- different from the address the master wants
-- to talk to
-- with Start/Stop interrupts
const bit i2c_enable_start_stop_interrupts = true
-- this init automatically sets global/peripherals interrupts
i2c_hw_slave_init(SLAVE_ADDRESS)
44 | Jallib | PIC internals
On this next video, I've removed the pull-ups resistors, and it doesn't work anymore (slave doesn't high speed blink its
LED).
http://www.youtube.com/watch?v=cNK_cCgWctY
Next time (and last time on this topic), we'll see how to implement the state machine using jallib, defining callback
for each states.
Jallib | PIC internals | 45
In previous parts of this tutorial, we've seen a little of theory, we've also seen how to check if the i2c bus is
operational, now the time has come to finally build our i2c slave. But what will slave will do ? For this example, slave
is going to do something amazing: it'll echo received chars. Oh, I'm thinking about something more exciting: it will
"almost" echo chars:
• if you send "a", it sends "b"
• if you send "b", it sends "c"
• if you send "z", it sends "{"3
Two connectors are used for earch port, PORTA and PORTB, to plug daughter boards, or a breadboard in our case.
The i2c initialization part is quite straight forward. SCL and SDA pins are declared, we'll use a standard speed,
400KHz:
-- I2C io definition
var volatile bit i2c_scl is pin_b4
var volatile bit i2c_scl_direction is pin_b4_direction
var volatile bit i2c_sda is pin_b1
var volatile bit i2c_sda_direction is pin_b1_direction
-- i2c setup
const word _i2c_bus_speed = 4 ; 400kHz
const bit _i2c_level = true ; i2c levels (not SMB)
include i2c_software
i2c_initialize()
We'll also use the level 1 i2c library. The principle is easy: you declare two buffers, one for receiving and one for
sending bytes, and then you call procedure specifying how many bytes you want to send, and how many are expected
to be returned. Joep has written a nice post about this, if you want to read more about this. We'll send one byte at a
time, and receive one byte at a time, so buffers should be one byte long.
const single_byte_tx_buffer = 1 -- only needed when length is 1
var byte i2c_tx_buffer[1]
var byte i2c_rx_buffer[1]
include i2c_level1
What's next ? Well, master also has to read chars from a serial line. Again, easy:
const usart_hw_serial = true
const serial_hw_baudrate = 57_600
include serial_hardware
serial_hw_init()
-- Tell the world we're ready !
serial_hw_write("!")
So when the master is up, it should at least send the "!" char.
Then we need to specify the slave's address. This is a 8-bits long address, the 8th bits being the bit specifying if
operation is a read or write one (see part 1 for more). We then need to collect those chars coming from the PC and
sends them to the slave.
The following should do the trick (believe me, it does :))
var byte icaddress = 0x5C -- slave address
Jallib | PIC internals | 47
forever loop
if serial_hw_read(pc_char)
then
serial_hw_write(pc_char) -- echo
-- transmit to slave
-- we want to send 1 byte, and receive 1 from the slave
i2c_tx_buffer[0] = pc_char
var bit _trash = i2c_send_receive(icaddress, 1, 1)
-- receive buffer should contain our result
ic_char = i2c_rx_buffer[0]
serial_hw_write(ic_char)
end if
end loop
The whole program is available on under the name 16f88_i2c_sw_master_echo.jal in the sample directory of your
Jallib installation.
• state 4: master still wants to read some information. This should never occur, since one char is sent and read at a
time. Slave should thus produce an error.
procedure i2c_hw_slave_on_state_4() is
pragma inline
-- This shouldn't occur in our i2c echo example
i2c_hw_slave_on_error()
end procedure
• state 5: master hangs up the connection. Slave should reset its state.
procedure i2c_hw_slave_on_state_5() is
pragma inline
data = 0
end procedure
Finally, we need to define a callback in case of error. You could do anything, like resetting the PIC, and sending log/
debug data, etc... In our example, we'll blink forever:
procedure i2c_hw_slave_on_error() is
pragma inline
-- Just tell user user something's got wrong
forever loop
led = on
_usec_delay(200000)
led = off
_usec_delay(200000)
end loop
end procedure
Once callbacks are defined, we can include the famous ISR library.
include i2c_hw_slave_isr
So the sequence is:
1. include i2c_hw_slave, and setup your slave
2. define your callbacks,
3. include the ISR
The full code is available from jallib's SVN repository:
• i2c_hw_slave.jal
• i2c_hw_slave_isr.jal
• 16f88_i2c_sw_master_echo.jal
• 16f88_i2c_hw_slave_echo.jal
All those files and other dependencies are also available in latest jallib-pack (see jallib downloads)
Everything is ready...
Once connected, power the whole and use a terminal to test it. When pressing "a", you'll get a "a" as an echo from the
master, then "b" as result from the slave.
What now ?
We've seen how to implement a simple i2c hardware slave. The ISR library provides all the logic about the finite state
machine. You just have to define callbacks, according to your need.
i2c is a widely used protocol. Most of the time, you access i2c devices, acting as a master. We've seen how to be
on the other side, on the slave side. Being on the slave side means you can build modular boards, accessible with a
standard protocol.
Jallib | PIC internals | 51
In the following tutorials, we're going to (try to) have some fun with PWM. PWM stands for Pulse Width Modulation,
and is quite weird when you first face this (this was at least my first feeling). So here's a brief explanation of what it is
about.
Both have a 50% duty cycle (50% on, 50% off), but the upper one's frequency is twice the bottom
Figure 4: PWM: same duty cycle, different frequencies.
52 | Jallib | PIC internals
Three different duty cycle (10%, 50% and 90%), all at the same frequency
Figure 5: PWM: same frequency, different duty cycles
But what is PWM for ? What can we do with it ? Many things, like:
• producing variable voltage (to control DC motor speed, for instance)
• playing sounds: duty cycle is constant, frequency is variable
• playing PCM wave file (PCM is Pulse Code Modulation)
• ...
That said, we're now goind to experiment these two major properties.
Jallib | PIC internals | 53
The connector brings +5V on the two bottom lines (+5V on line A, ground on line B).
end loop
Quite easy right ? There are two main waves: one will light up the LED progressively (0 to 250), another will turn
it off progressively (250 to 0). On each value, we set the duty cycle with pwm1_set_dutycycle(i) and wait a
little so we, humans, can see the result.
About the result, how does this look like ? See this video: http://www.youtube.com/watch?v=r9_TfEmUSf0
In previous tutorial, we had fun by controlling the brightness of a LED, using PWM. This time, we're going to have
even more fun with a piezo buzzer, or a small speaker.
If you remember, with PWM, you can either vary the duty cycle or the frequency. Controlling the brightness of a
LED, ie. produce a variable voltage on the average, can be done by having a constant frequency (high enough) and
vary the duty cycle. This time, this will be the opposite: we'll have a constant duty cycle, and vary the frequency.
4
I guess this is about energy or something like that. One guru could explain the maths here...
Jallib | PIC internals | 57
By the way, how to observe the "duty cycle effect" on the volume ? Just program your PIC with the previous
experiment one, which control the brightness of a LED, and power on the circuit. I wanted to show a video with
sounds, but the frequency is too high, my camera can't record it...
Anyway, that's a little bit boring, we do want sounds...
end loop
Quite straightforward:
• we "explore" frequencies between 0 and 100 000 Hz, using a counter
• we use pwm_set_frequency(counter) to set the frequency, in Hertz. It takes a dword as parameter (ie.
you can explore a lot of frequencies...)
• finally, as we want a 50% duty cycle, and since its value is different for each frequency setting, we need to re-
compute it on each loop.
Note: jallib's PWM libraries are coming from a "heavy refactoring" of Guru Stef Mientki's PWM library.
While integrating it to jallib, we've modified the library so frequencies can be set and changed during
program execution. This wasn't the case before, because the frequency was set as a constant.
So, how does this look like ? Hope you'll like the sweet melody :)
http://www.youtube.com/watch?v=xZ9OhQUKGtQ
SPI Introduction
Matthew Schinkel
Jallib Group
What is SPI?
SPI is a protocol is simply a way to send data from device to device in a serial fashion (bit by bit). This protocol is
used for things like SD memory cards, MP3 decoders, memory devices and other high speed applications.
We can compare SPI to other data transfer protocols:
Table 1: Protocol Comparison Chart
SPI RS-232 I2C
PINS 3 + 1 per device 2 2
Number Of Devices unlimited 2 1024
Bits in one data byte 8 10 (8 bytes + 1 start 9 (8 bytes + 1 ack
transfer bit + 1 stop bit) bit)
Must send one No No Yes
device address byte
before transmission
Clock Type Master clock only Both device clocks Master Clock that
must match slave can influence
Data can transfer Yes Yes No
in two directions at
the same time (full-
duplex)
As you can see SPI sends the least bit's per data byte transfer byte and does not need to send a device address before
transmission. This makes SPI the fastest out of the three we compared.
Although SPI allows "unlimited" devices, and I2C allows for 1024 devices, the number of devices that can be
connected to each of these protocol's are still limited by your hardware setup. This tutorial does not go into detail
about connecting a large number of devices on the same bus. When connecting more devices, unrevealed problems
may appear.
SPI Modes
If you are using a device that does not yet have a Jallib library, you will need to get the devices SPI mode. Some
device datasheets tell you the SPI mode, and some don't. Your device should tell you the clock idle state and sample
edge, with this information, you can find the SPI mode. SPI devices can be set to run in 4 different modes depending
on the clock's idle state polarity & data sample rising or falling edge.
The image above is SPI mode 1,1. See if you can understand why.
Clock Polarity (CKP) - Determines if the clock is normally high or normally low during it's idle state.
If CKP = 1 - the clock line will be high during idle.
If CKP = 0 - the clock will be low during idle.
Data Clock Edge (CKE) - The edge that the data is sampled on (rising edge or falling edge)
If CKP = 0, CKE = 0 - Data is read on the clocks rising edge (idle to active clock state)
If CKP = 0, CKE = 1 - Data is read on the clocks falling edge (active to idle clock state)
If CKP =1, CKE = 0 - Data is read on the clocks falling edge (idle to active clock state)
If CKP = 1, CKE = 1 - Data is read on the clocks rising edge (active to idle clock state)
We can put this in a chart to name the modes:
Note: I noticed the mode numbers & mode table on Wikipedia is different then the table in the Microchip
PDF. I am going by the Microchip PDF, as well as the tested and working PIC Jallib library + samples.
Wikipedia also names these registers CPOL/CPHA instead of CKP/CKE.
Jallib | PIC internals | 61
You can also send and receive data at the same time with the spi_master_hw_exchange procedure. here's an example:
-- send decimal byte 50 and receive data into byte x
var byte x
x = spi_master_hw_exchange (50)
When your done transmitting & receiving data, don't forget to disable your device
device_chip_select = low -- enable the device
Alright, now you should be able to implement SPI into any of your own devices. If you need assistance, contact us at
the Jallist Support Group or at Jallib Support Group.
References
The Jallib spi_master_hw library - Written by William Welch
Microchip Technology SPI Overview - http://ww1.microchip.com/downloads/en/devicedoc/spi.pdf
Wikipedia - http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus
Jallib | PIC internals | 63
What is USB?
USB stands for Universal Serial Bus and has replaced on may computer the standard (RS232) serial interface.
It is the most popular connection used to connect a computer to devices such as digital cameras, printers, scanners,
and external hard drives. USB is a cross-platform technology that is supported by most of the major operating
systems. On Windows, it can be used with Windows 98 and higher. USB is a hot-swappable technology, meaning that
USB devices can be added and removed without having to restart the computer. USB is also “plug and play”. When
you connect a USB device to your PC, your operating sytem should detect the device and even install the drivers
needed to use it..
There are various versions of USB. The original version of USB is USB 1.0, supporting speeds of up to 11 Mbps and
was used mostly to connect keyboards and mice. This is also the version that is supported by the JAL USB driver
although the PIC USB hardware is able to support USB 2.0 which supports speeds up to 480 Mbps. If you want to
know more about the higher USB version you can find all information on the Internet..
In the next section we will create a program that makes it possible to control the LEDs on a PIC from a (host)
computer using the USB as serial port. For the serial interface from the computer to the PIC, a free terminal emulation
program Termite is used, but any other terminal emulation program will do.
64 | Jallib | PIC internals
In the following sample program the PIC will act as a serial port. From the computer (the host) we will control two
LEDs connected to the PIC. The PIC will also send the status of the LEDs back to the computer. On the computer
side, the terminal emulation program is used for sending the control commands to the PIC and for showing the
message returned by the PIC.
-- Other fuses.
pragma target CPUDIV P1 -- NO CPU system divide
pragma target USBLSCLK F48MHZ -- System clock expects 48 MHz
pragma target PLLEN ENABLED -- 3x or 4x PLL Enabled
pragma target FCMEN DISABLED -- Fail-Safe Clock Monitor is disabled
pragma target WRT DISABLED -- Write protection off
pragma target STVR ENABLED -- Stack Overflow or Underflow will cause a Reset
pragma target LPBOR DISABLED -- Low-Power BOR is disabled
pragma target IESO DISABLED -- Internal/External Switchover Mode is disabled
pragma target PWRTE DISABLED -- power up timer
pragma target BROWNOUT DISABLED -- no brownout detection
pragma target WDT DISABLED -- Watchdog disabled
pragma target MCLR EXTERNAL -- External reset
pragma target LVP ENABLED -- allow low-voltage programming
pragma target VOLTAGE MAXIMUM -- brown out voltage
pragma target CP DISABLED -- Program memory code protection is disabled
When a PIC is reset, all pins are set to input and are floating. A good practice is to use the weak pull-up feature of the
PIC to pull the inputs high. When making a pin output the weak pull-up for that pin is disabled. For this PIC only
port A has the weak pull-up feature and because of that we make port C output so that the pins are not floating.
-- Enable weak pull-up for port a and and set port c to output just to
-- have no floating input pins.
OPTION_REG_WPUEN = FALSE -- Enable weak pull-up for port a.
WPUA = 0b0011_1111 -- Weak-pull up for all inputs.
TRISC = 0b0000_0000 -- Port c output.
Now include the Jallib USB library. Since we will send information back to the computer we want to format it nicely
so we also include the Jallib print library. We will also define the pins including some aliases to make the program
more readable.
-- Include serial library and print library for formatting print output.
include usb_serial
include print
This program uses a few variables, one for the character that is received from the computer and two bit variable to
hold the status of the Red and Green LED.
-- Variables.
var byte character
var bit red_value, green_value
Last but not least is the main part of the program which does the following:
• Initialize the usb library
• Initialize (clear) all LEDs
• Report if the PIC USB device is configured
• Keep the USB going by frequently calling the function usb_serial_flush()
Note: The USB driver can also be used on an interrupt basis as described in the USB library and the
USB sample programs. In that case the usb_serial_flush() is not required
• Handle the commands sent by the computer and control the LEDs accordingly. A single character command will
toggle the status of the LED from on to off or the other way around
• Return the status of the controlled LED to the computer after a command was received
• Return an error message if an incorrect command was received
The main program then becomes as follows.
-- ------------- The main program starts here ------------------------
66 | Jallib | PIC internals
-- LEDs off.
led_yellow = FALSE
red_value = FALSE
green_value = FALSE
forever loop
end loop
The complete program can be found in the sample directory of the latest Jallib release under the name
16f1455_tutorial_usb_serial.jal.
In this video you can see the program in action. Commands are entered in the terminal emulation program, LEDs
are switched on and off and the response of the PIC is returned to the computer. Some additional info that is worth
mentioning:
• In order to initialize the PIC as USB device you have to enable RTS/CTS
• The USB serial baudrate and number of bits is not relevant
• Since we are using single character commands make sure to disable sending carriage return and/or linefeed after
the character was entered, otherwise the PIC will return that as an unsupported command.
Chapter
3
Experimenting with external parts
Topics: You now have learned enough to be able to begin interfacing your PIC with external parts.
Without being exhaustive, this chapter explains how to use a PIC with several commonly
• Hard Disks - IDE/PATA
used parts, such as an LCD screen.
• IR Ranger with Sharp
GP2D02
• LCD Display - HD44780-
compatible
• Memory with 23k256
sram
• RC Servo Control & RC
Motor Speed Control
• SD Memory Cards
• DFPlayer Mini
68 | Jallib | Experimenting with external parts
Jallib | Experimenting with external parts | 69
Actual Size
The most common drive sizes today are 3.5" and 2.5". The 3.5 inch drives are commonly used in desktop computers,
2.5" drives are used in laptops. The 2.5" drives are nice for your circuit because they do not require a 12v supply
voltage, and they use much less power.
If you wish to use a 2.5" laptop hard drive, you may need a 2.5" to 3.5" IDE adapter like this one:
Circuit Power
It is very important that you have enough power to drive your circuit. Hard drives need a lot of amps to run,
especially the 3.5" drives, so make sure you have a decent 5v and 12v power supply. I suggest that you DO NOT use
your PC's power supply to drive your circuit. You can easily short circuit your power supply and blow up your PC.
If you really insist on doing this, you better put a fuse on both 5v and 12v between your PC and your circuit. Just
remember that I told you not to!
Here's what the completed circuit should look like (don't turn on the power yet):
Jallib | Experimenting with external parts | 73
Power It Up
Plug your circuit into your PC for serial port communication at 115200 baud rate. Now turn it on. You should get data
similar to the image below onto your serial port. You will also hear the hard drive turn on and off because of one of
the examples in the sample file.
Serial Port Output
Some of the data is not shown in the above image. If your disk is formatted with fat32 you may be able to see some
readable data from the boot sector. On my drive formatted with fat32 I can read "Invalid partition table Error loading
operating system" (not shown in the image). The AA BB CC DD EE are read/write examples that will be shown
below. The last set of data is from the Identify Drive command.
You now have a working hard disk circuit!
I have left a few ways to read and write to hard disks. The usage you choose may will on the PIC data space you have,
and what your application is. On a smaller PIC, you will only be able to run examples #1, #2, #5 and #6. I'll explain
as I go.
Example #1 - Read data at sector 0
This is a low memory usage way of reading from the hard disk, however it is slower then some of the other examples
later on. This method requires the use of pata_hd_start_read(), pata_hd_data_byte, and pata_hd_stop_read(). You'll
see that the usage is quite simple.
Note: The variable pata_hd_data_byte is not actually a variable, it is a procedure that looks & acts like a
regular variable. This is called a pseudo variable. You may use this variable to read data or write data, as
shown in these examples.
The steps are:
1. Start reading at a sector address. In this case, sector 0 (the boot sector)
2. Loop many times while you read data. One sector is 512 bytes, we will read two sectors.
3. Store each byte of data into the variable "data". You can retrieve the data by reading the pseudo variable
pata_hd_data_byte
4. Do something with the data. Let's send it to the serial port.
5. End the loop
6. Tell the hard disk we are done reading. The hard disk light will go out at this step.
pata_hd_start_read(0) -- get sd card ready for read at sector 0
for 512 * 2 loop -- read 2 sectors (512 * 2 bytes)
data = pata_hd_data_byte -- read 1 bytes of data
serial_hw_write(data) -- send byte via serial port
end loop
pata_hd_stop_read() -- tell sd card you are done reading
Ok, we're done our example, so lets separate it from the next one with the separator() procedure to send some "-----"
characters and a small delay.
separator() -- separate the examples with "----"
_usec_delay(500_000) -- a small delay
Example #2 - Writing data
This example is similar to example #1, but we will be writing data to the hard disk. It requires low memory usage.
As with the first example, we will be required to use 3 procedures. pata_hd_start_write(), pata_hd_data_byte and
pata_hd_stop_write()
Here are the steps:
1. Start writing at a sector address. I choose sector 20 since it seems that it will not mess up a fat32 formatted drive, I
could be wrong!
2. Loop many times while you write your data. In this example, I am writing to 1 sector + 1/2 sector. The 2nd half of
sector 2 will contain all 0's. The end of sector 2 will contain 0's because hard disks will only write data in blocks
of 512, and therefore any data you have there will be overwritten.
3. Write some data. This time we are setting the value of the pseudo variable pata_hd_data_byte. Writing to this
variable will actually send data to the hard disk. We are sending "A", so you will expect to read back the same
data later on.
4. End your loop
5. Tell the hard disk we are done writing. The hard disk light will go out at this step.
pata_hd_start_write(20) -- get sd card ready for write at sector 20
for 512 + 256 loop -- loop 1 sector + 1 half sector (512 + 256 bytes)
pata_hd_data_byte = "A" -- write 1 bytes of data
end loop
pata_hd_stop_write() -- tell sd card you are done reading
Now of course you will want to read your data back, which will be the same as in example #1, but at sector 20.
pata_hd_start_read(20) -- get sd card ready for read at sector 20
for 512 + 256 loop -- loop 1 sector + 1 half sector (512 + 256 bytes)
data = pata_hd_data_byte -- read 1 bytes of data
78 | Jallib | Experimenting with external parts
Your Done!
That's it, Now you can read & write to all those hard drives you have laying around. You can read raw data from
drives and possibly even get back some lost data.
Alright, go build that hard disk thingy you where dreaming about!
Jallib | Experimenting with external parts | 81
Sharp IR rangers are widely used out there. There are many different references, depending on the beam pattern, the
minimal and maximal distance you want to be able to get, etc... The way you got results also make a difference: either
analog (you'll get a voltage proportional to the distance), or digital (you'll directly get a digital value). This nice
article will explain these details (and now I know GP2D02 seems to be discontinued...)
I've also added thermoplastic rubber tubes, to cleanly join all the wires:
Jallib | Experimenting with external parts | 83
Finally, in order to easily plug/unplug the sensor, I've soldered nice polarized connectors:
gp2d02_vout_direction = input
A sample file 16f88_ir_ranger_gp2d02.jal, is available in the sample directory of the jallib released packages.
I usually power two tracks on the side, used for the PIC and for the ranger:
Jallib | Experimenting with external parts | 85
Using the same previously created mental note, I connected the yellow Vout pin using a yellow wire, and the green
Vin pin using a green wire...
In this "Step by Step" tutorial, we're going to (hopefully) have some fun with a LCD display. Particularly one
compatible with HD44780 specifications, which seems to be most widely used.
Looking closer, "JHD 204A" seems to be the reference. Near the connector, only a "1" and a "16". No pin's name.
Jallib | Experimenting with external parts | 87
Googling the whole points to a forum, and at least a link to the datasheet. A section describes the "Pin Assignement".
Now I'm sure about how to connect this LCD.
88 | Jallib | Experimenting with external parts
So we now have everything to build the circuit. Here's the schematic. It also includes a LED, it will help us checking
everything is ok while powering up the board.
Jallib | Experimenting with external parts | 89
As usual, writing a program with jallib starts with configuring and declaring some parameters. So we first have to
declare which pins will be connected:
-- LCD IO definition
var bit lcd_rs is pin_a6 -- LCD command/data select.
var bit lcd_rs_direction is pin_a6_direction
var bit lcd_en is pin_a7 -- LCD data trigger
var bit lcd_en_direction is pin_a7_direction
-- set direction
lcd_rs_direction = output
lcd_en_direction = output
lcd_dataport_direction = output
This is, pin by pin, the translation of the schematics. Maybe except porta_low. This represents pin A0 to A3, that
is pins for our 4 lines interface. porta_high represents pin A4 to A7, and porta reprensents the whole port, A0 to
A7. These are just "shorcuts".
We also have to declare the LCD geometry:
const byte LCD_ROWS = 4 -- 4 lines
const byte LCD_CHARS = 20 -- 20 chars per line
Once declared, we can then include the library and initialize it:
include lcd_hd44780_4 -- LCD library with 4 data lines
lcd_init() -- initialize LCD
For this example, we'll also use the print.jal library, which provides nice helpers when printing variables.
include print
Now the main part... How to write things on the LCD.
• You can either use a procedure call: lcd_write_char("a")
• or you can use the pseudo-variable : lcd = "a"
• lcd_cursor_position(x,y) will set the cursor position. x is the line, y is the row, starting from 0
• finally, lcd_clear_screen() will, well... clear the screen !
Full API documentation is available in the jallb release.
So, for this example, we'll write some chars on each line, and print an increasing (and incredible) counter:
const byte str1[] = "Hello world!" -- define strings
const byte str2[] = "third line"
const byte str3[] = "fourth line"
end loop
The full and ready-to-compile code is available on jallib repository
You'll need latest jallib-pack, available on jallib's download section.
Learn how to use Microchip's cheap 256kbit (32KB) sram for temporary data storage
If speed is your thing, this one is for you! This is FAST. According to Microchip's datasheet, data can be clocked in
at 20mhz. The disadvantage to this memory however is that it will not hold it's memory when power is off since it is a
type of RAM (Random Access memory).
If you wish to hold memory while power is off, you will have to go with EEPROM but it is much slower. EEPROM
requires a 1ms delay between writes. In the time that I could write 1 byte to an EEPROM (1ms), I could write 2500
bytes to the 23k256 (if I can get my PIC to run fast enough).
Yet another advantage, is that it is only 8 pins (as you can see from the image). Other RAM memories have 10 or so
address lines + 8 data lines. If you haven't guessed yet, we are sending serial data for reads & writes. We will be using
SPI (Serial Peripheral Interface Bus).
I suggest you start by reading the SPI Introduction within this book first.
You can read more about the 23k256 here:
https://www.microchip.com/en-us/product/23K256
Note: Jallib version 0.5 had this following line in the library file, but in the next version (0.6) it will
be removed from the library and you will have to add it to your sample file before the line include
sram_23k256.
const bit SRAM_23K256_ALWAYS_SET_SPI_MODE = TRUE
Here's the 23K256 pin-out diagram:
Now build this schematics. Notice the resistors for 5v to 3.3v conversion. Also notice that we are using the PIC's
hardware SPI port pins. These pins are named (SDO, SDI, SCK) + One chip select pin of your choice.
Note: This is a 3.3V Device
Plug in your serial port and turn it on (serial baud rate 38400). If it is working, you will get mostly the hex value "11"
to your PC's serial port. Here's an image from my serial port software:
Jallib | Experimenting with external parts | 95
If it is not working, lets do some troubleshooting. First start by checking over your schematic. If your schematic is
correct, the most likely problem is voltage levels. Check over your PIC's datasheet to see what the PIN types are, if
any of the pins have CMOS level outputs, you will not need voltage conversion resistors.
In the past, I have had issues with the voltage conversion resistors on the SCK line.
23k256 Usage
I'm going to go over this quickly since the code is simple.
Read & Write Byte
Write hex "AA" to address 1:
sram_23k256_write(1,0xAA) -- write byte
Now read it back:
var byte data
sram_23k256_read(1, data) -- read byte
Byte Array
You can use the 23k256 as a large byte, word or dword array like this:
-- Example using 23k256 as a 32KByte array (at array address 2)
var byte data1
sram_23k256_byte[2] = 0xBB -- set array byte 2 to value 0xBB
data1 = sram_23k256_byte[2] -- read array byte 2, data2 should = 0xBB
If you are looking for a quick way to write lots of data, you can use the start_write, do_write and stop_write
procedures. You should not use any other SPI devices on the same SPI bus between start_write() and stop_write()
sram_23k256_start_write (word in address) -- sets the address to write to
sram_23k256_do_write (byte in data) -- send the data
sram_23k256_stop_write() -- stops the write process
Here's an example:
-- Example fast write lots of data
sram_23k256_start_write (10)
for 1024 loop
sram_23k256_do_write (0x11)
end loop
sram_23k256_stop_write()
This works the same for the read procedures:
sram_23k256_start_read (word in address) -- sets the address to read from
sram_23k256_do_read (byte out data) -- get the data
sram_23k256_stop_read() -- stop the read process
-- Example fast read lots of data
sram_23k256_start_read (10)
for 1024 loop
sram_23k256_do_read (data1)
serial_hw_write (data1)
end loop
sram_23k256_stop_read()
Your done, enjoy!
98 | Jallib | Experimenting with external parts
PIC RC servos and RC speed controllers used in the Radio Control hobby.
The only way to really know how something really works is to take it apart! I found some gears, a potentiometer
some electronics and a motor. The servos gears are to give it the strength it needs to move whatever it is you want to
move in your project. The servo knows it's position by reading a voltage off the potentiometer that gets turned by the
gears which of course gets turned by the motor. After a signal is given, the servo will move to the correct location.
Jallib | Experimenting with external parts | 99
To control a servo, we need to send it a PWM (pulse width modulation) signal. Thankfully it will all be taken care of
by the Jallib library I have created. A pulse will be sent every 20ms, and each pulse will be a width between 0.5ms
and 2.5ms. The pulse width will vary depending on the position you have chosen. Servo pulse width required can
very depending on the servo manufacturer, therefore the library has been created with some default values that you
may change to get a full movement from left to right.
Here's a YouTube video of one servo moving and it's signal on my oscilloscope: http://www.youtube.com/watch?
v=zA3anG0YZD4
Servos come with a verity of connector types but always have 3 wires. One is ground, one is power and the other is
signal.
Here's an image of my RC servo connector (left), I will use some pins (right), to plug my servo into my breadboard.
There are two ways of implementing servos into your project. You may either have your servos connected to your
main PIC, or to an external PIC. For smaller projects you will choose to control your servo from your main PIC, this
is the method I will show you.
If your main PIC is needed to run some heavy code, or if you need more then 24 servos, you may wish to use external
PIC(s) via I2C interface. There is a library and two samples for using an external PIC via I2c bus. I will not discuss
this method here.
The schematic is very very simple, just take your blink circuit and plug in your servo.
The Code
Since your main PIC will be controlling the servos, the PIC is acting as a master device and therefore we will be using
the servo_rc_master library.
The library can be found under Jallib SVN at trunk\include\external\motor\servo\servo_rc_master.jal
The sample can be found in the Jallib SVN at trunk\sample\18f4620_servo_rc_master.jal
You can access the Jallib dowload site at http://justanotherlanguage.org/downloads
Let's start by including your PIC, and disable all analog pins
-- include chip
include 18f4620 -- target PICmicro
pragma target clock 20_000_000 -- oscillator frequency
-- configuration memory settings (fuses)
pragma target OSC HS -- HS crystal or resonator
pragma target WDT disabled -- no watchdog
pragma target LVP disabled -- no Low Voltage Programming
pragma target MCLR external -- reset externally
Jallib | Experimenting with external parts | 101
servo_move(255,1)
servo_move(0,2)
_usec_delay (1_000_000)
led = !led
servo_move(0,1)
servo_move(255,2)
_usec_delay (1_000_000)
led = !led
end loop
So, that's it for the code. Simple right? I wish writing the library was that easy!
You can go ahead and turn on your circuit, you should see the led blink and the servos should be moving. Change and
test your servo pinouts if needed. The two servos will move in opposite directions since my servo_move() procedure
call values are different for each servo.
At this point, you should turn off the power when your servos are at the center position. We are turning the power off
so you may remove the moving part on the top of your servo, and place it back on so it looks centered.
Here's a YouTube video of my two moving servos http://www.youtube.com/watch?v=QS8M07uuagY
SD Memory Cards
Matthew Schinkel
Jallib Group
In this tutorial we will learn how to use an SD Card for mass data storage.
SD Card Introduction
SD Cards (Secure Digital Cards) are quite popular these days for things like digital camera's, video camera's, mp3
players and mobile phones. Now you will have one in your project! The main advantages are: small size, large data
storage capability, speed, cost. It has flash storage that does not require power to hold data. The current version of the
sd card library that we will be using in this tutorial works with "standard capacity" sd cards up 4gb in size. I hope to
find time to add "high capacity" and "extended capacity" capability to the library.
SD Card have 2 data transfer types "SD Bus" and "SPI Bus". Most PIC's have an SPI port. The "SD Bus" is faster,
however uses more pins. We will be using SPI in our circuit. For more info on SPI read the tutorial in this book: SPI
Introduction. The SPI mode for SD Cards is 1,1.
We are not responsible for your data or SD card. Make sure you have nothing important on your SD card before you
continue.
These SD Cards are 3.3v devices, therefore a 5v to 3v conversion is needed between the PIC and the sd card. We will
use resistors to do the conversion, however there are many other methods. See https://ww1.microchip.com/downloads/
en/DeviceDoc/chapter%208.pdf for more information.
My favorite way of converting 5v to 3v is with 74HCT08. It must be HCT (not LS). 74LS08 will not work on a 3.3v
power supply.
This circuit will use 16F877 If you are using a different PIC for your project, refer to the PIC's datasheet for pin
output levels/voltage. For example, 18F452 has many pins that are 5v-input that give 3v-output. These pins show
as "TTL / ST" - TTL compatible with CMOS level outputs in the datasheet and they will not require any voltage
conversion resistors. If you are not sure, set a pin as an output, and make it go high then test with a volt meter.
Jallib | Experimenting with external parts | 105
Power It Up
Plug your circuit into your PC for serial port communication at 38400 baud rate. Now turn it on. Press the reset button
in your circuit, you should get a result similar to this:
Serial Output
As you can see from the image, we got some actual readable data off the sd card as well as a bunch of junk. My sd
card is formated with fat32, this is why I can actually read some of the data.
You now have a working sd card circuit!
Sources
The Jallib SD Card Library - Written by Matthew Schinkel
Jallib | Experimenting with external parts | 113
DFPlayer Mini
Rob Jansen
Jallib Group
Introduction
This JAL Library supports all features of the DFPlayer Mini, an audio playback device.
The library is set up in a way that the main program determines which serial interface is being used for controlling
the DFPlayer Mini. Three sample files are available, a simple version called 16f1823_dfplayer.jal
that plays the first track, waits for 10 seconds and then plays the next track. The other sample program called
16f19176_dfplayer.jal uses a menu structure with which all features of the library can be controlled. The
third sample called 12f617_dfplayer.jal shows the same functionality as the 16f1823 version but this version
is meant to show that it can work on a smaller PIC that has no on-board USART so it uses the JAL software serial
interface library to control the DFPlayer Mini.
The Hardware
The DFPlayer Mini is controlled via the serial interface using a fixed baudrate of 9600 baud. It can operate on 5 Volt
but it is recommended to use 1k resistors in the serial communication lines between the PIC and the DFPlayer Mini.
The DFPlayer Mini plays audio files in mp3 or wav format, stored on e.g. a micro sd card that can be inserted into the
device. A loudspeaker can be connected directly to the DFPlayer Mini of which the volume can be controlled via the
API provided by the library.
The schematic diagram below shows how the DFPlayer mini can be connected to the pic12f617.
At reset all pins of the PIC are set to analog input. Switch them to digital. Note that we also wait some time here. It
can happen that a PIC needs some more time to stabilize after power up so we add a delay here before we continue
with the rest op the program..
enable_digital_io()
-- Give the hardware some time to stabilize.
Jallib | Experimenting with external parts | 115
_usec_delay(100_000)
This PIC does not have a serial interface on board, the so called USART. Instead we use a software library that
emulates a serial port. We have to define which pins we are going to use for the serial interface. After that we can
include the serial software library and initialize it.
-- Setup the serial software interface for communication with the DFPlayer.
alias serial_sw_tx_pin is pin_GP4 -- Pin 3 of 8 pin DIP.
pin_GP4_direction = output
alias serial_sw_rx_pin is pin_GP5 -- Pin 2 of 8 pin DIP.
pin_GP5_direction = input
const serial_sw_baudrate = 9600
include serial_software
serial_sw_init()
The next step is to include the library of the DFPlayer mini and start playing an audio track. In this example we first
set the volume, start playing track 1 and play a next track after every 10 seconds. For the 10 seconds delay we use a
delay_1s() function from the delay library so we need to include that library too .
include delay
-- Play the first track that the DFPlayer found on the storage device.
dfplayer_play(1)
forever loop
-- Play each track for 10 seconds the go to the next available track.
dfplayer_play_next()
delay_1s(10)
end loop
The following video shows this sample program in action. The micro as card has one folder called '01' which has
five mp3 tracks labeled '001.mp3' to '005.mp3'.
Some more info about the DFPplayer Mini that you should know
Audio files are stored in a certain folder structure. This structure is documented in the dfplayer.jal library and is
defined as follows:
• Folders used must be named 01 to 99, ADVERT or MP3
• Audio files are numbered 001 to 255 or 0001 to 3000 with extension .mp3 or .wav
• Folders 01 to 15 can contain audio files named 001 to 255 and 0001 to 3000, these are the so called special 3000
track folders
• Folders 16 to 99 can contain audio files with names 001 to 255
• Folder ADVERT can contain advertisement audio files named 0001 to 3000
• Folder MP3 can contain mp3 only audio files named 0001 to 3000
So audio files (tracks) are always numbers and they have to be exactly 3 or 4 digits with the extension .mp3 or .wav.
Note that some API functions only work on files with 3 digits and some other on audio files with 4 digits. It is
possible to combine these different files in folders 01 to 15, so you could have audio files in these folders like
001.wav, 1234.mp3.
To play track 011.wav from folder 02 you the procedure call is dfplayer_play_folder(2,11)
but if you want to play track 1234.wav from the same folder with number 02 the procedure call is
dfplayer_play_3000_folder(2, 1234). When calling procedure dfplayer_play_advertisement(2000), the
DFPlayer will interrupt the playback of the current track, plays the advertisement track 2000 (.wav or .mp3) from the
ADVERT folder and will resume play after the advertisement track has completed.
The module has some other special features like a repeat track, repeat folder and an equalizer. It also has a sleep
function that can be called via the API of the library but the only way to wakeup the DFPlayer after sleep is by
switching the power off and on again.
116 | Jallib | Experimenting with external parts
The tests of the library where done with the folders and files stored on a micro sd card but the module and the library
also supports other storage devices.
This library was immediately used by one of the JAL users. The result of this project can be seen in the video of
Bobby .
Chapter
4
PIC software
Topics: Learn about software libraries that will help you on your journey. These software libraries
may run on hardware you already connected from other tutorials.
• Print & Format
• FAT32 File System
• Large Array
118 | Jallib | PIC software
Jallib | PIC software | 119
Now let's have a look at the format library. you will see 3 alike procedures with names:
1. format_byte_dec - Formats a byte in decimal.
2. format_word_dec - Formats a word in decimal.
3. format_dword_dec - Formats a dword in decimal.
These format procedures are able to format a byte, word or dword. Here are the input parameters:
1. device - Same as print library.
2. data - The data to be sent to the device.
3. n_tot - The total length of the outputted number (Including sign' +/-', and decimal point)
4. n2 - The number of decimal places.
The following example will write 61.234 to the serial port in ASCII format:
var dword_dec x = 61234
format_dword_dec(serial_hw_data,x,6,3)
Printing Strings
The print library also has a procedure for printing strings. called print_string. It requires 2 inputs:
1. device - same as above.
2. str[] - The string to print to the serial port (an array of characters).
Here's an example that will output "Hello World" to the serial port in ASCII format:
const byte hello_string[] = "Hello World"
print_string(serial_hw_data, hello_string)
Note: the constant array must be a byte array.
Last of course, you may need to go to the next line with carriage return + line feed (CRLF).
print_crlf(serial_hw_data)
CRLF can also be put directly into your string with "\r\n". This will put Hello and World on 2 separate lines.
const byte hello_string[] = "Hello\r\nWorld"
print_string(serial_hw_data, hello_string)
include print
include format
const byte string2[] = "Let's print a dword with 3 decimal places: "
print_string(serial_hw_data,string2)
format_dword_dec(serial_hw_data,x,6,3)
print_crlf(serial_hw_data)
const byte string4[] = "If we print as a hex byte, it will be truncated: "
print_string(serial_hw_data,string4)
print_byte_hex(serial_hw_data, byte(x) )
There you go... that's print and format! Doesn't this make life so easy!
122 | Jallib | PIC software
FAT32 Intro
If you made it here, you either have or are thinking about putting some storage device into your project. Of course
you may want to use FAT32 or some type of file system if you are using a device such as a SD card or hard disk with
a huge amount of storage space. You could read or write directly to your storage device if you wanted wish, so why
use a file system such as FAT32? It is an easy way to manage data and to access data via a PC, it is user friendly for
building your product and also good for users of your product.
Fat32 can be read by the most popular operating systems. Of course, FAT32 is a Microsoft product used in Windows,
but Linux and MAC OS can also read FAT32. Jallib also has Minix V2 file system available.
This tutorial will concentrate on the normal FAT32 library. There will be a separate tutorial for FAT32 SMALL
whenever I find time!
Note: Always get the newest library and sample. I suggest you download the newest Jallib Bee package
from http://justanotherlanguage.org/downloads
SD cards - SD cards are popular thanks to their small size. They are quite easy to connect to your circuit. The hookup
will cost you 4 PIC pins via SPI port. They are slower then hard disks due to serial data transfer via SPI port. Most
SD Cards also have an endurance of 100,000 write cycles. They run on 3.3v.
Hard Disk - Hard drives are fast but large. The main sizes of hard disks are 3.5", 2.5" and 1.8". Connecting them to
your circuit is simple, but will require 21 pins. I did actually fit sd card + hard disk in one circuit on 18f4620. Hard
drives have an unlimited number of write cycles. They run at 5v TTL levels, but will accept 3.3v on it's inputs. You
can run your PIC at 3.3v or 5v.
Suggested Tutorials
1. Getting Started
2. Blink a led
3. Serial Communication
4. SD Card OR PATA Hard DIsk
5. 23k256
Benefits of ICSP
1. You may program your PIC while it is in your breadboard circuit
2. You may program your PIC while it is on a soldered circuit board
3. You will save time programming so you can write more code faster
4. You can reset your circuit from your PC
5. You can program surface mount PIC's that are on soldered circuit board
6. You won't bend or break any pins
7. You won't damage your PIC by placing it in your breadboard wrong
8. With a remote desktop software like VNC, you can program your PIC from anywhere around the world.
9. I can program my PIC in my living room on my laptop while I watch tv with my wife! (I keep my mess in my
office)
The Schematic
Your schematic will be the same as either the hard disk or sd card tutorial. If you wish to use external memory, you
can add a 23k256. I'll explain external memory later on. Although the schematics show 16f877, you can replace it
with 18f4620. 16F877 is not large enough.
124 | Jallib | PIC software
Jallib | PIC software | 125
Some Images
Run a sample
If you've already done a previous sd card or hard disk tutorial, you know you have a working circuit. I suggest you try
one of the following samples:
18f4620_fat32_pata_hard_disk.jal
18f4620_fat32_sd_card.jal
Start by formatting your storage device in windows. Then put a few files and a directory on it. In this example I put 4
files and one directory.
Set your serial port to 115200 baud. If all is good, you should get a directory listing on your serial port software:
126 | Jallib | PIC software
The Code
Alright then, we're ready to get our hands dirty. Let's take a look
Jallib | PIC software | 127
Required Includes
The first part of the sample is just a bunch of includes, I'm not going to cover the first includes to much since they are
covered in other tutorials. When we get to the fat32 include, I'll give more detail.
-- Title: FAT32 library for reading fat32 filesystem
-- Author: Matthew Schinkel, copyright (c) 2009, all rights reserved.
-- Adapted-by:
-- Compiler: >=2.4k
--
-- This file is part of jallib (http://jallib.googlecode.com)
-- Released under the BSD license (http://www.opensource.org/licenses/bsd-
license.php)
--
-- Description: this example reads files & folders from a fat32 formatted sd
card
-- using the fat32 library.
--
-- Sources:
-- http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
-- http://www.pjrc.com/tech/8051/ide/fat32.html
-- http://en.wikipedia.org/wiki/File_Allocation_Table
--
-- include chip
include 18f4620 -- target picmicro
-- this program assumes a 20 mhz resonator or crystal
-- is connected to pins osc1 and osc2.
pragma target osc INTOSC_NOCLKOUT -- hs crystal or resonator
;pragma target osc hs -- hs crystal or resonator
;pragma target clock 20_000_000 -- oscillator frequency
pragma target clock 32_000_000 -- oscillator frequency
--
pragma target wdt disabled
pragma target lvp disabled
pragma target MCLR external -- reset externally
--;
;OSCCON_IRCF = 0b110 -- set int osc to 4mhz
OSCCON_IRCF = 0b111 -- set internal osc to 8mhz
OSCTUNE_PLLEN = true -- multiply internal osc by 4
;--
enable_digital_io() -- make all pins digital I/O
--
_usec_delay(100_000) -- wait for power to settle
include delay
include print
size, cluster address etc. This way the entire file name list does not need to be stored in RAM. Only the location of the
file name gets stored.
FAT32_USE_INTERNAL_MEMORY - Choose where to store FAT32's file location table (internal memory or
external memory). This is related to FAT32_FILES_MAX. If you have 50 files max, each file will take 2 bytes
of ram, so 100 bytes ram. Choose weather you want this 100 bytes of ram to be used internally or on an external
memory device. For external memory, I very much suggest external RAM or something fast and with a high
endurance (write cycles) like 23k256. This will of course affect the "if" statement that follows this constant.
Within the FAT32_USE_INTERNAL_MEMORY "if" statement, you will need to define an array named
"fat32_entry_location". This array can be a real array, a large array (through the large array lib) or a pseudo array. If
you look in the 23k256 lib, you will see that sram_23k256_word[] is a pseudo (fake) array. For external memory we
simply alias a pseudo array "alias fat32_entry_location is sram_23k256_word"
And of course, here is a sample block for including fat32. You can keep the defaults for now and mess around with
them later. I kept the values low to save RAM space.
-- setup fat32 --
-- include the required files
;include pic_data_eeprom
-- change these vaues to save memory
const bit FAT32_WRITE_LONG_FILE_NAMES = FALSE -- support writing of long file
names
const word FAT32_FILES_MAX = 20 -- the max number of files allowed
in a directory
const byte FAT32_FILE_NAME_SIZE = 80 -- choose max file_name size. if a
file_name is longer the this, beginning chars will be cut. short file_names
are 12 bytes.
const FAT32_DIR_FRAGMENTS_TO_ALLOW = 5 -- uses 6 bytes memory per fragment
allowed (0 not allowed)
-- -- windows defrag does not
defragment directories.
const FAT32_FILE_FRAGMENTS_TO_ALLOW = 5 -- uses 8 bytes memory per fragment
allowed (0 not allowed)
--
-- experts may change the following values
;const byte FAT32_ENTRIES_MAX = 1 -- highest file entry address can
be 256
const byte FAT32_ENTRIES_MAX = 2 -- highest file entry address can
be 65535
--
-- choose a memory source for the file list
const bit FAT32_USE_INTERNAL_MEMORY = TRUE -- Use internal memory for file
location list
IF FAT32_USE_INTERNAL_MEMORY == TRUE THEN
-- Setup a large array for storing sector data, This is where file_name
locations are stored
const dword LARGE_ARRAY_2_SIZE = FAT32_FILES_MAX -- choose
number of array variables
const dword LARGE_ARRAY_2_VARIABLE_SIZE = FAT32_ENTRIES_MAX -- choose
bytes size of variables
include large_array_2 -- include the array library
ALIAS fat32_entry_location is large_array_2
elsif FAT32_USE_INTERNAL_MEMORY == FALSE THEN
-- put your own code here if you wish to allow massive amounts of files per
directory
END IF
--
include fat32 -- include fat32 library -- include fat32
You may want to filter out some files such as hidden or system files which you may not need in your project.
-- CHOOSE FILE ATTRIBUTES TO FILTER OUT
fat32_filter_is_read_only = FALSE
fat32_filter_is_hidden = FALSE
fat32_filter_is_system = FALSE
fat32_filter_is_volume_id = FALSE
fat32_filter_is_directory = FALSE
fat32_filter_is_archive = FALSE
The main program
Well then, your ready for the main program. First we have a few inital settings.
I have created a simple seperator procedure to send a line "-----------" via serial port.
-- procedure for sending 80 "-----------------" via serial port
procedure separator() is
serial_data = 13
serial_data = 10
const byte str3[] =
"--------------------------------------------------------------------------------"
print_string(serial_data, str3)
print_crlf(serial_data)
end procedure
R - Is read only
fat32_print_directory(serial_data, FAT32_PRINT_ALL) -- sends dir listing via
serial port
Of course, you could just print one file name at a time instead. This could be useful on an LCD where you can only
view a certain number of files at a time, and scrolling is needed.
-- read 3rd file's name, location, size, attributes into memory
fat32_read_file_info(3)
-- now send the filename via the serial port (file number and file name)
fat32_print_file_info(serial_data,FAT32_PRINT_NUMBER +
FAT32_PRINT_LONG_FILE_NAME)
Declare some variables we're going to use, then start our main loop
var byte data
var dword step1
var word step2
var byte file_number = 0
forever loop
separator() -- send "-----" then loop and wait for user input
This example is a user program, so we will wait for the user. The user can send data to the device via serial port to
select a file number. So, let's wait for data.
Note that the serial software library does not contain a serial_data_available variable.
When we get data from the user, it will be placed into our variable file_number.
file_number = serial_data
Now we can either check the file's attributes to see if it is a file or directory (see fat32_file_attrib in fat32.jal), or we
can simply try to go into the directory. If we fail to go into the directory, it must be a file.
If we do go into the directory, we will print the new directory to the screen.
-- choose a file for reading or dir for opening
if fat32_cd(file_number) then -- if change directory is
successful
fat32_print_directory(serial_data, FAT32_PRINT_ALL) -- print dir listing
Otherwise (if it is not a directory), we will open the file.
elsif fat32_file_open(file_number) then -- if go into file is successful
Calculate the number of sectors in a file
The fastest way to read files is by reading them sector by sector. We'll need to calculate how many sectors are in the
file so we can use a for loop later on.
-- calculate number of sectors in file
var dword sectors_available
if (fat32_file_size) == (fat32_file_size / 512) * 512 then
sectors_available = (fat32_file_size / 512)
else
sectors_available = (fat32_file_size / 512) + 1
end if
Reading & writing
While writing the FAT32 library, I wanted to give some different ways for the code writer to read & write to a file.
1. Read any byte from a file at any address.
a. fat32_read_file_byte_address(address) - function that returns a byte from any byte address in the file.
132 | Jallib | PIC software
2. A faster way to read byte by byte. Still slower then sector reads. It is not so user friendly since you must call a few
procedures. Only reads starting at the beginning of a file. If you are using an sd card and have other SPI devices
connected, do not use them until you do stop_file_read.
a. fat32_start_file_read() - start reading a file from the beginning
b. fat32_read_file_byte() - read one byte
c. fat32_stop_file_read - stop reading
3. A very fast & user friendly way to read and write to a file at any sector address of the file.
a. fat32_sector_buffer[] - a 512 byte array that stores data to be read or written
b. fat32_read_file_sector_number(address) - Call this to read data into the buffer from any address.
c. fat32_write_file_sector_number(address) - Call this to write sector buffer to media at any address.
4. The fast way to read and write to a file. A little bit faster then #3. Not as user friendly. You must start reading or
writing at the beginning of the file. Read and write sector by sector by filling fat32_sector_buffer[]
a. fat32_sector_buffer[] - a 512 byte array that stores data to be read or written
b. fat32_start_file_write() - start writing to a file, starting at the beginning of the file.
c. fat32_stop_file_write() - stop writing to a file
d. fat32_start_file_read() - start reading from a file, starting at the beginning of the file.
e. fat32_stop_file_read() - stop reading from a file
Well, as you can see you have a lot of options. Our sample uses #3 (fast and user friendly). It really depends on your
application. If you are recording sound, you may want #4 since you'll be starting at the beginning of the file. If you
are jumping around in the file, you may want #3. Of course #3 would be perfectly sufficient for recording sound.
You'll just have to try them out!
I'll give a bit more explanation of #3. You will obviously either read from the storage device or write to the storage
device.
For writing, you will first fill the sector buffer with data, then when you call
fat32_write_file_sector_number(address), the library will transfer the data from the buffer onto the storage device.
-- EXAMPLE 3 WRITE (fast and user friendly)
-- Read from any sector number in the file, in any order you wish.
for sectors_available using step1 loop
Well, that was awsome, let's wrap this up! You should close the file when your done with it, just to ensure your
storage device goes ready. On a hard disk, you will see the disk LED go off.
fat32_file_close()
end if
end loop
What's that now? You want to see an example of this working? I guess it's time for a Youtube Video! You can see me
easily moving around in files & directories, and even transferring an MP3 to my PC via Realterm!
http://www.youtube.com/watch?v=ar7DkTPriNk
Have fun!
134 | Jallib | PIC software
Large Array
Rob Jansen
Jallib Group
Introduction
JAL support to type of arrays:
• Arrays with constant data. Data is stored in program memory of the PIC
• Arrays with variable data. Data is stored in data memory of the PIC
The maximum size of the constant data arrays depends on the size of the program memory of the PIC and can at most
be 64 kbytes. For an array with variable data there are limitation caused by how a PIC is organized. Data memory in
the PIC is stored in banks which are limited in size:
• For PIC12F and PIC16F, banks are 80 bytes
• For PIC18F banks are 256 bytes
The total data memory of a PIC is a total of all banks that are present in the PIC.
device file the pragmas and other libraries. Instead we focus only on the definition and use of the large array. Here we
use large array 4.
-- Setup the large array
const LARGE_ARRAY_4_SIZE = 400 -- choose number of array variables
const LARGE_ARRAY_4_VARIABLE_SIZE = 4 -- choose size of variables (byte*4)
include large_array_4 -- include the array library
alias test is large_array_4 -- rename/alias the array to test
There output printed to the serial port should look something like this:
There are many large array sample files in the Jallib sample directory.
136 | Jallib | PIC software
Appendix
138 | Jallib | Appendix
In this tutorial, we're going to build a serial port that can connect your PIC's TX and RX pins to your pc or other
hardware using a max232 chip.
Many circuits will require some serial port communication, you may buy yourself a rs232 to TTL adapter off the net
for as little as $10, or you can build one yourself. The max232 is a very popular chip. It converts your 5v circuit to the
12v required for serial communication to things like your PC. Many microcontrollers have RX and TX output pins.
Here is a image of the max232 adapter I purchased. It has input pins for RX, TX, CT, RT as well as GND and 5v. The
RX and TX pins can be directly connected to your PIC.
I am going to use a cut serial port cord since it already has leads on it, and is long enough to reach my pc. Use your
multi-meter to find the pin numbers, and touch up the wires with solder so they’ll go into your breadboard easily.
Now build the circuit, As you can see, you will need the max232 chip from your local electronics store and a few 1uf
capacitors.
140 | Jallib | Appendix
Great job, now connect the RX and TX pins to your circuit, and plug the rs232 port directly your pc, or to a usb-to-
serial adapter, or even to a bluetooth-to-serial adapter for short range wireless.
I strongly suggest you make this on a PCB with pins that will plug to your breadboard. you’ll use it a lot!
In this image, I did not complete my PIC circuit, but I think you get the idea:
Jallib | Appendix | 141
You can use serial_hardware lib or serial_software lib to transmit data to your pc, check for it in the other jallib
projects. I suggest the software realterm for sending/receiving data to your PIC
Open Source REALTERM http://realterm.sourceforge.net/
It can be downloaded for free from http://sourceforge.net/projects/realterm/files/
Open the software, click “Port”, choose your speed and port number and press “open”
Hex output
142 | Jallib | Appendix
Ascii output
Jallib | Appendix | 143
In Circuit Programming
Matthew Schinkel
Jallib Group
What is ICSP?
ICSP stands for In-Circuit Serial Programming. More information can be found at http://ww1.microchip.com/
downloads/en/DeviceDoc/30277d.pdf
Benefits of ICSP
1. You may program your PIC while it is in your breadboard circuit
2. You may program your PIC while it is on a soldered circuit board
3. You will save time programming so you can write more code faster
4. You can reset your circuit from your PC
5. You can program surface mount PIC's that are on soldered circuit board
6. You won't bend or break any pins
7. You won't damage your PIC by placing it in your breadboard wrong
8. With a remote desktop software like VNC, you can program your PIC from anywhere around the world.
9. I can program my PIC in my living room on my laptop while I watch tv with my wife! (I keep my mess in my
office)
Your done! Turn on your power supply and try to program your chip!
146 | Jallib | Appendix
Introduction
As explained in the Getting Started section, any text editor can be used to develop JAL programs. To make
life easier JAL Edit can be used, which supports syntax highlighting and much more. This editor, however, only
works for Windows.
A good editor helps writing good programs and syntax highlighting makes life easier. In order to support more than
only the Windows platform, Microsoft Visual Studio Code can be used, which runs on Windows, Linux and MacOS.
Visual Studio Code can be downloaded for free. A JAL Visual Studio Code extension is available to support
programming in JAL.
This section describes how to install the Visual Studio Code JAL extension and how to use Visual Studio Code for
your JAL development.
Type ‘jal’ in the search bar and you will find the JAL extension.
You can download this piece of code from GitHub or copy-paste the code below in the tasks.json.
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
// prefilled tasks.json for compiling a JAL file
"version": "2.0.0",
"tasks": [
{
"label": "Compile JAL File",
"type": "process",
Jallib | Appendix | 149
"command": "${config:jal.paths.exePath}",
"args": [
"${file}",
"-s",
"${config:jal.paths.LibPath}"
],
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
Set the paths to the JAL documentation, the JAL compiler, the JAL libraries and programmer (if present), an example
is given below:
150 | Jallib | Appendix
The compiler output appears at the bottom of the screen in a terminal window and may look like this:
If a compiler error occurs you can jump to that error in the editor by pressing ctrl-click.
• Syntax Highlighting
• Fast opening and saving of files irrespective of the size
• Linux and Windows support Code folding
• Auto completion (More work needs to be done to have functions/procedures included from include files)
• Code Snippets (Only very few are added, but not very difficult to add)
• Compiling to Hex file
• Ctrl-Click to go to error line (It doesn't go automatically)
• Searching/Replacing any word within files and across folder
• Direct Github Push/Pull/Diff other commands
• Side by side View and file comparison
• Theme selection/switching
• Folder/explorer view
Some of the main features not in the extension:
• Code Explorer for include files,procedures,functions,variables,constants,aliases
• Opening include files with Ctrl-Enter
• Auto Backup with time stamp/compilation
• Backup project as zip file
• Go to error line after compilation
• Running programmer on successful build
• Serial Terminal
• Compile/Program buttons/keys
• Detecting PIC name from code and passing it as variable to Programmer executable
• Set file as Active JAL file and compile that irrespective of file you are editing
Jallib | Appendix | 153
Making a Tutorial
Rob Jansen
Jallib Group
Introduction
This tutorial gives a brief instruction on how to create a new tutorial for the Tutorial Book. It will not explain the
elements used within a tutorial since that is already explained in detail in the file template.xml that can be used as
a starting point.
Before starting with a new tutorial you can have a look at the existing tutorials to see how they are built up. When you
start, you can make a copy of the previously mentioned template file or make a copy of a tutorial that has more or less
the format and layout that you want to use. Rename the xml that you copied file to the subject of your tutorial. The
format of such a tutorial xml file is tutorial_my_subject.xml where the filename is only using small caps. It
is recommended to use a logical name for the subject that matches the subject of your tutorial.
Required tooling
It is not very easy to write xml documents so we will be using a tool for writing our tutorial. A nice XML editing
tool that is available for Windows, MacOS and Linux is XMLmind which can be downloaded and used for free for
personal use or for open source development. Before writing your tutorial open the template.xml file to see
which features can be used like creating sections, paragraphs, unsorted lists, etc.
Note: The version number and the release date are also mentioned in the bookmeta on the first page of
the Tutorial Book in the file tutorials.ditamap. Before releasing, this data should be updated too.
154 | Jallib | Appendix
Headers in a library
Every jal file published on this repository must have the following headers (comments), as the very beginning of the
file:
-- Title: [very small description if needed]
-- Author: [author's name], Copyright (c) YEAR..YEAR, all rights reserved.
-- Adapted-by: [adapter author's name, comma separated]
-- Compiler: [which version of compiler is needed. Ex: >=2.4g, 2.5]
--
-- This file is part of jallib (https://github.com/jallib/jallib)
-- Released under the ZLIB license (http://www.opensource.org/licenses/zlib-license.html)
--
-- Description: [describe what is the functional purpose of this lib]
--
-- Sources: [if relevant, specify which sources you used: website, specifications, etc...]
--
-- Notes: [put here information not related to functional description]
--
The author is the original author's name. The library may have been modified and adapted by adapters. The
compiler helps readers to know which compiler version is needed to use this file (no space between operator and
version: >=2.5r6). Description, sources and notes fields must be followed by an empty line (just `--`) to declare the
end of the field content. As a consequence, those fields cannot have empty lines within them.
JSG Header example:
-- -----------------------------------------------------------------------------
-- Title: Library for the DS3231 Real Time Clock IC.
-- Author: Rob Jansen, Copyright (c) 2021..2022, all rights reserved.
-- Adapted-by:
-- Compiler: 2.5r6
--
-- This file is part of jallib (https://github.com/jallib/jallib)
-- Released under the ZLIB license (http://www.opensource.org/licenses/zlib-license.html)
--
-- Description: Library for controlling the SD3231 Real Time Clock IC.
-- The chip uses an IIC interface. The library provides all
-- functions and procedures to support the rtc_common.jal library and
-- includes extra functions and procedures specific for the DS3231.
-- For all common rtc procedures and functions see rtc_common.jal.
--
-- Sources: Maxim datasheet rtc. 19-5170; Rev 10; 3/15
--
-- Notes: This library supports the control of the DS3231 via IIC.
-- The default is hardware IIC control but this can be overruled using
-- software IIC control by defining the following constant:
-- -) const RTC_SOFTWARE_IIC = TRUE
--
156 | Jallib | Appendix
Note: if you need to create a new paragraph within a multiline field, use the "--" special chars. See example in Notes
field: "The following pins ..." is part of the Notes field, but visually separated from the beginning of the field content.
In the /tools directory on GitHub you'll find jallib.py and jallib3.py for Python version 3 and higher.
Among many things, you can run the "validate" action, and check lots of JSG requirements. You can (must) use it to
make sure that all your jal files are JSG compliant. This script will help you to identify problems:
Example:
bash$ python jallib.py validate my_file.jal
File: my_file.jal
4 errors found
ERROR: Cannot find field Title (searched for '^-- Title:\s**(.**)')
ERROR: Cannot find field Author (searched for '^-- Author:\s**(.**)')
ERROR: Cannot find field Compiler (searched for '^-- Compiler:\s**(.**)')
ERROR: Cannot find field Description (searched for '^-- Description:\s**(.**)')
0 warnings found
i2c_<whatever>.jal. On the contrary, it can be useful to have two serial implementation within a same
PIC (eg. one talking a PIC, another talking to a external device). Thus, serial libs' const/var/... are prefixed by
serial_hw_<whatever>.jal or serial_sw_<whatever>.jal.
Exception: If your library uses a special PIC feature, it may use the name defined in the device files / datasheet. Not
so much an exception, as you'll use the pin name given the context (feature, peripheral).
158 | Jallib | Appendix
Note: Syntax "var ... is ..." is now deprecated in favor of "alias ... is ..." and must
not be used anymore. The "alias" keyword is more powerful as it allows to create synonyms for any
type of names (variables, constants, procedures, functions, pseudo-variables).
Example: An i2c hardware library (using built-in PIC i2c) may refer to `SCK` and `SDA`. Those pin names are set
into the device include file (prefixed with the portname!).
Write examples
Write examples to show the world how to use your great library. Without it, people may (will) not use your library,
because it's too complicated and too time-consuming reading code to actually discover what it does. Also remember
writing examples can help you to design a usable, simple and clear API.
Assembler
Avoid the use of inline Assembler. If you cannot do without it use standard asm opcodes and avoid nasty Assembler
statements. So:
Good
btfsc STATUS_Z
Bad
skpnz
Code layout
Indent your code. It helps following the code structure (flows). Code must be indented using 3 spaces (no tab). You
can use python jallib3.py reindent <file.jal> for this.
Good
var byte char
forever loop
if serial_hw_read(char) then
echo(char)
end if
end loop
Jallib | Appendix | 159
Bad
var byte char
forever loop
if serial_hw_read(char) then
echo(char)
end if
end loop
Bad
var byte ThisIsAVariable
var byte Another_One
Bad
const reset_CHAR = "*"
const sspCON1_Ckp = 1
-- Calling
do_it_please()
-- pseudo-var
function my_pseudo_var'get() return byte is
-- I promise I'll do it
end function
Bad
procedure do_it_again is
-- this is bad
end procedure
do_it_again
Bad
$ ls 16F88.jal
Bad
include 16F88
External data
When developing a library, you may need to collect and organize external / 3rd party data. For instance, the relation
between a datasheet reference and the PICs described in this datasheet is what we call external data: it's not jal code,
but often used to generate some, and always a source of information everyone can refer too.
External data must store in a structured format so everyone potentially is able to use it. Before we, developers,
are also (kind of) humans, we want this format to be readable, and even writable, but also structured enough so a
computer can also use and exploit it. That's why this format is JSON (and not XML), which is available in many
languages. This is a way to share information, among the many scripts used to deal jal code base.
Jallib | Appendix | 161
Miscellaneous
162 | Jallib | Appendix
Changelog
Jallib Group
Jallib Group
Date Comments
2022/03/19 Added making a tutorial
2022/03/13 Added Visual Studio Code tutorial
2022/03/12 Added PICKit2 and PICKit3 software to the
getting started tutorial
Date Comments
2022/03/05 Added MPLABX IPE to the getting started tutorial
2022/03/05 Added style guide tutorial
2022/02/26 Added USB tutorial and Large Array tutorial
2022/02/20 Updated tutorials of ADC, blink-a-led
2022/02/19 Restored/Updated broken links
2022/02/12 Added DFPlayer tutorial
Date Comments
2011/05/23 Added print & format library
2011/05/19 Added FAT32 tutorial
2010/04/22 Fixed English and integrate Youtube flash object
in HTML output
2010/04/06 Alphabetical TOC
2010/04/05 Added RC servo & motor speed control tutorial
2010/04/01 Changed hard disk tutorial schematic
2010/03/25 Updated ICSP schematic and tutorial to reflect PIC
Kit 2 pinouts. ICSP schematic matches Microchip
Specification
2010/03/12 Updated SD Card schematic. Added pull-up
resistor on chip-select line, changed resistor values
for 5v-3v conversion
Date Comments
2010/01/27 Fixed I²C bus schematic and modified I²C titles
Jallib | Appendix | 163
Date Comments
2010/01/21 Added ADC introduction, re-organized PWM tutorials and
titles
2010/01/20 Better quality Images on Getting Started, serial board, blink
a led tutorials.
2010/01/19 Added serial & rs-232 tutorial
2010/01/15 New ICSP Schematic
Date Comments
2009/12/06 Added SD Card tutorial
2009/12/06 Added PATA Hard Disk tutorial
2009/12/06 Added ICSP tutorial
Date Comments
2009/11/22 Initial Release
164 | Jallib | Appendix
License
We, the Jallib Group, want this book to be as open and free as possible, so we have decided to release it under the
Creative Commons Attribution-Noncommercial-ShareAlike 3.0 license.
Basically (and repeating what's on the Creative Commons website), you are free to:
• Share - copy, distribute, and transmit the work
• Remix - adapt the work
Under the following conditions:
• Attribution - You must attribute the work in the manner specified by the author or licensor (but not in any way
that suggests that they endorse you or your use of the work).
• Noncommercial - You may not use this work for commercial purposes.
• ShareAlike - If you alter, transform, or build upon this work, you may distribute the resulting work only under the
same, similar or a compatible license.
The full, legal text of the license can be found at: http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode
This license applies to the book content itself, not to the code, libraries, examples, etc. found in the Jallib collection,
or where it is explicitly stated that a particular work is released under another license. For instance, most of the works
in the Jallib collection are released under either the BSD or ZLIB licenses, not under this Creative Commons license.
If you are in doubt about the license status of a particular file, please ask on the Jallib Google Group.