My Very First USB Peripheral
Earlier this month I talked about the Microchip PIC16C745 and PIC16C765, which are 8-bit microcontrollers with built-in low-speed USB. Since that time, I’ve got hold of one of these devices and built a simple USB peripheral with it. Click on the thumbnail for a bigger version of the image.
Summary: hardware easy, firmware tricky, software painful. Read on for more detail and some hints for anyone treading the same road in the future.
[Last updated 20050606: added firmware source code.]
As you can see from the image, the hardware is simplicitly itself. (If you’re really interested, you can look at a schematic). You can see the USB B connector at the far left, carefully soldered to some wires: I did take care to continue the data connections as a twisted pair, but other than that it’s really not subtle.
The PIC16C745 is in the centre; you can see that this is the ceramic /JW package from the little quartz window over the die. You uncover this when you want to reprogram the chip; it takes about ten minutes cooking in my UV eraser. Theoretically, the processor can start up badly unless you cover the window when the chip is in use, so I usually put a little orange sticky dot over it on a programmed device.
Above the processor you can see a crystal and two capacitors giving us the required 6MHz reference frequency. It turns out that low-speed USB is more flexible about frequency accuracy than the faster variants and that a ceramic resonator would have been sufficient and a little cheaper. That’s probably more a concern for people interested in production quantities; you can get a bag of those things for a fiver.
Just to the right of the processor you may be able to make out a decoupling capacitor and a resistor holding the chip’s reset pin high; just to the left of it you can see a resistor and capacitor that allow the device to pull up one of the USB signals at startup to indicate that it is a low-speed device. The bit of black sticky tape is there to remind me where the end of the chip goes after reprogramming it.
This is everything you need to get the device up and running; the remaining components on the breadboard are four little switches, each with an in-line resistor to help protect against static discharge, and two LEDs each with a current limiting resistor.
Things started well on the firmware front. Microchip do have standard firmware packages for these devices linked directly, for example, to the PIC16C745’s index page. Even better, though, they have a series of “canned applications” that are more useful for tutorial purposes, provided as technical briefs. The only problem is that these are almost impossible to find on their web site. For reference, I found all of them by reading through the list of all application notes and picking up everything that sounded interesting.
I started by downloading Technical Brief 54 and its associated source code package. This is An Introduction to USB Descriptors - With a Gameport to USB Gamepad Translator Example and the ZIP file contains a hex format file you can burn directly to a PIC16C745 or PIC16765. Plug in the USB connector and the device should be almost instantly recognised as a gaming device: no other drivers are required, at least on Windows since the 98SE version and under Linux 2.4. You can play with your new USB “gamepad” in the Windows control panel.
This surprisingly handy effect comes about because the firmware identifies the USB device as a HID class device: HID standing for Human Interface Device, i.e., one of those terribly slow things whose data rate is limited by how fast humans can twitch. Within the HID class, there is an additional specification to allow a device to enumerate its controls, their values and the usages intended: for example, a joystick device would have a couple of linear axes and some on/off buttons.
The problem comes if you want to deviate from someone else’s working setup, as you almost certainly will at some point. For example, I wanted to change the number of buttons and add a couple of LEDs. To do this, you need to build new HID report descriptors and there you run into problems with incomprehensible standards documentation and inconsistent operating systems implementations.
There are several different kinds of descriptor you need to build to make a working USB device. Some of these are described in the USB standard itself (hint: for most purposes, just read the 1.1 standard as it is substantially shorter), some in the HID adjuncts to that standard. The most difficult of all to understand are the HID report descriptors and the system of usages and usage pages: I found that apparently sensible changes to a descriptor would just silently “not work”, resulting in a device that was invisible to Windows 2000. My advice is to make small changes, step by step, from a known working system to where you want to go. Back up at every stage before making a change, and revert immediately if something doesn’t work. Don’t be tempted to make too many descriptor changes at a time, even if it does take ten minutes to erase the device each time you want to make a change. Under no circumstances attempt to build descriptors from scratch, as most likely your device simply won’t configure; you get essentially no information as to the reason for this. If you’d like to compare the TB054 source code with my modified version, you can download my firmware source code.
There is definitely an operating system consistency issue as well: for example, I have seen configurations of controls that are acceptable in Windows 2000 but cause Windows 98SE to reject the device. You need to be able to test your firmware against all the target systems in order to be sure that it will actually work there.
The USB HID page includes a tool to be used to create HID report descriptors; it can perform minimal checking on the ones it creates or be used to do the same minimal checking on ones you’ve constructed elsewhere. It’s not infallible, though.
The other tool provided by the USB Implementers Forum that looks like it should be useful is USBCV. This only works under Windows 2000 and XP, and only works in systems with both a high speed (USB 2.0) host controller and high speed hub, even for testing low speed devices. Unfortunately, I don’t have a system meeting all of those requirements at present so I can’t yet say how good a diagnostic tool it is.
Other resources I found of use while debugging firmware:
- Snoopy Pro, a Windows application you can use to trace the requests being sent to your peripheral.
- USBCheck is the predecessor to USBCV. The official USB web site doesn’t have it any more, but you can get it elsewhere. It’s not always helpful (it says my device isn’t HID compliant, but not why) but it is better than nothing as it does let you poke around in the various descriptors.
- The Linux
lsusbcommand, which seems pickier about some things than Windows, and more verbose to boot.
- The web site for Jan Axelson’s book USB Complete. I suspect the book would be a good investment, too, either in its paper or slightly cheaper e-book form.
[2018-03-18: Updated link to the latest edition of Jan Axelson’s book.]
One last item that fits in under “firmware” better than anywhere else is the issue of vendor IDs. Like PCI and other “plug and pray” bus systems, your device presents a vendor ID and a product ID so that the host operating system can locate appropriate drivers. Unlike those other systems, there is no “experimental” vendor ID or apparently any way to get a legitimate vendor ID other than paying the USB Implementers Forum a minimum of $1500 every couple of years. Microchip do have a vendor ID, but as far as I know they don’t have a programme in place to hand out product IDs to customers as was the case for many PCI chip vendors. If you do the obvious thing and pick two random 16-bit numbers or some defunct company’s vendor ID, everything will (probably) work but you can’t use the USB logos on your products.
Host application software for a custom peripheral is where things get really painful. This isn’t the case if you’re building a joystick or a mouse or some other device for which operating systems already provide all the drivers that you need; all you need to do is fire up Flight Simulator and you’re done. If you want a host application of your own talking to a collection of custom peripherals you’ve designed, though, things are much harder.
Ideally, I’d want to be able to write a client application in a nice safe language like Java and have some hope of it talking to my USB devices under at least some variants of Windows and Linux. The bad news for me is that there is no stable Java API for USB yet, and neither of the attempts to date appear to have been ported to Windows.
The older of the two extant APIs is Java USB, which appears moribund and is currently Linux-only. Some Windows code was submitted to the project a year or so back, but it doesn’t appear to have been developed or available for use. The newer API is javax.usb, which apart from being quite active is also the subject of Java Community Process JSR-80: in other words, the aim is to make it into a semi-official standard. Unfortunately, this project is also currently Linux-only; something in the way of a Windows port is anticipated around the end of 2003 or early 2004.
One option I have considered is to make use of the fact that if I continue to make my peripheral pretend to be a gaming device of some kind (with some fake axes that never move), getting data from it can be done through Microsoft’s DirectInput API. It just so happens that an enterprising German developer has something that allows just this kind of operation from Java under Windows: this is JXInput; it works by using a JNI (Java Native Interface) library to bridge across from the Java VM to the DirectInput objects. This is a promising avenue, but unfortunately DirectInput gives essentially no way to write data back to the device, apart from the “force feedback” facilities. JXInput does not even support the force feedback option: this means I could read my buttons but couldn’t light my LEDs.
Microsoft’s DirectInput documentation covers this eventuality neatly by suggesting that the Windows HID functionality be used directly for these purposes. Of course, this could be the route for both data directions and another option would be to write my own JNI wrapper for the appropriate Windows API calls.
Stepping back from Java, there are of course several alternative programming environments for Windows. I know both C++ and Visual Basic well, and example code of varying degrees of crudity are available for these languages in various places (start at Jan Axelson’s site’s USB code page). However, neither language is really as good with multi-threading or asynchrony as Java is, and I really dislike the idea of learning to program the Windows GUI in C++ at this stage, having avoided it for so many years. Microsoft’s C# would be the new trendy alternative, but I’m unfamiliar with it except as being “Java like” at some level and having got the “Hello, C# world” console application running.
You can see from this that by far the most difficult part of the whole enterprise is software for the host. At present, I’m using an adapted version of some of Jan Axelson’s Visual Basic code but I’m far from happy that I could scale this up to drive several similar devices in an asynchronous way, and unfortunately that’s what I have in mind when I get beyond the pure experimental stage.
If I’m lucky, JSR-80 will happen before I get there.
I’d like to reiterate what you said about the HID descriptor. It’s difficult to understand, and even if you do think you understand it, only make small changes. Otherwise you’ll never know what went wrong, because something will go wrong. But don’t let me discourage anyone, with small steps, usb is very obtainable.
— HempHacker on November 10, 2003
I am praveen doing my master’s in biomedical instrumentation. i have to also design the embedded device which has usb output. so i m using pic16c745. i have to collect ECG and BODY FAT data and then after some calculations rocess it through the usb port. so please suggest me something that how i should have to start and how to progress it.
— praveen on December 27, 2003
hi my name is harry and i have built a device that
i now want to market i need to have my own usb conection to a computer as i have been using a key board usb at present… but when i plug it in windows reconises it as a k-board and this is not good for me to sell my invention on the web..
can you help as i want my own desing so there will be no come backs latter ?… please!!
my phone is redacted
— harry on February 2, 2004
Hi, i’m a student from M’xico city and i need to made a simple usb transmisor, and i’m very interesting in the example in the top, but i try to found the code you mention here to made a gamepad and i don’t found it, so maybe you can send me the zip.
— David Burgue’o on October 14, 2004
David, I have updated the links in the post so that they are correct for Microchip’s new web site organisation. You should be able to locate the TB54 files from the appropriate link now.
— iay on October 16, 2004
Hi, i need to know the value of the capacitors for the crystal, because i dont found it.
— David Burgue’o on October 19, 2004
David, for the crystal I was using the capacitors were 33pF. However, you should probably check the data sheet for the crystal you are using.
— iay on October 19, 2004
Hi again, thank you for answer me so fast, but i need more information, and i thank you for your help, i try to connect the pic like your diagram, but i can’t because i don’t understand it, i can’t see how is the connection do, i thank you if you sent me the diagram of how do you connect because i see in the microchip page and don’t undestand, thank you anyway
— David Burgue’o on October 21, 2004
Sorry again, but i dont undestand where do you connect each pin, because in the page of microchip some buttons are connected to pins that must be connected to ground or VDD, so i don’t undestand what happens, also i dont know where do you connect pin 1, and others, so if you got an electric diagram i thakfull a lot.
— David on October 21, 2004
I’ve uploaded a schematic and linked it to the article. It might not be exactly the same design as the one in the picture, but it is close enough and should help you a bit.
The link is also here.
— iay on November 4, 2004
Hello, I’m Ahmed a CS undergraduate from Egypt.
I am currently developing an HID class device and the chip that i chose was the PIC16C765. However, the chip’s program memory is an OTP one. Are there any emulators or simulators which i can use to test my firmware before actually programming it onto the chip?
— Ahmed on November 7, 2004
Ahmed, I think you need the UV erasable version of the PIC16C765. It is electrically identical but with a window on the top for erasure. It is the “/JW” version of the chip on this page. Hope this helps.
— iay on November 7, 2004
There is a new version of PIC16C765, which has flash memory so it can be reprogrammed. The new chip is PIC18F2455 (also an LF), PIC18F2550 and there a couple in 40 pin package.
— P Gandhi on January 22, 2005
I have a working application with pic16c745 and want to migrate to pic18f2455. I’m programmed my firmware in C. What changes do I need to do to have it work.
Thankfull for any responds.
— Michael Stankov on February 16, 2005
I have an working application with pic16c745 programmed with C and want to migrate to pic18f2455.What changes (software and hardware) do I have to do to make it work?
— mordor on February 16, 2005
Hi, i’m trying to develop a new hardware using de usb pic16c765 but as you explain i have some trouble with the descriptor, i don’t know if i have to use the “vendor especific” option in class, subclass and protocol part. How do i make windows to belive it’s a new device, and how do i control my device from visul basic…
I hope you can help me, and if you can give me any example i’d be thankful…
— Andr’s Cadena on February 23, 2005
I’m trying to exchange some data with PC/PIC16C765, via USB.
All I want to do is send one byte to PC, and from PC to PIC, like in RS-232 serial connection.
Is it dificult?…
I’m working on Delphi, and didn’t find much for connecting it…
My e-mail is email@example.com
Thanks for any help,
— Julio Silva on March 1, 2005
I used Microchips vendorId and it worked.
— mordor on March 2, 2005
I am just starting in learnng and developng USB PIC applications. My first comment is to those using Delphi. The JEDI library has a HID component that is a fundamental cornerstone to using Delphi with HID devices. My second comment is that the Velleman Kits web site has downloads for its own K8055 USB interface kit and though these do not show the code for the 16C745, they do have access to the Delphi source code that uses the Jedi component.
My real request is that though there are a lot of examples of PIC source code for 16C745 and 16C765 processors there is very little for the new Flash programable 18F2455 and 18F2550 OR rehoasting from the 16C745/765 across to these Flash programable chips. Has anybody tried to use these chips yet.
— D Lockwood on April 9, 2005
The PIC18FXXXX devices are great devices to use with their expanded instruction set. I would like to find firmware code for the USB perhiperal also. Has anyone bought the “PICDEM Full Speed USB” from Microchip (currently $59)?
— G Sitongia on April 14, 2005
I am just starting with USB PICs.
So far I have managed to modify the Microchip LCD demo to light LEDs and to read some switches. BUT every time I try to modify the HID descriptor I run into troubles.
Also I am trying to get an immediate echo-back of commands from the PC to the chip. Its wierd but whatever I do in copying between ‘outbuffer’ and ‘inbuffer’ there is a delay of one write/read cycle before I get the values back. Also if I change so that the same buffer is echoed back, the whole chip stops being recognised by windows.
What I realy need as a starting point is a true ‘skeleton’ outline ‘that works’.
— Dave Lockwood on May 3, 2005
Hi, my name is Humberto and I am from Brazil, I would like to know if you could send to me the entire code about this project to see what kind of changes you made in the original one from Microchip.
Thanks from Brazil
— Humberto on June 5, 2005
I’ve uploaded my source code and added it to the article so that you can download it. As well as the link in the article, this one should work.
I have not looked at this code in nearly two years, so you’re on your own if you download this. Good luck!
— iay on June 6, 2005
i just started using this pic16c745. how do i send a byte from pc to the chip using usb connection?
— illas on June 17, 2005
I have a PIC16C745 programmed in assembly interfaced with usb i now what to use the PIC18F2455 with the same code so as to take advantage of the 10 bit adc, I’d be extremely gratefull if anyone could help me out with a way to get around this problem.
— neep help on June 27, 2005
ALERT: SPAM warning in effect! :D
One suggestion to those that want to have their own Vendor/Product ID but cannot afford the $1500-2500 price tag from USB.ORG, check out M’canique:
They will lend you their Vendor ID along with 10 Product IDs for a small fee. The nice thing is that you can replace the text in the little peripheral detect Window pop-up thingy with any text you want, totally independant of the Vendor ID used.
I found it a GREAT saving for a little budget like mine.
— Robert Hedan on June 30, 2005
I have now got somewhere reasonably sucessfull by starting with your gamepad code and ‘cut-paste’ and bodging to get a 16C745 to behave more or less exactly like the one on a Velleman K8055 board. That is it responds correctly to Vellemans own DLL and Application code. This gives me my own very valuble starting point. Going forwards to the 16C765 should be relatively easy.
BUT what I realy want to do is port my code to an 18F2550 and this is giving me real problems. Microchips own examples on their High Speed development board are too complex and are written in C. What I need is a Keep-It-Simple USB example of ASM on an 18F2550 or a 18F4550. Anybody know where I can find this.
Note: because my own code emulates the Velleman K8055 I have to ‘clear the ground’ with them before I can make it available.
— David Lockwood on August 23, 2005
Previously I’m sorry for my English, because it was so many time since the last time I wrotte on English.
I’m an Spanish student ot telecomms and I’m now working on my final project to obtain my certificate. That project consists in a hardware interface and a visual basic module that have to control a elevation and azimut rotator of a parabolic antenna for receive satellite signals. I designed an interface based on a 16C765 and an external A/D converter, a MAX180.
First the A/D converter didn’t work right but testing it I finally found the better way to make it run, but now, when the 16C765 was programmed and connected to the MAX180 all the computer where I tried to connect the interface didn’t recognize it and I have no idea of what is the problem. The first time I connected the interface to a computer the computer (I’m working on XP) shows a device not recognized error. I tested then the 16C765 with other programs and firmware as the PicCalc made by Alec McNamara.
Previously thanks for every help you can give to me.
— Esteban Bru on September 2, 2005
I am Harmish, an Engineering graduate. I am working on developing a general purpose peripheral which is having an USB interface. I learned about so many USB Microcontroller available form different vendors. I liked one available form Microchip is ver reliable (PIC18F4550). I have very good command in programming PIC Microcontrollers and Hardware. But I am very confused about writing the driver for the Device. I tried to surf internet, but I am helpless. I just wanted to know details of ‘How a driver can be developed’.
— Harmish on September 25, 2005
thank u for code this is very helpful to me
— binnypthomas on December 1, 2005
My name Mr.Arampee junyai, are electronic engineering in Thailand. Now I design about PIC18F2550/4550 communication between USB & PIC Device. But I confuse about driver in PC, I don’t know , how to begin,
My information Board.
Compiler are CCS Version 3.241
Windows 2000 / XP
Can you advise me….
Example code for PIC
Tool for create / built driver on PC (after Plug in Device)
— Mr.Arampee Junyai on January 9, 2006
I work on usb commucation with teh 18f2550 but i have some problems, some times work very well and some times doesn’t it. i don’t know what could happend.
Other question: when i transmitted from the PIC to PC hom much time i have for picking up from the pc?
I done the communication with my pc through Visual basic.
For programming the PIC i worked on CCS and i took their usb library PIC18_USB.H and USB.H.
— paola portilla on January 16, 2006
I’d love to help people with PIC18-based questions, but unfortunately I have never worked with any of them.
If anyone reading finds a pointer to a good PIC18 site that might answer the questions people are having, they are very welcome to post it here and I’ll copy it into the main article.
— iay on January 16, 2006
my name is pankaj and i want to read image from scanner connected to usb port and reassemble that image can u please suggest me some material form the task
— pankaj on January 27, 2006
I am Hossain doing my ugrad in biomedical instrumentation. i have to design the embedded device which has usb output. so i m using pic18. i have to collect ECG and BODY FAT data and then after some calculations process it through the usb port. Please suggest me something as in how to start this(i use linux and want to use c++ to transfer data).
Thanks a lot
— Hossain on February 21, 2006
I am trying to test the sample code I downloaded from the microchip webpage to test the USb features on a PIC16C745.
this example emulates a mouse cursor on the screen when you plug the PIC to the coputer via USB connector.
The computer recognizes the PIC16C745 firmware and that, it is a HID device. But then, windows says there is a problem with the device, and in the device hardware manager from windows, the status for the device says: This device cannot start Code ‘10’. So I do not know what could be the problem. because windows recognizes the device.
I have asked the microchip support, but they do not know what could be the problem. Do you know what could be the problem??
— Alveru on April 3, 2006
Do not use UV pic chips anymore. Ford stop using Model-T, so follow in their footsteps.
— Alveru on May 20, 2006
does anyone know what is the maximum data transfer rate from chip input to PC via the USB port using the Microchip PIC16C745 or PIC16C765 ?
(NB i don’t mean the max’ data rate of the USB port).
— neo on October 24, 2006
Hi, I am using PIC18F4450 Chip for the first time. I am constantly getting error ‘Device detected but enumeration failed’. Can any one help me with this problem? Thanks !
— mhaque on January 14, 2007
what r the basic components that i need for connecting PIC18F4450 with Usb socket and how can i check whether data is transferred or not?
how much frequency of crystal dat should i use n values of different pull-up resistors?
Can i get a simple code for driving this microcontroller?
— Ankita on June 10, 2009
Hi, thanks for the tutorial. I am a newbie in programming and I might say that I don’t really like it(but since this is one of my project at work, i have to learn it anyway). My boss gave me task to finish up his project which is a device to drive or provide power for other device. And this device is controlled by computer, connected via usb. Right now, the firmware used is custom made and requires a special driver(which would cost thousands of dollars), therefore, my boss wants me to change the firmware to HID firmware. Any clue where should I start?what type of USB HID i should choose(as there are HID joystick,HID mouse, etc, for what i understand)? And i am using PIC18f4550. Thanks for the help!
— Yusnan Wijaya on September 24, 2009