Building a PIC18F USB device
I get a number of emails every month asking about creating USB devices using the PIC18F microcontroller. After looking at projects such as my Atari Joystick USB Adaptor and C64 VICE Front-End there seems to be a demand for more information on how to ‘hack your own’.
In this article I will show how to breadboard a simple USB generic HID device, creating the PIC18F firmware and finally creating the Windows interface for the device which will allow you to control a LED from the PC and read the state of a push-button from the device. Since the advent of Windows 7 you need an expensive Microsoft validation certification to create custom USB drivers (without it most users cannot even install your software). Using the built in drivers for generic HID devices provides a simple method of creating Windows and Linux compatible devices and also makes the creation of both firmware and software far simpler. Since the HID standard does not require custom drivers you will not need to get a certificate for your driver, also both Windows and Linux have built-in libraries to help you communicate.
Update: I have updated this article to use the Microchip C18 compiler and to be based around my latest USB framework libraries for both the PIC and Windows (2011-10-19). This should provide a smoother path from this basic tutorial to more complex projects. As always I welcome your feedback and suggestions in the comments.
For this article we’re going to stick to a fairly basic USB device. The device will allow you to control a LED from Windows and also see the status of a push-switch on the device. Using this the basic principals of 2-way USB communication will be made clear allowing you to progress onto more complex projects.
To keep the cost and difficulty as low as possible I will concentrate on breadboard construction of the hardware using few components, the PIC18F firmware will be based on (the freely available) MPLAB and Microchip C18 compiler, the Windows software will be created using Microsoft Visual C# 2010 express (which is also free to download).
Although this article is based around the PIC18F4550 microcontroller you can easily substitute this for the smaller and cheaper PIC18F2550 which is code compatible with the larger 4550.
If you want to follow along with this article I suggest you scroll down to the bottom and download the accompanying software. Also make sure you have MPLAB, Microchip C18 for the PIC18F and Microsoft Visual Studio 2010 express installed.
Please note that all of the host screenshots are taken from a Windows 7 machine, if you need to find the same/similar thing on an older Windows box please head over to Google where you will find plenty of information about where the items are on your WindowsME machine.
To begin with we need to build a USB device to communicate with. In the following circuit diagram you can see the minimum configuration for a usable USB device. The device includes an ICSP header (In Circuit Serial Programming) and a USB type B connection. In addition there is a single LED and a single push switch to represent the input and output devices.
The circuit is very straight forward (if you are not familiar with this level of microcontroller electronics I suggest you go ahead and build some of the many flashing LED and push button tutorials available on the web before attempting this). The PIC18F4550 will be ‘bus powered’; this means that the device will draw its power from the USB host (your PC) so no power regulation is required. The 470nF capacitor (C3) is required so the PIC can operate the internal USB circuitry (it helps with regulating the USB voltages required by the on-board USB interface in the PIC) – Note that C3 can be any value between 220nF and 470nF (the datasheet recommends 220nF however I had 470nF available, it doesn’t make any odds to the functioning of the circuit.
The ICSP header allows you to connect a PIC programmer, I suggest using the inexpensive PICkit3 programmer, however other ICSP compatible programmers should work just fine. An external oscillator (crystal) is required for the PIC to be able to use the on-board USB module. In these examples (and the associated firmware) a 20Mhz crystal is used (this allows the PIC to use PLL which ups the clock speed to the required 48Mhz necessary for USB communication). You can use other crystal speeds, however I recommend you use 20 Mhz to begin with since otherwise you will need to alter the firmware.
The following picture shows the circuit constructed on a hobbyist breadboard. I’ve added some labels to the picture to make it clear which components go where. Please note that, for programming, we will be using the 5V supply from the programmer. Since this is a bus-powered USB device the 5V lines will be connected to the USB connector also. This means that if both the programmer and the USB cable are connected simultaneously there is the potential for the programmer to supply 5V to the USB host; this is not recommended by the USB standards. I’ve never seen a case where this matters (for experimentation purposes), but if you want, you can add a barrier diode to the USB connector to prevent this. In my projects I typically use a 1N5817 Schottky Barrier diode for this.
If you don’t have a USB plug for your breadboard you can either simply make one using a small piece of stripboard (such as my simple adaptor in the picture above) or you can cut one end of a USB cable, strip back the wires and put them directly into the breadboard. I’d recommend taking the time to make an adaptor, it reduces the risk of wires coming loose when you are plugging the USB cable in and out of your PC.
All of the resistors used are small 1/4W resistors. For all other components (such as the capacitors) anything which is rated to handle 5Vs and above will work perfectly. Also take care when reading the schematic, not all components are represented in ‘pin order’. Take note of the pin numbers when connecting everything together.
If you’re unsure of the wiring for the USB cable the following picture shows the pinout for a USB socket (female B type) and the standard cable colour coding:
Once you’ve built the circuit above be sure to check the positive and negative power connections for any shorts (use a multimeter to check for continuity between the 5Vs and ground) before plugging the device in to your PC; You don’t want to damage your computer. Always be sure to check things over before connecting either the USB cable or your programmer to avoid expensive repair bills!
In order to connect your USB device to the computer you will first need to write and compile some firmware for the PIC18F4550. Microchip (the manufacture of the PIC microcontroller) supply a freely downloadable USB stack just for this purpose. To make things easy I have written some simple firmware to drive the device, you can use this to get going and also as a basis for understanding how the firmware operates. Once you’ve got your first device running you will find it much easier to understand how you can adapt it for more complex applications.
The firmware has to perform two important tasks which are described below.
The first is USB device enumeration – this complex sounding feat is in fact the initial communication with the USB host (your PC) when the device tells the host what it is and how it wishes to communicate. USB communication is performed using ‘endpoints’ which send information either to the host or to the device. As well as setting up the communication channels the device must also pass its device name and two other important values: the VID and PID.
The VID is the Vendor ID and identifies the manufacturer of the device. To get your own VID you need to pay a thousand bucks or so to the USB standards body. In this example we will use Microchip’s VID to save the expense. If you are serious about producing and selling devices you will need to register one of your own.
The PID is the Product ID. Together with the VID they form a unique identifier for your device. When your device first enumerates Windows will store the VID and PID combination for the device; this is true even if you use a generic driver like the HID since it cuts down on the amount of time Windows needs to get your device ready. This is important because, if you decide to change your device’s enumeration information (add more endpoints, etc.), you will also need to at least change the PID before reconnecting otherwise you will get ‘Device not started’ errors even if you code is flawless (from experience I’ve noticed that Linux is not quite as fussy and tends not to complain if you keep the same VID/PID combination).
Communication with the host
The second important task the firmware performs is the actual communication between the host and the device. Each communication is identified by a ‘command’. When using the generic HID standard the ‘command’ tells the host and the device how to interpret the information which is passed with the command. This information could be anything (they don’t call it ‘generic’ for nothing!) and this is how you can achieve great flexibility in the tasks your devices perform.
Once your device is enumerated the host will periodically poll the device (this is always initiated by the host and not the device (although there are exceptions later when you get more deep into the communication protocols). On each poll the host can both send a command and data to the device as well as receive a command and data from the device.
The main part of the firmware which you should look into is the section which deals with the polling requests from the host and performs the necessary actions to make the device work.
Installing and building the firmware source code
The reference firmware is targeted for the Microchip C18 compiler (and will not work with other PIC compilers without alteration). The firmware also relies on the Microchip USB stack (which is linked in enabling the code to be easily updated as new versions of the stack are release).
To install the firmware you will need to create a directory in which to place both the library and the firmware. You then have to run the Microchip Application Library installer and instruct it to install into a directory called “Microchip Solutions v2011-07-14” under the directory you created in the last step. The firmware is only tested against version 2.9a of the stack (which is contained in the v2011-07-14 installer) and you can download the library installer here (note: Microchip have a habit of moving files around… if the link breaks, please let me know in the comments!).
Next grab a copy of the firmware zip file (at the bottom of this article) and unzip it with the application library. If all goes well you should now have two sub-directories in the same directory called “Microchip Solutions v2011-07-14” and “WFF Generic HID Demo 3”. Now double-click on the “WFF Generic HID Demo 3” directory and load the project file WFF_GenericHID_Demo_3.mcp.
From within MPLAB you should be able to compile the firmware and then program it onto the PIC in the usual manner.
If you alter the relative location of either the library or the firmware you will need to change the include path in the firmware project to tell MPLAB where to find the application library. You can do this in MPLAB by going Project -> Build Options Project -> Directories -> Include search path and changing the relative path to match your set-up.
Since the VID/PID and the rest of the enumeration information is already prepared you should start by performing a build-all on the project and then download the resulting firmware to your PIC18F. Of course, you will need a sane build environment for this to work but there are plenty of resources via Google if you are having problems with your environment. Try some simple examples to make sure everything is ok before reloading this project and trying again.
Note: I have had a few comments on this section which has highlighted some issues. Unfortunately I haven’t found a good work-around yet but perhaps some information will help. Firstly when you install the application library from Microchip you have to be careful to make sure it is installed in a directory called ‘Microchip Solutions v2011-07-14’. Although this is the default, when you specify another install location (from the Microchip installer) you have to respecify the directory name again.
Secondly, there is no simple method of using relative paths for files in MPLAB (which is surprising since the Microchip Application Library forces you to use them). Therefore when you first open the supplied project some files may be shown as ‘missing’ in the project view. To solve this right-click on the missing files in the project view and select the find file option. You will then need to locate the correct file within the application library structure (if you know a good way to solve this please let me know via the comments!).
Both of these issues are due to the restrictive nature of Microchip’s Application Library licensing. I encourage you all to email Microchip’s customer service and ask them why the Application Library is not published as open-source using an OSI recognised licence.
Understanding the firmware source code
The firmware provides 3 commands:
- 0x80 – Toggle the LED
- 0x81 – Read the push-switch status
- 0x82 – Read the LED status
The code which performs these commands is located in the main.c source file in the processUsbCommands() function. This function is responsible for determining the required command and then sending and receiving data as appropriate. This is pretty straightforward since the USB stack takes care of all the underlying complexity; take a quick look at the source code and you will see how simple this really is. The only extra check performed by the function is to see if the device is in a ‘configured state’; this means that the device is connected to a host and enumeration has been successful.
The main function simply calls the USB stack to perform any low-level device tasks and then the processUsbCommands function over and over again. It is possible to do this either using interrupts or a while() loop; the definition in HardwareProfile.h controls how this happens.
To understand a little more about the enumeration process take a look at usb_descriptors.c and HardwareProfile.h which contain the information that is passed to the host when the device is first connected. In the source you will find the VID and PID information for the device as well as a series of configuration descriptors which explain to the host what type of interfaces the device has and the capabilities of the interfaces. The ‘endpoints’ are the connectors for the ‘pipes’ described earlier. There are also some strings which describe the manufacturer and the product textually. Windows usually uses these strings when naming USB devices.
Understanding the enumeration process and the descriptor formats is quite complex and is covered by the various USB specifications as well as a great book by Jan Axelson called ‘USB Complete – Everything you need to develop custom USB peripherals’ (ISBN 978-1931448086). If you are enjoying this article and want to get more serious about USB I would highly recommend getting a copy of the book, it certainly helped me when I was learning.
Overall the firmware is quite simple, all you need to get up and running communicating to and from the host is included. Obviously you can make this as complex as you like, but for the purposes of this article (getting you going with USB) there is plenty to experiment with.
Connecting the device
Once you have followed the steps above and downloaded the firmware to your USB device you are ready to get it connected to your PC. Since we are using the generic HID USB drivers there is nothing to install on the PC before connecting. Simply plug the USB cable into your device and then plug the other end of the USB cable into your PC.
Windows 7 should detect a new device and display the usual ‘installing new hardware’ notice. After a few seconds you should see the following dialogue window:
If you then navigate to your start menu and select ‘devices and printers’ (if you have an older version of Windows you need to look elsewhere in the control panel, but the result is just the same. All these screenshots are from Windows 7) you will see the new device displayed on the screen. You should see something like the following window:
That’s it, your first USB device is enumerated and ready to go! Now we can move on to the host-side of the programming and looking at how you can communicate with your device using Microsoft Visual C# 2010. Note: The default status of the LED is on, it should light up shortly after you connect the device.
The host software is based on my open-source Generic HID library. You can find full details about it and how it works Open Source Framework for USB Generic HID devices based on the PIC18F and Windows.
The host software is fairly straight-forward and basically consists of 3 parts all contained within the Form1.h file:
- Monitoring the USB device to ensure it is connected (and disabling user input and device communication if it’s not)
- Displaying and processing the user interface form to allow the user to interact with the application
- Communicating with the USB device and updating the device status
To run the host software unzip the Visual Studio 2010 express zip file and load the project into Visual Studio. Once you compile and run the code you should then be presented with the following dialogue:
To test the device detection simply unplug the USB cable from your PC. The dialogue should change to the following:
Now reconnect the USB device, wait until the status label updates (and says attached), now try clicking on the ‘Toggle LED’ button. You should see the LED on the breadboard turning on and off… cool huh? 🙂
Next make sure that the LED status label in the window matches the actual LED status. This is the 0x82 command in the firmware in action. Finally try pressing the push-button on the breadboard, you should see the push button status change accordingly in the window.
Congratulations, you are now the proud owner of your first self-made USB device!
I’ve included the full source code in the Visual Studio zip file, so you should be able to view the project in Visual Studio to get a better understanding of how it works.
Where to next?
The USB generic HID interface is one of many available interface types in the USB standard (although it is arguably the most useful to PIC developers). Using exactly the same techniques shown in this article you can build data-loggers, robotics interfaces, custom interface hardware, etc. etc. The list is endless.
Hopefully this article has given you an insight into what’s possible, for your next steps I strongly recommend you take a look at my Open Source Framework for USB Generic HID devices based on the PIC18F and Windows.
Furthermore, if you would like to continue to experiment but would like a more powerful reference hardware environment please check out my PIC USB Development Board which allows you to easily experiment with many more USB designs and interfaces.
Files for Download
MPLAB project files for the PIC18F4550 firmware (The firmware files compile with the Microchip C18 compiler using MPLAB. Both can be downloaded from Microchip for free):
Visual C# 2010 Project files for the Windows host program:
21 Responsesso far.
Leave a Reply
You must be logged in to post a comment.
I have a question about something you say in your text.
You say “To install the firmware you will need to create a directory in which to place both the library and the firmware. You then have to run the Microchip Application Library installer and instruct it to install into a directory called “Microchip Solutions v2011-07-14” under the directory you created in the last step. ”
What is the Microchip Application Library installer excatly? Where can I find this and how do I need to do this?
If you scroll back to that part of the article and click on the link in the sentence “download the library installer —>here<--- (note: Microchip have a habit of moving files around… if the link breaks, please let me know in the comments!)." - then you can download the library. Other than that, all you have to do is run it and follow the instructions that you copied.
Thank you Simon for your response!
I installed the Microchip Application Library installer from your link but when installed where can I find this to run this? After a long search I didn’t find it.
And what do you exactly mean with “To install the firmware you will need to create a directory in which to place both the library and the firmware. ”
Which files do you mean with library and which are firmware?
If I open the WFF_GenericHID_Demo_3 in MPLAB and try to build it’s fails.
I think it’s because I miss 2 files
I think I found the 2 files, I aded them in MPLAB so they aren’t missing anymore but build is still failing.
This is the location where I found them.
1. usb_device.c : C:\Microchip Solutions v2011-07-14\Microchip\USB
2. usb_function_hid.c : C:\Microchip Solutions v2011-07-14\Microchip\USB\HID Device Driver
What I’m I doing wrong or how do I need do do this?
Ooow sorry there are a lot off more file’s that are missing in my MPLAB program.
Did you follow the part of the article that stated “If you alter the relative location of either the library or the firmware you will need to change the include path in the firmware project to tell MPLAB where to find the application library. You can do this in MPLAB by going Project -> Build Options Project -> Directories -> Include search path and changing the relative path to match your set-up.”?
I followed your tutorial and built and loaded the project perfectly fine, however, when I connected the USB to the PC nothing happened, no pop up or anything. Your tutorial does it in Windows 7, but I am using Windows 10. Could that be the issue as to why I am not getting anything? Or do you think it could be something else?
It is most likely a problem with the hardware, it should work fine under Windows 10. Check your USB connection and make sure you have 5Vs power and that the D+ and D- lines are the right way around.
It was a hardware problem. The USB connections were loose, but we got it to work. Thank you so much!! This was the best tutorial we found.
I have just tried this project. The system detecting as unknown device. The same micro controller I used.
It’s almost always a hardware issue. Check the USB connections, make sure you have 5V and ground, then verify the D+ and D- lines are the correct way around.
Thanks Simon it was hardware issue
Great 🙂 Glad you got it sorted!
Thanks for a great project. I have used it to design a USB audio mixer, USB oscilloscope and USB LC meter.
I would like to build a switch panel to control the switches on Microsoft Flight Simulator using the PIC18F14550 via USB. My question is regarding the Host Software. After I program the Firmware Source for the PIC which will contain the Joystick Descriptor, and I plug in the panel to the computer, do I also have to write the Host Software or does the Firmware from the PIC automatically creates it for me. In other words when I go to the control panel and select Game Controllers–> select the joystick –> select properties , do I have to program the Joystick Properties window(contains the switches for me to test) that pops up or does it get created for me?
Thank You so Much,
Provided you use the HID joystick protocol you won’t need a driver on the PC as it’s built into both Windows and Linux. If you look back through the projects on this site in the PIC section you’ll find one called ‘Atari Joystick USB Adaptor” that implements most of what you need (as an example).
Hi Simon, I am new to this group. I enjoyed reading your interesting article “Building a PIC18F USB device”.
I am using the MPLAB X IDE and XC8 compiler. What would be the likely changes I have to make to implement your project in this environment. Thanks in advance for your guidance.
This project is pretty old these days, and it’s been a long time since I’ve used PIC devices (having moved to AVR and ARM) – so, I’m not really in a position to try this out with the current MPLAB versions.
Hi Simon, I want to implement a USB interface using the PIC18F26J50. From what I have seen from the data these devices have the same USB module as the PIC18F2550.
As a first move I setup your project and have built sucessfully with the original code. I am using the Hitec picc18 compiler so my first question is about your comment that the build only works with the Microchip C18 compiler ? so is this normal. Second point is when I change the PIC to the 26J50 I get a whole lot of errors around the CONFIG macros in the main file eg
…\Secure USB Time-Stamp\main.c; 53.31 Unknown macro (USBPLL) used in __CONFIG()
Can you please give me a pointer on how to fix this.
As I said in the previous post, the project is pretty old and I don’t have the environment set up any more; it’s probably better to ask on a dedicated PIC forum about porting code to the newer compilers.