A Test Circuit
Before we start anything, we’ll need a circuit to demonstrate our USB capabilities. Here’s a simple little gadget I made when I was starting out at my job.
Simple HID Joystick – Schematic and BOM
When I first made the circuit, I forgot to put an oscillator, so I stuck one on with a bunch of tape and some fancy rework. There are three analog inputs to the circuit as well as 6 contact buttons. We will be only using the 6 buttons to create a simple joystick for this example. Here’s a photo of the finished circuit, along with my trusty ICD 3.

USB Power
A bit of discussion is needed for the power options in USB. The USB specification allows a device to draw up to 100 mA during enumeration, and up to 500 mA after enumeration (if the host deems that the required power is available). If you need more power, you will have to provide it yourself through a separate power connection. A device that only uses the 5V power from the USB connection is considered “Bus Powered”. If a device does not draw any current from the USB connection, and only draws power from an external power source, it is considered “Self-Powered”. These are the two most common options. You can also create complex powered devices which takes priority depending on which power source is available. The diagrams below are taken from the wiring requirements from Microchip’s datasheets.

For this example, we can easily calculate how much power the circuit will require. The oscillator and the microcontroller subcircuits are by far the modules that take the most power. I would estimate them to be about 30 mA to 50 mA. The rest of the subcircuits draw minimal power as pull-up resistors and potentiometers are not very power hungry. Since we are below the 500 mA limit for the bus power device category, we can directly draw power from the 5V USB connection. The connections and bypass capacitors are shown below.

The Vcap pin bypass can be supplemented with another 0.1uF capacitor if desired. Since there are not that many digital switching circuits on this design, I opted not to add the capacitor. The VBUS and VUSB pins must be separated as they refer to very different votlages. The VBUS is the 5V connection directly coming directly from the USB connection. This pin is used to detect that a USB connection has been made. A high resistance resistor can be put in series on this pin to reduce susceptibility to surges and voltage spikes. The VUSB pin is used to power the USB module on the PIC24. Since the data signaling on the USB is at 3.3V, this pin is also connected to 3.3V. In some situations, you might be powering your PIC at a lower voltage (ie. 2.5V). However, the VUSB pin must always be at 3.3V due to the USB physical layer electrical requirements.
Exploring the USB stack
If you haven’t read the first section of the USB tutorial, please follow the instructions in that section to install the Microchip Applications Library (MAL). Next we need to made a copy of the USB stack. I usually do this because I want to make sure that my base code does not get changed when there is an update to the Microchip Application Library. The location of the USB stack is “./[MAL Directory]/Microchip/USB/”.
I have a dedicated directory for all of my PIC projects, and a copy of the USB stack is copied to this directory. Below is a snap show of my directory structure.

All of the compiled binaries for modules and drivers are stored under “lib”. All of the source codes for modules and drivers that are not complied are stored under “nlib”. All projects are stored under “projects”, and finally all of the Microchip drivers are stored under “Microchip”. There are definitely other way to arrange your files, but I find this system to work quite well.
Creating a Project
Microchip is slowly phasing out MPLAB, so we are going to do this next project with MPLAB X. I have some Java programming background, so using a NetBeans IDE was second nature to me. Overall, MPLAB X has been pretty good, although, it’s still quite a bit buggier than the original MPLAB (as of August 2011).
We will now create a new project using the New Project wizard.

It will ask you a few questions, but you should end up with an empty project “Standalone Project”. My circuit uses a PIC24FJ32GB002T-I/ML so make sure the appropriate controller is picked. Now we add some files. Add the following sources from the “./[MAL Copy]/Microchip/USB/” and its subdirectories.
usb_device.c
usb_function_hid.c
These are the only drivers needed for now. We now need to add the header files for these USB drivers. A quick way to do this is to add all the header files in a directory by listing it in the “Include” directory during compilation. We can right click on the MPLAB X project and select “Properties”, then select the “pic30-gcc” option for “Include directories”. Add the necessary directories so that the correct header files will be included. This will add all header files in the directories without having to individually select them.

We are now ready to create a support package for our USB circuit.
Creating a Board Support Package
A Board Support Package (BSP) is a common term used to describe a bunch of headers and sources that are used to define pins and timing information for a specific circuit. Embedded programmers like to separate the reusable code from the board specific code. This way the least amount of work has to be done every time a new board revision comes out. We will now create a board support package for this particular circuit.
The file we will first create is a master “include” file. This file has all the headers listed together, and more importantly, it lists the headers in the order in which they should be included. I usually name this file “dev.h”. Below is the code listing.
(dev.h)
/******************************************************************************
Engscope.com
Author JL
Created Jul 16, 2007
Modified Aug 27, 2011
Master Include for USB Simple Joystick
******************************************************************************/
#ifndef DEV_H
#define DEV_H
//include proper headers
#ifdef __PIC24F__
#include "p24fxxxx.h"
#elif defined __PIC24H__
#include "p24hxxxx.h"
#else
#error No valid target device
#endif
//type definitions
#include "GenericTypeDefs.h"
#include "Compiler .h"
//board support
#include "bsp.h"
//USB drivers
#include "./USB/usb.h"
#include "./USB/usb_device.h"
#include "./USB/usb_function_hid.h"
//nlib driver
#include "nlib_sys.h"
#include "nlib_hid.h"
#include "nlib_drv_btn.h"
#endif
The main advantage of a master include file is that the headers are always linked in the exact order specified in the “dev.h” file. The symbols that needs to get defined first, are guaranteed to be defined first. In the above listing, I first include the device specific header, then Microchip’s type definitions, then the file “bsp.h”. This last file has the board specific symbols that I will explain shortly. Next comes the USB drivers, and lastly, drivers that I have written myself.
We now need to define some board specific symbols, and we will do that in the file “bsp.h”. Here’s a sample listing of what to expect:
(bsp.h)
/******************************************************************************
Engscope.com
Author JL
Created Jul 16, 2007
Modified Aug 27, 2011
Board Support Package for USB Simple Joystick
******************************************************************************/
#ifndef bsp_h
#define bsp_h
/******************************************************************************
Timing control bits
******************************************************************************/
//oscillator frequency
#define BSP_PRIMARY_OSC_HZ 8000000UL
//mcu frequency
#define BSP_FCY_HZ (BSP_PRIMARY_OSC_HZ / 2)
//timer 2 tick frequency
#define BSP_TMR2_FREQUENCY 1000UL //1 ms ticks
#define BSP_TMR2_PERIOD (BSP_FCY_HZ / BSP_TMR2_FREQUENCY)
/******************************************************************************
Pin definitions
******************************************************************************/
//define buttons, policy
#define BUTTON1 PORTBbits.RB2
#define BUTTON2 PORTBbits.RB3
#define BUTTON3 PORTBbits.RB4
#define BUTTON4 PORTBbits.RB5
#define BUTTON5 PORTBbits.RB7
#define BUTTON6 PORTAbits.RA4
/******************************************************************************
Custom Types for HID control
******************************************************************************/
typedef union HID_CONTROLS_TYPEDEF
{
struct
{
BYTE B1:1; //buttons
BYTE B2:1;
BYTE B3:1;
BYTE B4:1;
BYTE B5:1;
BYTE B6:1;
BYTE Bpad:2; //filler
} buttons;
} HID_CONTROLS;
/******************************************************************************
BSP Function Prototypes
******************************************************************************/
//board specific functions
void BSP_init(void);
void BSP_ProcHid(HID_CONTROLS* joy);
#endif
Here I’ve included some board level information concerning the oscillator timing that may or may not be used. Each of the buttons are connected to a digital pin. These pin symbols are redefined to “BUTTONx” so that they are easier to use in the actual context of code. Next, I define a specific data type used to transfer information to and from the USB driver. Since our circuit uses six buttons, we will use one bytes to represent the data. This byte contains 6 bits for the buttons, plus 2 filler bits that won’t do anything. Lastly, we need to define some prototype functions that we will use in our “bsp.c” source file.
Next we need to create the source code for our board support package with the file “bsp.c”. Below is the listing of the file for this project.
(bsp.c)
/******************************************************************************
Engscope.com
Author JL
Created Jul 16, 2007
Modified Aug 27, 2011
Board Support Package for USB Simple Joystick
******************************************************************************/
#include "dev.h"
/******************************************************************************
define other board specific variables here
******************************************************************************/
BtnObj btnJoy1; //buttons
BtnObj btnJoy2;
BtnObj btnJoy3;
BtnObj btnJoy4;
BtnObj btnJoy5;
BtnObj btnJoy6;
//create function pointers using these private functions
int btn1() {return BUTTON1;};
int btn2() {return BUTTON2;};
int btn3() {return BUTTON3;};
int btn4() {return BUTTON4;};
int btn5() {return BUTTON5;};
int btn6() {return BUTTON6;};
/******************************************************************************
Timer Interrupt definition
******************************************************************************/
#define TIMER2_ISR_PRIO 4
void __attribute__((__interrupt__, auto_psv)) _T2Interrupt(void) {
//clear interrupt
_T2IF = 0;
btn_Proc(btnJoy1);
btn_Proc(btnJoy2);
btn_Proc(btnJoy3);
btn_Proc(btnJoy4);
btn_Proc(btnJoy5);
btn_Proc(btnJoy6);
hid_Proc();
}
/******************************************************************************
Board specific functions
******************************************************************************/
void BSP_init(void) {
//Disable Watchdog
RCONbits.SWDTEN = 0;
//configure for digital
AD1PCFG = 0xFFFF;
//set up timer
T2CON = 0;
TMR2 = 0;
PR2 = BSP_TMR2_PERIOD - 1;
_T2IP = 4;
_T2IF = 0;
_T2IE = 1;
T2CONbits.TON = 1;
//buttons needs to be pulled up
_CN6PUE = 1;
_CN7PUE = 1;
_CN1PUE = 1;
_CN27PUE = 1;
_CN23PUE = 1;
_CN0PUE = 1;
//set up buttons
btnJoy1 = btn_New();
btnJoy2 = btn_New();
btnJoy3 = btn_New();
btnJoy4 = btn_New();
btnJoy5 = btn_New();
btnJoy6 = btn_New();
btn_Init(btnJoy1, &btn1, 2000);
btn_Init(btnJoy2, &btn2, 2000);
btn_Init(btnJoy3, &btn3, 2000);
btn_Init(btnJoy4, &btn4, 2000);
btn_Init(btnJoy5, &btn5, 2000);
btn_Init(btnJoy6, &btn6, 2000);
//initialize HID USB Interface for joystick
hid_Init(HID_EP, &BSP_ProcHid);
}
//function processes the HID IOs
void BSP_ProcHid(HID_CONTROLS *joy){
joy->buttons.B1 = btnPressed(btnJoy1);
joy->buttons.B2 = btnPressed(btnJoy2);
joy->buttons.B3 = btnPressed(btnJoy3);
joy->buttons.B4 = btnPressed(btnJoy4);
joy->buttons.B5 = btnPressed(btnJoy5);
joy->buttons.B6 = btnPressed(btnJoy6);
}
This file uses many symbols, however, I no longer need to add the header directives individually because I know that my “dev.h” file has the header listed in the order that I need already. I can simply link all of the header files by including the “dev.h” file.
The file begins by defining some objects used to represent the buttons. These object use dynamic memory and samples the button inputs during a timer interrupt. Next I define the timer interrupt, which will be used to set up my periodic sampling of my buttons and to update the value to be sent over the USB connection. Several functions are then defined. “BSP_Init” is used to initialize some variables during the beginning of the program, and “BSP_ProcHid” is used to update the USB data structure used to represent buttons.
We also need to create a file that sends out data in the struct through the API defined by Microchip. This file is called “nlib_hid.c” and “nlib_hid.h”. The code is pretty straight forward, and I will omit posting any explanations here. You can find the files in the zipped project file in the subsequent tutorial updates.
We now need to define some USB hardware level stuff. The Microchip USB Framework stores all of the hardware specific definitions for the USB Stack in a file called “HardwareProfile.h”. I’ve simplified their version of the file with my own, which takes out all the code that are not used for the PIC24.
(HardwareProfile.h)
#ifndef HARDWARE_PROFILE_H
#define HARDWARE_PROFILE_H
/*******************************************************************/
/******** USB stack hardware selection options *********************/
/*******************************************************************/
//This section is the set of definitions required by the MCHPFSUSB
// framework. These definitions tell the firmware what mode it is
// running in, and where it can find the results to some information
// that the stack needs.
//These definitions are required by every application developed with
// this revision of the MCHPFSUSB framework. Please review each
// option carefully and determine which options are desired/required
// for your application.
//#define USE_SELF_POWER_SENSE_IO
#define tris_self_power TRISAbits.TRISA2 // Input
#define self_power 1
//#define USE_USB_BUS_SENSE_IO
#define tris_usb_bus_sense U1OTGSTATbits.SESVD //TRISBbits.TRISB5 // Input
#define USB_BUS_SENSE U1OTGSTATbits.SESVD
//Uncomment this to make the output HEX of this project
// to be able to be bootloaded using the HID bootloader
#define PROGRAMMABLE_WITH_USB_HID_BOOTLOADER
//If the application is going to be used with the HID bootloader
// then this will provide a function for the application to
// enter the bootloader from the application (optional)
#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)
#define EnterBootloader() __asm__("goto 0x400")
#endif
/** I/O pin definitions ********************************************/
#define INPUT_PIN 1
#define OUTPUT_PIN 0
#endif //HARDWARE_PROFILE_H
Lastly, we need to copy over some project specific definitions for our USB device. These files are written in a very specific way, and I don’t know how to create them. However, I can get a copy of them from the examples in the Microchip Application Library, then modify them for my own use. I have taken the following files from “./[MAL Directory]/USB/Device – HID – Joystick/Firmware” and copied it into my project’s folder:
main.c
usb_config.h
usb_descriptors.c
Before we go forward, the button drivers use dynamically allocated memory. We will need to tell the linker to reserve some of the ram for heap memory. Right click on the project and select “Properties”, then go to the “pic30-ld” options, and reserve a healthy amount of heap. I’ve selected 1000 bytes for this project.

The board support package is now complete, and we are ready to finish programming our USB joystick in the next section.
I am trying to implement a USB host (on the PIC24FJ64GB002) to communicate with a Digital Mixing Console. However, I am having a hard time understanding Microchip stack. And so I am trying to write my own code. I am using a Flash drive to test the enumeration process.
Using the info in the PIC24 data sheet, I am able to get an ATTACH Interrupt and RESET the device. However, when I try to send the GET DESCRIPTOR(Device), I get an Interrupt but the info in BD0STAT is not updated. And if I try to retrieve the data for GET DESCRIPTOR(Device) nothing happens. I am sending the following for the GET DESCRIPTOR(Device);
unsigned char USB_Output_Bufer[10] __attribute__ ((address(0×2400)))={0×80, 0×06, 0×01,0×00, 0×00, 0×00, 0×00,0×12 };
And I place 0×2400 in BD0ADR.
If I could get through the ENUMERATION process using anyone’s code, I would be ok.
Your advise would be very much welcome here.
Thanks so much.
@Dave. Unfortunately, I have not yet implemented a USB host as of yet. I do know however that implementing a host is an order of magnitude more difficult than implementing a USB device. In order to be compliant as a host, it is actually very difficult to test. I believe the standard way to implement a host is to get a USB compliance tester, and then analyze the packets. It seems like you are already capable of doing this so you are ways ahead of me in terms of development. If you just need flash storage, I would suggest using the MMC stack that Microchip provides and using perhaps SD cards for your storage needs.
Best of luck.
-J
J,
Thanks very much for your response and suggestions. And thanks for your tutorials. I have gained, and hope to gain much understanding of the operation of the PIC PIC24FJ64GB002 as a result of this website.
Best regards
Dave
Greetings, I am wondering, how do you configure the oscillator configuration for this project, you use the 8MHz oscillator installed on your circuit or the FRC on the pic?
@Alfredo. Depends on what you are doing. For USB, the clock requirements are outlined in the USB standard. The FRC is NOT precises enough for the USB to function (I have tried to get the FRC to go USB for who knows how many times). You will need an external oscillator with a good ppm in order for the USB to work. For real time clocks, you will need a 32.768K oscillator that is temperature compensated since the FRC tends to vary a lot depending on temperature. This is due to the de-rating of the capacitors in the RC circuit of the oscillator. For everything else, FRC is actually quite good.
-J
Yeah, I understand that, but i downloaded your project from the next chapter and watching your configuration bits it seems like you don’t use the primary oscillator but instead you use the FRC with the postscaler and PLL that is when I came with the question.
@Alfredo, you must be referring to this portion of the code.
The comments don’t align with the code. We are actually using the primary external as the symbol FNOSC_PRIPLL is used.