Monday, September 7, 2009

Jaluino v1.1: enhanced Arduino-like board

Jaluino, with user guide, schematics, PCB, shields, etc... can now be reached on the following sites:

Main site:

Last time, I built Jaluino v1.0, the very first version of Jaluino. Jaluino is an Arduino-like board (some even say a clone), based on a Microchip PIC 18F4550, and powered by jalv2 and jallib. This first version was very encouraging, but several points had to be improved. Quite a lot of has been discussed, now has come the next version: Jaluino v1.1

What's been improved ?

Several important points were discussed and improved:

  • i²c support. Jaluino v1.0 lacked i²c support, this new Jaluino v1.1 version now provides a new connector, and two jumpers to select whether the board should act as a master or a slave (more on this on a later tutorial I guess). This is an important point, as i²c is widely used. Jaluino now provides mostly important communication connectors: serial, USB, ICSP and i²c.
  • 3.3V power supply. Lots of components uses this voltage. Jaluino v1.1 provides 3.3V through the power supply connector. There are several options to choose the regulator: LM3940, LD1117V33, LM1117T, LM1086, LF33V, ... Not all have the same pinning. For now, we provide two options:
    • Input/Ground/Ouput pinning: use LM3940, LF33V. See Jaluino v1.1a.
    • Ground/Output/Input pinning: use LD1117V33, LM1117T, LM1086. See Jaluino v1.1b.
  • More space between connector shields. Last version revealed space between shield connectors weren't big enough, you couldn't put a mini-breadboard between them. This time, connectors have more space, slightly more than original Arduino's.
(also, because Richard, who designed the board, doesn't like vias, he removed one :))

Schematics and PCBs

  • Jaluino v1.1a: Input/Ground/Ouput pinning, using LM3940 or LF33V. See schematic and PCB.
  • Jaluino v1.1b: Ground/Output/Input pinning, using LD1117V33, LM1117T or LM1086. See schematic and PCB.
Note: by the time of writing, files are being renamed, in any case, go to Jaluino directory here, and select the appropriate files. Eventually, there will be one version remaining, to keep the whole thing simple...)


Here are couples of photos showing the results. The version built is Jaluino v1.1b, expecting to use LM1086 3.3V regulator. But that doesn't make a difference, since I'm still waiting to receive the part :). So note there's no 3.3V regulator on the board, yet it's working with 5V...

(this is not the best board I built, I had quite some problems mostly due to my etchant being too saturated, so expect the more beautiful board next time !)

Most components used to build Jaluino v1.1, except LM1086 and few caps

Jaluino v1.1 is born !

(ugly) Copper side

Connectors, from left to right: USB, serial, i²c and ICSP

Jaluino v1.1 and Wisp648, programming step

Wisp648 can directly be connected to Jaluino ISCP connector, making easy to program chip on-board

Another one :)

Jaluino v1.1, blinking a LED (while waiting for a development shield...)

Power connector supplies the breadboard with +5V

LED is connected to RA0, a wire is used to connect this pin to the breadboard

Breadboard view...

So... I need to "practice" this new Jaluino v1.1 board. Next steps are:
  • documentation, explaining, for instance, how to use jumpers, etc...
  • tutorials, showing how to use the board, with jalv2 & jallib (please provide some suggestions about covered topics)
  • shields building, an intermediate shield acting as a converter between Jaluino's and Arduino's original shields, and a development shield, to experiment with LCD, ADC, PWM, sounds, buttons, ... Any more suggestions ?

Sébastien Lelong & Richard Zengerink

Tuesday, August 25, 2009

Building Jaluino v1.0

Jaluino, with user guide, schematics, PCB, shields, etc... can now be reached on the following sites:

Main site:

Big time.

Thanks to Richard's last contribution, we now have a nice schematics for the first version of Jaluino board, and very clean and easy to build PCB.

Jaluino is aimed to be a clone of Arduino, but PIC-based, and powered by jalv2 & jallib. The purpose is to share a common hardware configuration, on top of which one can add different features and capabilities, thanks to shields (daughter boards). Ala Arduino...

This post is to give an overview of how to build it, but with not so much details. If you want to build it, you'll have to be familiar with PCB creation.

That said, having this board within your hands is really nice ! It really helps thinking about what could be done with it, what could be improved, and is a nice base to start thinking about building shields.

So, here we go ! First of all, you can find all schematics, PCB and many more details in jallib SVN repository, under "/project/jaluino" directory.

Here's the schematic, but have a look at the PDF file for a more detailed one:

The PCB is surprisingly very simple (thanks Richard !), and thus very to easy to build:

Don't print and use this image ! Use the PDF file here, and print it at scale 1:1, that is, without any zoom-out or zoom-in correction. If any doubt, once printed, put the microcontroller support on the paper (or the like) and check all pins perfectly fit all holes.

PCB creation

As said, PCB creation is easy. I use the toner transfert method, using glossy photo laser paper (dedicated to laser printer, not ink-jet). If interested, have a look at this post, explaining how to do this, step by step, with a video.

Once the transfert is done, the PCB is ready to be etched.

PCB is etched, now drill the holes

PCB is ready for soldering

A brief comparison between original Arduino and Jaluino. Jaluino is obsviously bigger, but embed a much bigger chip, and most importantly is made homebrew!

Soldering components

I try to start soldering components from the smaller & lower ones, to the biggest and taller ones. We'll follow this component diagram, provided in PCB PDF file (page 2).

First solder resistors and diodes

Then solder small capacitors (unpolarized)

Place microcontroller support, quartz, pushbutton and bridge rectifier (I used a DF02M instead of DF04M)

Add wires (green), power jack, big capacitors (polarized)

Solder shield connectors, serial and ICP connects. Add 7805 voltage regulator. Don't forget jumper for power selection and RTS reset feature.

Place USB connector and fuse support

Place your favorite 18F4550 onto the support, and don't forget the fuse ! You're done, kudos !

The reverse side...

Now here's a brief map showing the different features coming with this board.

Note: one important missing feature is I²C support, which surely will come in the next version.

I already tried quite few things with this board: In Circuit Programming using XWisp648, blinking a LED (of course), UART using serial connector, with tinybootloader and testing Reset-via-RTS feature (great), and USB-to-serial ! In the next post, I'll try to describe these experiments one by one.

Another important thing, if not the crucial one, is how big should a shield board must be. Current shield connectors configuration gives a surface closed to Arduino's (only considering the surface between connectors, not the whole board). It it enough ? Should a shield board be bigger ? Now imagine this board is doubled-sided, built through a professional process (and thus available as a commercial product). How much smaller would it be ? Will current connectors configuration be valid ? This is a very important thing, because from this is derived all the shield compatibility. If one builds a shield for this Jaluino v1.0, and shield connectors gets changed, this shield will have to be adapted and rebuilt...

And about shields, now the time has come to design a development shield, providing (more or less) basic features. This shield could be used to learn jalv2 & jallib. I was thinking about having:
  • one LED connected to a standard digital output
  • one LED connected to a PWM channel
  • maybe a buzzer connected to the other PWM channel to make sounds
  • one or two push-buttons (input)
  • pot to have fun with ADC
  • maybe an EEPROM to play with I²C
  • a small LCD screen (8x2)
But maybe that's a little bit too much for single shield...

Please advise !

Sébastien Lelong & Richard Zengerink.

Monday, August 10, 2009

PIC 18f14k50 based USB WISP programmer

Today the description of a USB WISP programmer. A while back I had some trouble with my ICD2 clone, therefore I decided to make a WISP programmer. Since I've written the USB libraries for JAL(lib) and because I just had ordered a tube of 10 PIC18f14k50, I decided to redesign the original WISP so it uses the PIC18f instead of the the PIC16f648 (which I did not have in my junk box), and use the USB-Serial library so I can still use the various host applications but I can plug it in directly to the USB port. The additional benifits are:

  • Very cheap (just a PIC18f14k50 + resistor and capacitors, total costs ~5 Euro)
  • Have a fast serial connection
  • Can use exsisting WISP host applications (like Rob's XWISP2)
  • Can be directly powered from the USB port (no external power supply needed)
  • When adding a 3.3V regulator, board can also be used to program LF devices (if Vpp = 9v)
  • Added an additional connector for future use, like JTAG & I2C and RS-232 TTL

The schematic is very straigtforward, the blue boxed areas contain the optional section of the USB WISP programmer

I've made a few modifications to the original design, first the Target power is controlled by a PNP transistor, which acts as switch (so target power can be turned on/off), because USB 5v does not like to be short circuited for a short period, as is done in the WISP 648. In addition I've added a PNP transistor to control the Target VPP line, this is for future use.

I also made a small PCB, however, Wouter van Ooijen (the designer of the Wisp 648 programmer, see asked me not to publish the PCB layout. So don't ask me for it, if you want to build this project you have to design you own PCB, if you can't, buy a Wisp 648 kit from Wouter. The assembled PCB is depicted below:

The Source code
I just made minor modifications to the original source code (see The changes are:
  • Include usb_serial library
  • Change UART functions, so they send and receive chars from the USB library
  • Tune the timing delays (becuase effective speed is raised from 20->48 MHz)
  • Had to adapt the HEX<->ASCII function, because the original code still uses some inline assembly which did not work properly for the PIC18f
  • Call USB-Flush in the main routing

There still some work left, i.e. the port trough function is not working yet, the advantage of this design is the the UART can be used (even the polarity inversion of the UART signals can be programmed with the PIC18f14k50), so pass trough can work with speeds up to 115200 baud.
The JAL source code is uploaded in the JALLIB google code file download section,

The USB Wisp is operation for a couple of weeks, so far it worked flawlessly. With a small change in the XWISP2 configuration file, I was able to program the PIC14k50 as well. But of course, there is a big discalaimer, I only have a couple of PICs, so the solution is not tested extensivly, thus if you want a good and robust PIC programmer I advice you to buy or build the original WISP 648.

This small exerise shows the strenght(s) of JalV2 and Jallib, it shows how easy it is to port a large application from a PIC16f devices to a PIC18f device and that only a little effort is required to move from a RS-232 (UART) communcation interface to a USB (serial) based communication interface.

Sunday, August 2, 2009

Jaluino Medium 18F2550-based: first draft

Jaluino, with user guide, schematics, PCB, shields, etc... can now be reached on the following sites:

Main site:

Careful, schematic and PCB in this post aren't tested yet. Except if you're a daring risk-taker, you shouldn't build this board as it would only be a waste of time, and probably of money too... You've been warned.

I'm still on this Jaluino board.

While trying to get a working schematic, I've also spend a lot of time drawing the PCB. I focused on a 18F2550 version, instead of big fat 18F4550, so PCB layout is simpler and I can focus more important issues for now. So this is now about Jaluino Medium (18F2550), not Jaluino Maxi (18F4550). BTW any ideas about "marketing" names to replace Mini, Medium and Maxi ?...

Last schematic contained lots of errors, mostly on USB and dual power. Luckily Guru Albert helped and provided me four options. I kept the simpler one (I can understand), which consists in having a jumper to select whether power should come from:
  • external supply (jack)
  • USB self-powered connector
(I would even add a new source of power: from serial, and more specifically from a USB-to-serial converter)

The current schematic seems to look better (yet still untested, this will be for other posts).

So here how the PCB looks like now...

This PCB is expected to be 8.1cm x 7.1cm (3.2in x 2.81in). Compared to an original Arduino (6.9cm x 5.4cm), it's a little bit bigger. But it's also a single side board, and there are lots of other connectors (I²C and serial) not present in Arduino.

There are several connectors. Some will be the shield connectors (JP1, JP2, JP4, JP5 and POWER), female headers as in Arduino, others (ICSP/JP6, I²C, serial) will be male headers.

The shield is expected to be something like 4.8cm x 5.8cm (1.9in x 2.3in). Original Arduino's shield is 4.9cm x 4.3cm. It's a little bit bigger, and I may adjust connectors (move JP1 & JP2 lower) to have a "more squared shape".

Next posts will be about testing and prototyping this board, using a breadboard. This will also be a good exercise to have basic (and maybe advanced) experiments using jalv2 and jallib.

Sébastien Lelong

Thursday, July 30, 2009

PIC 18f14k50 USB Interface Board: Part 3

As promised, a blog about USB-HID devices. This blog will demonstrate how to create a USB-HID keyboard device running on the PIC 18f14k50 USB Interface Board. Making a HID device is a bit more complicated that getting the USB serial communication, becuase there are a wide range of HID devices, it is very hard to make a generic library. However, HID devices are nice, because you don't need a special drivers on the Host PC. There are many HID devices that can directly interact with the host operating systems, like keyboards, mice, joysticks etc, it is even possible to make a generic HID device, which can be controlled from a host application (but I will save that for another blog). Today were making a keyboard device, once you press the boot button it will generate a character. It is an educational example and does not have any practical use, but you can use it as a starting point to make for example a IR remote receiver that generate keystrokes.

The Code
I've splitted up the code description in a couple of section, and it will explain it step by step. We start of with the regular stuff, not very existing and I won't explain it in more detail

-- chip setup
include 18f14k50
pragma target clock 48_000_000

include delay

Before creating the USB descriptors, we need to include the USB constant definitions by

include usb_defs

Ok, that was the easy stuff. USB works with enpoints, and we have to indicate which endpoints will be enabled, where there are located and specify their size, and endpoint can be considered more or less a communcation channel between the Host PC and the PIC device. An endpoint can consist of an input endpoint (seen from the Host computer, so output for the PIC device) and an output endpoints (again, seen from the Host computer, so input for the PIC device). An USB device should always have input & output enpoint zero, which is used for e.g. exchanging device configuration settings. In this example we will have and additional enpoint, which is used for the exchange of HID reports (i.e. the keyboard information). Furthermore, the an enpoint consist of two parts, the Endpoint Descriptor and the Enpoint Buffers, the setup of the Endpoint Descriptors are taken care of by the USB library, however, the Enpoint buffers have to be setup by the user of the library. The following code shows how to enable the endpoints and Endpoints Buffers:

const bit USB_EP0 = 1
const byte USB_EP0_OUT_SIZE = 8
const word USB_EP0_OUT_ADDR = ( USB_BASE_ADDRESS + 0x0010 )
const byte USB_EP0_IN_SIZE = 8

const bit USB_EP1 = 1
const byte USB_EP1_OUT_SIZE = 8
const byte USB_EP1_IN_SIZE = 8

const bit USB_EP2 = 0
const bit USB_EP3 = 0

var volatile byte usb_ep1in_buf[ 8 ] at USB_EP1_IN_ADDR

const bit USB_EPx = 1 indicates that the endpoint is enabled, if the endpoint is enabled the address of the Endpoint buffer must be specified, in addition, it should map within a special memory region. The USB hardware "talks" with the microcontroller via a dual access memory, this memory location is dependent on the PIC type, however its base addres USB_BASE_ADDRESS constant is defined usb_defs, so we can use this constant to setup the memory regions for the usb buffers independent of the PIC type. You might wonder why the enpoint buffers are not mapped at the beginning of the memory regions (USB_BASE_ADDRESS), this is because the USB library needs to setup the Endpoint descriptors, they shall be located starting at the beginning of the dual access memory. To calculate the start of the memory region that can be used for the Endpoint buffers, take the highest enpoint number, add one, and multiply it by 8. So in this example we have endpoint 0 and 1, so 2 x 8 = 16 (0x10 hex).

Well, that just beginning, next "record" we have to specify is the USB_DEVICE_DESCRIPTOR, it consists of 18 bytes and describes the device properties. Take a look at the usb specifiction (see for the details.

0x02, -- usb version 2.00
0x00, -- class
0x00, -- subclass
0x00, -- protocol
USB_EP0_OUT_SIZE, -- max packet size for end point 0
0x04, -- Microchip's vendor
0x00, -- Microchip keyboard demo
0x00, -- version 1.0 of the product
0x01, -- string 1 for manufacturer
0x02, -- string 2 for product
0x00, -- string 3 for serial number
0x01 -- number of configurations

const byte USB_STRING0[] =
0x04, -- bLength
USB_DT_STRING, -- bDescriptorType
0x09, -- wLANGID[0] (low byte)
0x04 -- wLANGID[0] (high byte)

const byte USB_STRING1[0x36] =
0x36, -- bLength
USB_DT_STRING, -- bDescriptorType
"M", 0x00,
"i", 0x00,
"c", 0x00,
"r", 0x00,
"o", 0x00,
"c", 0x00,
"h", 0x00,
"i", 0x00,
"p", 0x00,
" ", 0x00,
"T", 0x00,
"e", 0x00,
"c", 0x00,
"h", 0x00,
"n", 0x00,
"o", 0x00,
"l", 0x00,
"o", 0x00,
"g", 0x00,
"y", 0x00,
",", 0x00,
" ", 0x00,
"I", 0x00,
"n", 0x00,
"c", 0x00,
".", 0x00

const byte USB_STRING2[42] =
42, -- bLength
USB_DT_STRING, -- bDescriptorType
"J", 0x00,
"A", 0x00,
"L", 0x00,
" ", 0x00,
"H", 0x00,
"I", 0x00,
"D", 0x00,
" ", 0x00,
"K", 0x00,
"e", 0x00,
"b", 0x00,
"o", 0x00,
"a", 0x00,
"r", 0x00,
" ", 0x00,
" ", 0x00,
"D", 0x00,
"e", 0x00,
"m", 0x00,
"o", 0x00

I'll not go into all the details of the USB descriptors, however, we need to specify USB_STRING0..3 because we filled in the USB string identifiers in the USB_DEVICE_DESCRIPTOR record. These string have to conform a predfined format, i.e. the first byte should specify the total record length, and the second byte indicates that it is a string USB_DT_STRING, furthermore, it has to be a unicode string, therefore after each character a 0x00 value needs to be defined. USB_String0 is a special string, since it specifies the language code, which is set to US English. Furthermore we specified there is one configuration record (last byte in the USB_DEVICE_DESCRIPTOR record.

The USB_CONFIGURATION_DESCRIPTOR record specifies the properties of the USB device, again the details are available the USB specification at High level description is that were setting up one configuration record for a HID device, which specifies the HID interface by pointing to the HID descriptor and it will have one endpoint (is number of enpoint exluding enpoint 0 which should always be present).

const byte USB_HID_REPORT1[]=
0x05, 0x01, -- USAGE_PAGE (Generic Desktop)
0x09, 0x06, -- USAGE (Keyboard)
0xa1, 0x01, -- COLLECTION (Application)
0x05, 0x07, -- USAGE_PAGE (Keyboard)
0x19, 0xe0, -- USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, -- USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, -- LOGICAL_MINIMUM (0)
0x25, 0x01, -- LOGICAL_MAXIMUM (1)
0x75, 0x01, -- REPORT_SIZE (1)
0x95, 0x08, -- REPORT_COUNT (8)
0x81, 0x02, -- INPUT (Data,Var,Abs)
0x95, 0x01, -- REPORT_COUNT (1)
0x75, 0x08, -- REPORT_SIZE (8)
0x81, 0x03, -- INPUT (Cnst,Var,Abs)
0x95, 0x05, -- REPORT_COUNT (5)
0x75, 0x01, -- REPORT_SIZE (1)
0x05, 0x08, -- USAGE_PAGE (LEDs)
0x19, 0x01, -- USAGE_MINIMUM (Num Lock)
0x29, 0x05, -- USAGE_MAXIMUM (Kana)
0x91, 0x02, -- OUTPUT (Data,Var,Abs)
0x95, 0x01, -- REPORT_COUNT (1)
0x75, 0x03, -- REPORT_SIZE (3)
0x91, 0x03, -- OUTPUT (Cnst,Var,Abs)
0x95, 0x06, -- REPORT_COUNT (6)
0x75, 0x08, -- REPORT_SIZE (8)
0x15, 0x00, -- LOGICAL_MINIMUM (0)
0x25, 0x65, -- LOGICAL_MAXIMUM (101)
0x05, 0x07, -- USAGE_PAGE (Keyboard)
0x19, 0x00, -- USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, -- USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, -- INPUT (Data,Ary,Abs)
const USB_CONFIGURATION_DESCRIPTOR_SIZE = 0x09 + 0x09 + 0x09 + 0x07

-- configuration descriptor - - - - - - - - - -
0x09, -- length,
USB_DT_CONFIGURATION, -- descriptor_type

0x00, -- total_length;

0x01, -- num_interfaces,
0x01, -- configuration_value,
0x00, -- configuration_string_id,
0b10000000, -- attributes (bus powered, no remote wake up)
100, -- max_power; (200ma)

-- interface descriptor - - - - - - - - - - - -
0x09, -- length,
USB_DT_INTERFACE, -- descriptor_type,
0x00, -- interface_number, (starts at zero)
0x00, -- alternate_setting, (no alternatives)
0x01, -- num_endpoints,
USB_HID_INTF, -- interface_class, (HID)
USB_BOOT_INTF_SUBCLASS, -- interface_subclass, (boot)
USB_HID_PROTOCOL_KEYBOARD, -- interface_protocol, (keyboard)
0x00, -- interface_string_id;

-- hid descriptor - - - - - - - - - - - - - - -
0x09, -- length,
USB_DT_HID, -- descriptor_type;
0x01, -- hid_spec in BCD (1.11)
0x00, -- country_code, (0=not country specific)
0x01, -- num_class_descriptors, (1)
USB_DT_HID_REPORT, -- class_descriptor_type; (0x22 = report)
(count( USB_HID_REPORT1 ) & 0xFF ),
(count( USB_HID_REPORT1 ) >> 8 ),

0x07, -- length,
USB_DT_ENDPOINT, -- descriptor_type,
0b10000001, -- endpoint_address, (Endpoint 1, IN)
USB_EPT_INT, -- attributes; (Interrupt)
0x00, -- max_packet_size
0x01 -- interval (1ms)

The HID Report specifies which information can be exchanged between the Host PC and the
USB device. There are seperate specification available which describes the details of a HID report (again, see
Making a HID report can be quite cumbersome, and there are even tools available to make HID report. Anyhow, for now assume that the specified HID report can exchange keyboard related information between the Host PC and the USB device

OK that was the toughest part, now some real JAL code.

-- include remaining USB libraries
include usb_drv_core
include usb_drv

-- HID report layout (see USB specification for more details)
-- 0 Modifier byte
-- bit
-- 1 reserved
-- 2 keycode array (0)
-- 3 keycode array (1)
-- 4 keycode array (2)
-- 5 keycode array (3)
-- 6 keycode array (4)
-- 7 keycode array (5)
var byte hid_report_in[8] = { 0,0,0,0,0,0,0,0 }

var byte key_value = 4
var bit sw3 is pin_c2
var bit latched_sw3 = sw3

-- disable analog unit, all ports set to digital

-- setup the USB device

-- enable USB device

-- set input where switch is attached to input
pin_c2_direction = input

-- main loop
forever loop
-- poll the usb ISR function on a regular base, in order to
-- serve the USB requests

-- check if USB device has been configured by the HOST
if usb_is_configured() then

-- prepare the HID buffer
if ( sw3 != latched_sw3 ) then

latched_sw3 = sw3

if ( sw3 == low )then
hid_report_in[2] = key_value
key_value = key_value + 1
if ( key_value == 40 ) then
key_value = 4
end if
hid_report_in[2] = 0
end if

-- Send the 8 byte packet over USB to the host.
usb_send_data(USB_HID_ENDPOINT, hid_report_in, count( hid_report_in ) , low )

-- debounce
end if
end if
end loop

First the remaing USB libraries have to be included, since the library need to have access
to the device and configuration records it has to be included after the definition of these recods. Next an array of 8 bytes is defined for the HID report were sending out from the device towards the HOST. The first byte is a modifier key, while the remaing bytes will contain the key character(s). More details can be found in the USB HID keyboard specification (see also Keep in mind though that the characters you send are not ASCII character, for example the "a" character has a byte value of 4.
Next the switch is initialized, and all inputs are set to digital io. Then the USB will be initialized by calling the usb_setup() and usb_enable_module() procedures. Then the main loop, first it has to call the usb_handle_isr() procedure on a regular base, in order to service the USB hardware. Next it will check if the USB interface is already configure by the host, via the usb_is_configured() function. If the USB device is recognized by the Host OS, it will check for state changes of the program switch of the PIC 18f14k50 USB Interface Board. If the value has changed and the button is pressed, it will send a HID report (i.e. it will send a character to the Host PC). The value of the character starts at 4 (the "a" character) and will increase till the "z" character, when reached it will start over again with the "a" character. It will fill in the character in the HID report and then it sends the HID report via USB towards the Host PC by calling the usb_send_data() procedure. Which will send the data via endpoint 1.

Executing the demo
Compile the code (available at the Jallib SVN repository projects\pic14k50_usb_io\examples\blog_part3.jal) using the -loader18 flag. Reboot the PIC 18f14k50 USB Interface Board, while holding down the program and reset switch together and release the reset switch while keep holding down the program switch. After a couple of seconds you can release the program switch. Start the PDFSUSB.exe application to download the hex file. Once downloaded, press the reset button once again. After a couple of seconds the Host PC should recgonize the a new "Keyboard". Wait a couple of seconds, start an editor, for example notepad on the Host PC, if you now press & release the program button on the board, it should type a character within the editor, next time you press & release the program button it will show you the next character of the alphabet.

OK, a long story this time, I know not everything has been explained in detail yet about the Jallib USB libraries, but maybe in a future blog I can tell more about the inner working of the Jallib USB libraries. The next episode will likely building a Generic HID device.

Wednesday, July 29, 2009

PIC 18f14k50 USB Interface Board: Part 4

This is a small follow up regarding the Jallib USB Serial library. Today's blog I'm showing how to make a more serious application with the PIC 18f14k50 USB Interface Board, namely a USB-RS-232 converter. I will go trough the source and explain the JAL code step by step.

Source code
The beginning is the same as Part 2, namely defining the target clockand including the device file.

1:  -- chip setup
2: include 18f14k50
4: -- even though the external crystal is 20 MHz, the configuration is such that
5: -- the CPU clock is derived from the 96 Mhz PLL clock (div2), therefore set
6: -- target frequency to 48 MHz
7: pragma target clock 48_000_000

Serial interrupt handling
Then we need to declare a forward procedure in order to receive the line setting change events, which will be discussed a bit later on. In addition the usb_serial library has to be included as well as the print library so for now we have to add the following code (line 1-7)

1:  -- forward procedure declaration
2: procedure usb_cdc_line_coding_changed_callback()
4: -- include standard libraries
5: include delay
6: include usb_serial
7: include print
9: procedure _serial_receive_interrupt_handler() is
10: pragma interrupt
13: if (PIR1_RCIF == TRUE) then -- UART receive interrupt
15: if ((RCSTA_OERR == TRUE) | (RCSTA_FERR == TRUE)) then -- frame/overr error
16: var byte x = RCREG -- flush hardware buffer
17: while RCSTA_OERR == TRUE loop -- overrun state
18: RCSTA_CREN = FALSE -- disable UART
19: RCSTA_CREN = TRUE -- re-enable UART
20: x = RCREG -- \ flush hardware buffers
21: x = RCREG -- /
22: end loop -- until no more overrun
24: else -- data without errors
25: var byte ch = RCREG
26: -- usb_serial_data = RCREG
27: usb_cdc_putc( ch )
28: end if
29: end if
30: end procedure
From line 9-30, the interrupt routine to handle the receiving of the UART characters. As discussed in the previous blog, the USB library is not interrupt driven, therefore the USB service procedure must be called on a regular base to service the USB hardware. Servicing can be time consuming therefore I've decided to make the RS-232 serial interface (UART) interrupt driven, so were sure that were not lossing incoming data on the UART. The incoming data will be placed directly in the USB transmit ring buffer by calling the usb_cdc_putc( ch ) procedure. The USB-Serial serving procedure checks if there is data present in the ring buffer.

Handling baudrate settings
Next code section is the handling of the baudrate settings. The USB serial library has a callback function usb_cdc_line_coding_changed_callback() , when defined, it will be called each time the USB Host will request the line coding setting (which contains the baudrate, parity, stopbits etc). The procedure entry is on line 45 in the code below, the procedure checks/limits the baudrate settings and will change the baudrate (line 2-23) and by re-initializing the UART hardware (line 27-42).

1:  -- procedure to change the baudrate settings of the UART
2: procedure change_baudrate( dword in baud_rate) is
4: -- compiler issue with -const-detect
5: if true then
6: var dword fosc_div4 = dword( target_clock ) / 4
7: else
8: var dword fosc_div4
9: fosc_div4 = dword( target_clock )
10: fosc_div4 = fosc_div4 / 4
11: end if
13: var dword div_factor = fosc_div4 / baud_rate - 1
14: var word div_wfactor = word( div_factor )
15: var byte div_btfactor[2] at div_wfactor
17: TXSTA_BRGH = true
18: BAUDCON_BRG16 = true
20: SPBRGH = div_btfactor[1]
21: SPBRG = div_btfactor[0]
23: end procedure
26: -- Initializes the serial port, calculates baudrate registers.
27: procedure serial_hw_init() is
28: RCSTA = 0b0000_0000 -- reset
29: RCSTA_SPEN = enabled -- serial port enable
30: RCSTA_CREN = enabled -- continuous receive enable
32: TXSTA = 0b0000_0100 -- reset (16 bit, asyn)
33: TXSTA_TXEN = enabled -- UART transmit enabled
34: -- TXSTA_SYNC = true
35: TXSTA_BRGH = true
36: BAUDCON_BRG16 = true
38: PIE1_RCIE = enabled -- UART receive int. enable
39: -- (PIE1_TXIE dynamically)
40: INTCON_PEIE = enabled -- periferal
41: INTCON_GIE = enabled -- general
42: end procedure
44: -- callback procedure, is called if the USB Host changes the line settings
45: procedure usb_cdc_line_coding_changed_callback() is
47: if ( cdc_line_coding_dte_rate > 115200 ) then
48: cdc_line_coding_dte_rate = 115200
49: end if
50: change_baudrate( cdc_line_coding_dte_rate )
51: serial_hw_init()
52: end procedure

The main loop
Finally we need to initalize the hardware and define the main loop. First all IO ports are set to digital (line 3) and need to initialize the USB serial library (line 6). Next a character is defined which holds the receiving character.

2: -- disable analog
3: enable_digital_io()
5: -- setup the USB serial library
6: usb_serial_init()
8: var byte ch
10: -- main loop
11: forever loop
12: -- poll the usb ISR function on a regular base, in order to
13: -- serve the USB requests
14: usb_serial_flush()
16: -- check if USB device has been configured by the HOST
17: if ( usb_cdc_line_status() != 0x00 ) then
19: -- check for input character
20: while usb_serial_read( ch ) loop
21: -- echo input character
22: TXREG = ch
23: while ! PIR1_TXIF loop end loop
24: end loop
26: end if
27: end loop
Finally the main loop, as said before, the usb_serial_flush() procedure has to be called on a regular base. This function takes care of transmitting the character to the USB Host that have been received by the UART, and it also takes care of putting the character that are sent from USB Host into a receive buffer.

A rough calculation on the maximum interval time between two USB Serial flush:
By default the USB-Serial library will create a ring buffer of 32 bytes, which is for this application more than sufficient (max UART speed is ~10.000 characters/second, so USB Serial flush must be called at least every 10.000 / 32 = 3.2 ms. So there is enough time left to perform additional taks

On line 17 it checks if the USB Host is connected, if so, it will put all character that were sent by the USB Host in the UART Transmit register (line 19-24).

That's about it, this blog showed how to create a simple USB-RS-232 convert, using the JALLB USB serial librray and the PIC 18f14k50 USB Interface Board. Possible extentions are to include RS-232 handshaking and to take other RS-232 line setting into account.

Sunday, July 26, 2009

PIC 18f14k50 USB Interface Board: Part 2

This is the second episode about the PIC 18f14k50 USB Interface Board. This time I want to take about the usage of the JALLIB USB-Serial library and how it can be used in conjuction with the interface board.

USB is a fairly complex interface, besides the basic interface, there are defined a couple of higher level "protocols" which are target for specific "device" functions. Commonly used interfaces are the Human Interface Device(s) types, to support devices like keyboards, joysticks and other devices, another commenly used interace is the Communication Device Class (CDC), which is developped for a broad range of (serial) communication devices, like modems, RS-232 converters etc. HID devices will be discussed in another blog, today we're looking a bit closer on the CDC interface and how to talk to the PIC device with a terminal application via the USB interface.

In order to reduce the USB learning curve, we've devevlopped a special library (USB-Serial) to easily create firmware that behaves like a RS-232 port on the Host side (virtual COM port). The big advantage is that you can still use the good old terminal application(s) to talk with your PIC device via the USB interface (both on Windows and Linux and probably other Host operating systems)

As an example we use the 18f14k50_board_test.jal, we start of simple and show step by step how to use the usb_serial library.

USB Serial example code
We start of with a basic application, the code is listed below:

include 18f14k50                    -- target PICmicro

-- This program assumes a 12 MHz resonator or crystal
-- is connected to pins OSC1 and OSC2.
-- Configuration bits may cause a different frequency!
pragma target clock 48_000_000 -- oscillator frequency

-- include libraries
include usb_serial
include print

-- initialize the USB serial library

-- main loop
forever loop

var byte ch

-- Service USB, call on a regular base to keep communcaiton going

-- check for input character
if usb_serial_read( ch ) then
-- nothing spectecular, echo ch + 1
if ch == "?" then
const byte str1[] = "Hi there \r\n"
print_string( usb_serial_data, str1 )
usb_serial_data = ch
end if
end if
end loop

The code is pretty straight forward, first the device file is included and the target clock speed is set. Then the usb_serial and print JALLIB libraries are included. The next step is to initalize the USB serial library by calling the usb_serial_init() procedure. Within the main loop, the usb_serial_flush() is called, so the USB serial Interface Enginge (SIE) is serviced on a regular base (the USB libraries are not interrupt driven, therefore this procedure must be called regulary.
The call towards usb_serial_read will check if there are character recieved from the USB Host, if a character has been received it will be echoed, unless the "?" character is send, then it will use print the "Hi there" string. Notice that the usb_serial library can be used in conjuction with the print and serial libraries, if the usb_serial_data argument is passed along (as the first argument) with the print related procedure calls.

Get it running
The code is compiled with jalv2 using the -loader18 -no-fuse. After compilation one can reset the PIC 18f14k50 USB Interface Board and holding down the program button. Now the PDFSUSB application can be used to download the HEX file file, after download reset the board. If everything went OK, it should recognize the USB-CDC device and ask for drivers (Windows only), select the driver (which can be downloaded from, file, by selecting the win2k_xp_vista32_64 directory. After installtion of the drivers, the host operating system will create a new (virtual) serial port.
After the (virtual) serial port is created, open the serial port with your favorite terminal appliction. The actual serial port settings does not really matter, once the serial port is opened, you can any send character, the character will be echoed unless the "?" mark character is sent, the it will respond by the "Hi There" sentence.

Wrap Up
So far about the usb_serial library, it shows how easy it is to create an PIC firmware application using which can comminicate with a Host PC via the USB interface. Upcoming blog will address more advanced usage of the USB interface by creating a HID device,.

Thursday, July 23, 2009

Jaluino: an Arduino-like board, power by jal

Jaluino, with user guide, schematics, PCB, shields, etc... can now be reached on the following sites:

Main site:

It's been a while I'd like to build and provide the same kind of board as Arduino's, but PIC-based. And powered by Jalv2 and jallib, of course. The reasons are pretty clear: as we share our jal code (software), why don't we also share our boards & PCB (hardware) ? Jaluino to the rescue !

There can be many benefits having such a board, such a common hardware. For instance, everybody would be able to get a board, and experiment with it (educational benefits). Keeping hardware problems away helps focusing on the real experiment's content. Jaluino provides a base, a context on which anyone can build extra boards. These can then be shared with everyone, easily, since Jaluino is the common base. This is what Arduino's shields are about, and what would be nice to reproduce.

Which PIC should be used for Jaluino ?

The size and the features are what matter. A USB capable PIC is somewhat mandatory, it opens oportunities for nice experimentation. 18F PICs seem to be the candidates. What about these three PICs:

  • 18F14K50 : 20-pin, cheap, lots of features
  • 18F2550 : 28-pin
  • 18F4550 : big fat 40-pin, the max for a PDIP package.
Following Arduino's ideas, several Jaluino boards could be provided:

  • Jaluino Mini : 18F14K50 based, breadboard layout (no shield connectors, just plug your Jaluino board on a breadboard). Closed to Pinguino, but with a smaller PIC
  • Jaluino Medium : 18F2550 based. Board contains connectors on which we can plug shields. A breadboard version can also be built (same as Pinguino)
  • Jaluino Maxi : 18F4550 based. Board is "shieldable" too, a breadboard version may not be a good idea, as the PIC is quite big a would require a rather large breadboard.

(we'd definitively need to work on marketing names for "Mini", "Medium", "Maxi"...)

Connectors for shields

Despite several Jaluino boards would be available, shield connectors have to be compatible. Ex: a shield for 18F2550 can be used with a 18F4550 (the reverse isn't true...). As Arduino Diecilima's shields are compatible with Arduino Mega. This can be done by extanding the 18F2550 layout by other connectors.

Comparing 18F2550 and 18F4550 pins, we can see one is perfectly included into the other. In green, pins from 18F2550 which be found in 18F4550, in blue, 18F4550 only pins. Circle-red pins are important features: serial, I²C, USB and OSC. Fortunatly, these are carried by the exact same pins between 18F2550 and 18F4550.

PIC 18F2550

PIC 18F4550

(also note 18F877 could be used and plugged into a Jaluino Maxi as OSC, RX/TX are carried by the same pins as in 18F4550. Only I²C -- and USB of course -- pins aren't compatible).

The general layout for Jaluino Medium and Jaluino Maxi would look like this (not scaled...). Orange connector is dedicated to power supply. Green connectors are exactly on the place between Maxi and Medium Layout, these are the compatible pins. Blue connectors export 18F4550 pins only.

Other connectors...

Several other connectors would be needed:

  • USB, of course...
  • I²C : following Joep's suggestion, a 5-pin header (+9V,+5V, GND, SCL, SDA) can be used a dedicated connector, making easier connection between boards & other parts using this protocol
  • Serial : again, following Joep's suggestion, a 4-pin header (+5V, GND, TX, RX) would allow to plug any serial module (see later)
  • ICSP : to easily program the chip, even if no bootloader is present

Serial : different options

In addition to dedicated USB connector, a serial connector would allow easy comms. from Jaluino to the external world. But what type of connector to provide ? DB9 ? USB via USB-to-serial conversion ?

Here are the different alternatives, depending on budget limits, easiness to make, and parts used to build this module:

  • USB-to-Serial via FDTI chip: widely parts, but FTDI chip only exist on SSOP package, hard to solder (but not impossible). Small. USB can be used to power the board.
  • USB-to-Serial, using a 18F14K50 : easy to make (though 18F14K50 may be quite hard to find...). Size to define. USB can be used to power the board.
  • DB9 connector, using MAX232 chip : classical, quite big. External power supply will be required
  • what-you-want option: just plug a module which honor the connector's interface. For instance, I have a bluetooth-to-serial module, this gives the opportunity to easily integrate it to Jaluino.

Few words about bootloader

ICSP connector make the develop-program-test cycle faster, preventing unplug/plug the chip to program it. But still it requires a programmer... A bootloader is required here.

There are many different ones out there, but Tiny Bootloader is widely used, very (very) small, many different programs exits for many different platforms. Bootloader should be able to be triggered without having to manually reset the device (see here for more, it seems to require some hardware parts).

A first schematic

I started to build a schematic. Please keep in mind this is very alpha, and this is not even supposed to work...


Following Arduino, I'd like to release Jaluino schematics & PCB under Creative Commons Attribution-Share Alike 3.0.

Basically, it says:

  • AttributionYou 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).
  • Share AlikeIf you alter, transform, or build upon this work, you may distribute the resulting work only under the same, similar or a compatible license.
See here for more details.

Any suggestions ? Would you like to join the effort ?

PS: see this thread on jallib group for a discussion. Also search the group more...

Sébastien Lelong

Friday, July 10, 2009

Using new ADC libraries

Since several weeks or months, quite a lot of effort has been put into the development and update of ADC libraries. Why ? Because when Guru Stef Mientki first developed this library, he designed it for quite a few PICs (but most used ones at this time). Since jallib is to support all (or as much as) possible PICs, it was time to have a look on this huge piece of code...

Many different cases...

As usual, Microchip PICs offers a wide choice configuring ADC:
  • Not all PICs have ADC module (...)
  • Analog pins are dispatched differently amongst PICs, still for user's sake, they have to be automatically configured as input. We thus need to know, for each PIC, where analog pins are...
  • Some PICs have their analog pins dependent from each other, and some are independent (more on this later)
  • Clock configuration can be different
  • Some PICs have 8-bits low resolution ADC module, some have 10-bits high resolution ADC module (and some have 12-bits, those aren't currently handled, that's a restriction...)
  • Some PICs can have two voltage references (VRef+ and VRef-), only one voltage reference (Vref+) and some can't handle voltage references at all
  • (and probably other differences I can't remember :)...
Luckily most of these differences are transparent to users (hey, that was the goal of this refactoring/rewriting...).

Dependent and independent analog pins

OK, let's write some code ! But before this, you have to understand one very important point: some PICs have their analog pins dependent from each other, some PICs have their analog pins independent from each other. "What is this suppose to mean ?" I can hear... Let's consider two famous PICs: 16F877 and 16F88. 16F877 datasheet explains how to configure the number of analog pins, and vref, setting PCFG bits:

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
Note: this is the behavior of the original Stef's lib adc_hardware.jal

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.

Note: As a consequence, these procedures don't exist when analog pins are dependent as in our first case.

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)

"Stop it, show me some code !"

Basically, all the logic accessing ADC module has been kept. Most of the work was about configuring the ADC module to handle all PICs. You'll find adc_read() and adc_read_low_res() functions, as usual. Changes only occur while configuring the ADC module.

16F877 : dependent analog pins

The following examples briefly explains how to setup ADC module when analog pins are dependent from each other, using PIC 16F877.

The following diagram is here to help knowing where analog pins are and where Vref pins are:

Example 1: 16F877, with only one analog pin, no 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
pragma target WDT disabled
pragma target LVP disabled
include delay

-- ok, now setup serial, we'll use this
-- to get ADC measures
const serial_hw_baudrate = 19_200
include serial_hardware

-- ok, now let's configure ADC
-- we want to measure using low resolution
-- (that's our choice, we could use high resolution as well)
const bit ADC_HIGH_RESOLUTION = false
-- we said we want 1 analog channel...
const byte ADC_NCHANNEL = 1
-- and no voltage reference
const byte ADC_NVREF = 0
-- now we can include the library
-- note it's now named "adc", not "adc_hardware" anymore
include adc
-- and run the initialization step

-- will periodically send those chars
var byte measure
forever loop
-- get ADC result, on channel 0
-- this means we're currently reading on pin RA0/AN0 !
measure = adc_read_low_res(0)
-- send it back through serial

-- and sleep a litte to prevent flooding serial...
end loop

Example 2: 16F877, with 5 analog pins, 1 voltage reference, that is, Vref+

This is almost the same as before, except we now want 5 (analog pins) + 1 (Vref) = 6 ADC channels (yes, I consider Vref+ pin as an ADC channel).

The beginning is the same, here's just the part about ADC configuration and readings:

const bit ADC_HIGH_RESOLUTION = false
-- our 6 ADC channel
const byte ADC_NCHANNEL = 6
-- and one Vref pin
const byte ADC_NVREF = 1
-- the two parameters could be read as:
-- "I want 6 ADC channels, amongst which 1 will be
-- reserved for Vref, and the 5 remaining ones will be
-- analog pins"
include adc

-- will periodically send those chars
var byte measure
forever loop
-- get ADC result, on channel 0
-- this means we're currently reading on pin RA0/AN0 !
measure = adc_read_low_res(0)
-- send it back through serial

-- same for pin RA1/AN1
measure = adc_read_low_res(1)

-- same for pin RA2/AN2
measure = adc_read_low_res(2)

-- pin RA3/AN3 can't be read, since it's Vref+

-- same for pin RA5/AN4
-- 4 is from from "AN4" !
measure = adc_read_low_res(4)

-- same for pin RE10/AN5
measure = adc_read_low_res(5)

-- and sleep a litte to prevent flooding serial...
end loop

16F88 : independent analog pins

The following example is about setting up ADC module with PIC 16F88, where analog pins are independent from each other.

The following diagram is here to help knowing where analog pins are and where Vref pins are:

Example 1: 16F88, analog pins on RA0/AN0, RA4/AN4 and RB6/AN5. No voltage reference.

-- beginning is about configuring the chip
include 16f88
-- We'll use internal oscillator. It work @ 8MHz
pragma target CLOCK 8_000_000
OSCCON_IRCF = 0b_111
pragma target WDT disabled

-- ok, now setup serial, we'll use this
-- to get ADC measures
const serial_hw_baudrate = 19_200
include serial_hardware

-- now configure ADC
const bit ADC_HIGH_RESOLUTION = false
const byte ADC_NVREF = 0
-- we can't specify a number of ADC channel here,
-- or we'll get an error !
include adc
-- now we declare the pin we want as analog !
set_analog_pin(0) -- RA0/AN0
set_analog_pin(4) -- RA4/AN4
set_analog_pin(5) -- RB6/AN5

-- reading is then the same
var byte measure
forever loop

measure = adc_read_low_res(0)

measure = adc_read_low_res(4)

measure = adc_read_low_res(5)

end loop

Whether you would want to turn RB6/AN5 into a digital pin again, you'd just call:


OK, enough for now. Next time, we'll see how it works for real, with a "Step by Step" tutorial. We'll probably use a 16F88 for this, using serial.

As of July 19th, 2009, this ADC libraries aren't release yet (but expected to be soon). If you want to have fun with them, you'll have to get them from jallib SVN repository. See instructions here:

You can also get files one by one from SVN:

Anyway, browse SVN as needed :)

Sébastien Lelong