PIC-USB board

Because of illness, I have a lot of free time... So why not to put something interesting on my web page. This time it will be project describing how to interface microchip PIC microcontroller with USB (full speed) interface. Some people like working with ATMEL processors and this project will show why is PIC better :) Lets have a look at google, try to find the most simple USB interfaces with ATMEL. What you will find is : 1.circuits with FTDI chips (USB to serial converters) and some EEPROMS, 2.circuits with software emulating whole USB protocol (bit-banging). But when using PIC18F4550 or other device from this family with USB support, you just need only PIC and some passive components, thats all !

This project can be divided into three parts - hardware (PIC board), firmware, software (on the PC side). The schematic is taken from HACKADAY website, I made some improvements in the circuit design, changed some components to SMD 1206, to make whole board smaller. I added a 74HC595 shiftregister for driving LCD display (hitachi HD44780 compatible). Display is controlled by three signals (data, clock, latch). LCD and shiftregister driver is provided with the source code.

 Full size Eagle 18F4550usb2.brd

Board PCB
 Download BMP @ 600 DPI

 Full size Eagle 18F4550usb2.sch

Firmware comes from microchip website. It was intended to compile it with microchip's C18 compiler, that I don't like at all. I prefer hitech-picc compiler, but unfortunatelly source code was not possible to compile with this compiler. Somewhere on the hitech forums I found a remake of CDC (usb to serial port emulation). I think the guy behind this hard work is Shane Tolmie of www.microchipC.com. How else I made some improvements even in the sources. When you look at the MPLAB project window, there is a lot of USB support files. MPLAB does not support any organization of files into filters/folder. So I renamed some files related to USB support without the "usb" prefix to "usb_*". Now all the user-code is placed at the top of each filter. Then I changed all the include paths not to use absolute paths. Now you can download this project, unpack it anywhere you want and compile without any problems.

Project in MPLAB

Project file tree

Download all sources
Download microchip programs
Eagle 18F4550usb2.brd
Eagle 18F4550usb2.sch

Good idea is to use bootloader. If you dont own PIC programmer, just find someone who have it and burn the bootloader firmware fw\Boot\_output\MCHPUSB.hex (mchpfsusb.rar) into your pic. You just need to do that only the first time, any other flashing is done through USB cable and bootloader utility Pc\Pdfsusb\PDFSUSB.exe (mchpfsusb.rar). It greatly simplyfies all the work. If you want to use the source code I provide here as standalone application (without BOOTLOADER), look for COMPILE_STANDALONE precompiler definition.

I suppose, you have bootloader already installed in your PIC. So if you want to have fun with your USB board, load the fw\Hid\Mouse\_output\MCHPUSB.hex (mchpfsusb.rar) file through bootloader utility. After re-connecting the usb board, it will simulate the mouse moving in a circle. By changing the source code, you can make your own mouse controller - for example controlling mouse by using joystick (two potentiometers).

Mouse emulation code
BOOL emulate_mode;
rom signed char dir_table[]={-4,-4,-4, 0, 4, 4, 4, 0};
byte movement_length;
byte vector = 0;
char buffer[3];

void UserInit(void)
    old_sw2 = sw2;
    old_sw3 = sw3;

    emulate_mode = TRUE;
}//end UserInit

void ProcessIO(void)
    // User Application USB tasks
    if((usb_device_state < CONFIGURED_STATE)||(UCONbits.SUSPND==1)) return;

        emulate_mode = !emulate_mode;
}//end ProcessIO

void Emulate_Mouse(void)
    if(emulate_mode == TRUE)
        if(movement_length > 14)
            buffer[0] = 0;
            buffer[1] = dir_table[vector & 0x07];           // X-Vector
            buffer[2] = dir_table[(vector+2) & 0x07];       // Y-Vector
            movement_length = 0;
        }//end if(movement_length > 14)
        buffer[0] = buffer[1] = buffer[2] = 0;

        HIDTxReport(buffer, 3);
    }//end if(mHIDIsPutReportReady())
}//end Emulate_Mouse

When you want to compile any of your programs for use with bootloader, you need to comment all the config-word related things (probably it is not important, but the bootload utility will show some warning), then you have to specify the start address of program. Bootloader occupies the memory area (0x0000-0x07xxh, don't know exactly it's size), and your program have to start at address 0x0800. For some reason, bootloader utility dont take the produced .hex from hitech picc compiler file directly, you have to add a ":020000040000FA" string at the begin of the file. Hitech's team said, that in the newer version of their compiler there will be a possiblity to put the string into produced .hex file automatically. But for now (19.jun 2008) you must to put that string manually - by opening the .hex file in editor, or by script.

Build options

Correcting script

Burning .hex file with bootloader utility - press and hold the BOOTLOAD button and press RESET, or if you have only jumper switch, put the jumper on the LOAD place and reconnect USB cable. Run the utility and choose your board from combobox. Load your .hex file, hopefully it will not display any error/warning. Then you press the "Program Device" button. After programming press the RESET button. In the case of jumper, remove it and reconnect cable. Probably you will need driver .inf files (when connecting USB board to your computer, it will ask for them), you will find them in the mchpfsusb.rar archive (Pc\MCHPUSB Driver\Release\mchpusb.inf generic driver, fw\Cdc\inf\win2k_winxp\mchpcdc.inf for CDC).

 Full size

Wrong config-word
 Full size

What provided firmware does - Prints on the LCD display "Ready.", anything what you will send through this virtual port (in my case COM5:) will be displayed on the LCD too. Periodically sends "[alive]" string into your computer. The USB framework is based on Cooperative Multi-Tasking (No Blocking Routines), so you should never put any DelayMs(xx) into your routine, it is preferred to use state machine. The function ProcessIO() is called in an infinite loop. In my case - it looks useful to use interrupt as reference clock. But for some reason my device will start typing err:trf=3 after 5 minutes, and cannot send any more text into my computer.

Pictures from real world - prototype design

 Click on a picture for full size view

Device recognized as virtual serial port COM5

Device manager

Device idly sending [alive] string through port and source code resposible for this.

COM monitor

User code example
#include "common.h"
#include "lcd.h"

char buffer[32];
long lCounter = 0;

void UserInit(void)

void ProcessIO(void)
  unsigned char cbReceived;

  if ( ++lCounter >= 100000L )
    lCounter = 0;
//      LCD_PUTCH('a');

  cbReceived = getsUSBUSART( buffer, 31 );
  if (cbReceived)
    buffer[cbReceived] = 0;

 Download all sources Download microchip programs

When compiling provided source code, in the output window should be something like this. If not, download correct version of compiler (PICC 18 STD) from hitech website.

Succesful build

Build C:\....\usb for device 18F4550  
Using driver C:\Programs\..\picc18.exe

Executing: "C:\Programs\..\picc18.exe" -C C:\....\autofiles\usbdsc.c 
  --chip=18F4550 -P --opt=default,+asm,9 --warn=0 -Blarge --double=24 --cp=16 -q -g 
  --asmlist "--errformat=Error   [%n] %f; %l.%c %s" "--msgformat=Advisory[%n] %s" 
  "--warnformat=Warning [%n] %f; %l.%c %s" 
Executing: "C:\Programs\..\picc18.exe" -C C:\....\htmorph\picc18_fuses.c ...
Executing: "C:\Programs\..\picc18.exe" -C C:\....\htmorph\spi.c ...
Executing: "C:\Programs\..\picc18.exe" -C C:\....\htmorph\usart.c ...
Executing: "C:\Programs\..\picc18.exe" -C C:\....\system\usb\class\cdc\usb_cdc.c ...
Executing: "C:\Programs\..\picc18.exe" -C C:\....\system\usb\usb9\usb9.c 
Executing: "C:\Programs\..\picc18.exe" -C C:\....\system\usb\usbctrltrf\usbctrltrf.c ...
Executing: "C:\Programs\..\picc18.exe" -C C:\....\user\usb_user.c ...
Executing: "C:\Programs\..\picc18.exe" -C C:\....\system\usb_main.c ...
Executing: "C:\Programs\..\picc18.exe" -C C:\....\user\main.c ...
Executing: "C:\Programs\..\picc18.exe" -C C:\....\user\lcd.c ...
Executing: "C:\Programs\..\picc18.exe" -C C:\....\system\usb\usbdrv\usbdrv.c ...
Executing: "C:\Programs\..\picc18.exe" -C C:\....\user\delay_18.c ...
Executing: "C:\Programs\..\picc18.exe" 
  -ousb.cof -musb.map --runtime=default,+clear,+init,-keep,-download,-ramtest 
  --codeoffset=800 usbdsc.obj picc18_fuses.obj spi.obj usart.obj usb_cdc.obj usb9.obj 
  usbctrltrf.obj usb_user.obj usb_main.obj main.obj lcd.obj usbdrv.obj delay_18.obj ...

Memory Summary:
    Program space        used   FE8h (  4072) of  8000h bytes   ( 12.4%)
    Data space           used    58h (    88) of   400h bytes   (  8.6%)
    EEPROM space         used     0h (     0) of   100h bytes   (  0.0%)
    External data memory None available
    ID Location space    used     0h (     0) of     8h nibbles (  0.0%)
    Configuration bits   used     0h (     0) of     7h words   (  0.0%)

Loaded C:\....\_output\usb.cof.