After a few weekends of work, Ive finally finished usbremote, the replacement to my old avrremote project. The avremote project was a quick weekend project I did when I got sick of getting up and walking across the room to increase or decrease the volume or pause/resume Netflix (on my desktop computer). Although it did the trick, there were several "incorrect" things about it:
- inefficient use of clock cycles in the microcontroller
- improper decoding of the infrared NEC signal
- using the expensive FTDI chip to enable communication over USB
I knew that eventually I would end up redoing the remote project, and do it right. So, here we are. USBRemote is finished with all three points above fixed.
I'll spend the next few paragraphs going over the details of addressing the issues outlined above, as well as a bit of detail on the USB implementatin and writing the host software.
Using AVR Timer's to properly utilize the MCU capabilities
In avremote, we constantly polled the infrared receiver pin to manually check for a rising or falling edge, indicating the start or end of a phase cycle. This works, but you end up spending a lot of clock cycles doing very few things. The proper way to do this is to use the built in timer, which also has a built in Input Capture.
Put basically, you configure the timer to clock at some predefined interval (typically some divisor of your main clock), set the input capture edge selector to rising or falling, and enable the input capture interrupt. When a rising or falling edge is detected, the input capture interrupt is called. In your service routine, you can copy the timer value, or the number of clock ticks since the last edge. This way you know the amount of time between each falling and rising edge, and can easily decode the signal once you have finished.
Properly decoding NEC transmissions
In avrremote, I simply shifted in each bit that came in after the start pulse, without properly decoding the address and command invidually. On top of this, for both address and command, a logical inverse is provided, acting as a kind of checksum to ensure there were no errors during transmission. In usbremote, the decoding is done properly and the inverse bytes are properly compared to ensure integrity.
Ditch that FTDI chip
FTDI chips are pretty great. They make it super easy to enable communication with another device over USB. One major down side to them, though, is that they are relatively expensive. In fact, the FTDI chip makes up roughly 60% of the overall parts cost of avremote. There are also more features to take advantage of when working with native USB.
This is where V-USB comes in. V-USB is a software implementation of USB 1.1 for AVR devices. Note that some AVR devices have hardware support for USB -- V-USB is specifically designed for those that do not. The components required are minimal, adding it to any AVR project is easy. I'll add a schematic to this page once I finish it.
Host software with libusb
If you've ever written kernel mode code, i.e. wrote a driver for linux or Windows, you know it can be a big pain. For USB projects, there is libusb. libusb enables you to write code in user space to manipulate and communicate with USB devices. If you take a look at the host code for usbremote, you can see that it's very easy to open the device and immediately start transferring data. When applicable and available, it's much more convenient to use libusb than it is to startin causing BSOD's writing kernel drivers.
USBRemote is open source, software and hardware. Copy it, modify it, redistribute it, spread it, or keep it for yourself. Do as you please. If you're interested in making it even better, I am always gladly accepting contributors. Lastly, if you get some time, check out the source. It's heavily commented, making it very easy to understand how it works.