User Tools

Site Tools


hidkey_gpio

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
hidkey_gpio [2012/11/25 23:03]
steve_m [Speed]
hidkey_gpio [2013/02/27 01:10] (current)
steve_m [Results]
Line 1: Line 1:
 ====== AVR Programmer built from a USB Keyboard ====== ====== AVR Programmer built from a USB Keyboard ======
  
-Recently, my old keyboard became louder and louder while typing, so I decided to buy a new one. But what to do with the old one? Ever since I saw the [[http://​www.pjrc.com/​hub_isp/​|AVR programmer that uses a USB hub]], I thought of abusing a USB keyboard for that.+Recently, my keyboard became louder and louder while typing, so I decided to buy a new one. But what to do with the old one? Ever since I saw the [[http://​www.pjrc.com/​hub_isp/​|AVR programmer that uses a USB hub]], I thought of abusing a USB keyboard for that.
  
 ===== Theory ===== ===== Theory =====
  
-Most keyboards have at least three indicator LEDs (Num-, Caps- and Scroll-Lock),​ which can be controlled from the host using a HID ''​Set_Report''​ request, and thus can be used as general purpose outputs. The inputs are a bit more tricky, since the keyboard uses a scan matrix divided in rows and columns. Most keyboards also do some debouncing and detect rows that are '​stuck',​ which means we need to simulate the keypress of a single key. If a key has been pressed, the keyboard triggers an interrupt transfer with 8 bytes of data, containing the current state of all keys. The first byte reflects the state of the modifier keys (shift, ctrl, alt, etc.)which I'll be using as inputs. Additionally,​ the keys can be polled using a ''​Get_Report''​ request to the control endpoint, but the interrupt transfers need to be handled either way, since my keyboard just locked up after the first keypress when I didn't handle them first.+Most keyboards have at least three indicator LEDs (Num-, Caps- and Scroll-Lock),​ which can be controlled from the host using a HID ''​Set_Report''​ request, and thus can be used as general purpose outputs. The inputs are a bit more tricky, since the keyboard uses a scan matrix divided in rows and columns. Most keyboards also do some debouncing and detect rows that are '​stuck',​ which means that we need to simulate the keypress of a single key. If a key has been pressed, the keyboard triggers an interrupt transfer with 8 bytes of data, containing the current state of all keys. The first byte reflects the state of the modifier keys (shift, ctrl, alt, etc.) which I'll be using as inputs. Additionally,​ the keys can be polled using a ''​Get_Report''​ request to the control endpoint, but the interrupt transfers need to be handled either way, since my keyboard just locked up after the first keypress when I didn't handle them first.
  
 ===== Hardware ===== ===== Hardware =====
Line 23: Line 23:
 {{ :​hidkey_breadboard.jpg?​800 |}} {{ :​hidkey_breadboard.jpg?​800 |}}
  
-You can see the keyboard controller PCB, the optocoupler, ​and an Atmel [[http://​www.atmel.com/​Images/​doc2543.pdf|ATtiny2313]] microcontroller.+You can see the keyboard controller PCB, the optocoupler,​ an Atmel [[http://​www.atmel.com/​Images/​doc2543.pdf|ATtiny2313]] microcontroller, and an LED for testing the simple blink program I flashed.
 I desoldered the LEDs and directly connected the 5V outputs (since there were already 330Ω current limiting resistors in place) as follows: I desoldered the LEDs and directly connected the 5V outputs (since there were already 330Ω current limiting resistors in place) as follows:
  
Line 30: Line 30:
 |Caps lock|MOSI|out| |Caps lock|MOSI|out|
 |Scroll lock|Reset|out| |Scroll lock|Reset|out|
-|row/column of right shift key|MISO|in|+|row/column of right shift key|MISO ​(through optocoupler)|in|
  
 For the optocoupler I added a 470Ω current limiting resistor. For the optocoupler I added a 470Ω current limiting resistor.
Line 36: Line 36:
 ===== Software ===== ===== Software =====
  
-First I wrote a small libusb-based test utility for experimenting with the keyboard. I'm directly communicating with the keyboard from userspace, unloading the kernel driver first.+First I wrote a [[https://​github.com/​steve-m/​hidkey_gpio|small libusb-based test utility]] for experimenting with the keyboard. I'm directly communicating with the keyboard from userspace, unloading the kernel driver first.
  
 ==== Speed ==== ==== Speed ====
  
-Just toggling the LEDs in a while-loop gives a signal fluctuating between 500 Hz and 1.2 kHz on the output, which is faster than I assumed. Unfortunately,​ the input-part is much worse, since the rows are only scanned at 250 Hz on my keyboard:+Just toggling the LEDs in a while-loop gives a signal fluctuating between 500 Hz and 1.2 kHz on the output, which is faster than I assumed. Unfortunately,​ the inputs are much slower, since the rows are only scanned at 250 Hz on my keyboard:
  
 {{ :​scan_pulse.png?​nolink |}} {{ :​scan_pulse.png?​nolink |}}
Line 59: Line 59:
 ==== Results ==== ==== Results ====
 <​code>​ <​code>​
-$ ./avrdude -c hidkey -C avrdude.conf -pattiny2313 ​-U flash:​w:​main.hex:​i -V+$ ./avrdude -c hidkey -C avrdude.conf -p attiny2313 ​-U flash:​w:​main.hex:​i -V
  
 avrdude: AVR device initialized and ready to accept instructions avrdude: AVR device initialized and ready to accept instructions
Line 79: Line 79:
 </​code>​ </​code>​
  
-Well, as you can see, programming takes quite a while, mainly because of the slow input speed I mentioned before, but is very reliable. Since I assume that many people have some old USB keyboard ​laying ​around collecting dust, it still could be used as a bootstrap flasher for solving the old chicken-and-egg problem when building a faster programmer ​like the [[http://​www.fischl.de/​usbasp/​|USBasp]],​ or as low-speed general purpose output for other applications. For example, many outputs could be driven using a simple serial-in, parallel-out shift register.+Well, as you can see, programming takes quite a while, mainly because of the slow input speed I mentioned before, but is very reliable. Since I assume that many people have some old USB keyboard ​lying around collecting dust, it still could be used as a bootstrap flasher for solving the old chicken-and-egg problem when building a faster programmer ​([[http://​www.fischl.de/​usbasp/​|USBasp]], ​[[http://​www.ladyada.net/​make/​usbtinyisp/​|USBtinyISP]]) ​or as low-speed general purpose output for other applications. For example, many outputs could be driven using a simple serial-in, parallel-out shift register
 + 
 +===== Update #1 ===== 
 + 
 +Since reading the MISO input is much slower than writing the outputs, as I mentioned above, I took a closer look at the avrdude code. As it turns out, the inputs are read every time, even if the data isn't used at all afterwards (like when writing a byte). I applied a crude hack, so that MISO is only being read if the data is used afterwards. I pushed that change to a new [[https://​github.com/​steve-m/​avrdude/​tree/​speedup|speedup branch]] on github. 
 + 
 +With those changes, flashing my 86 byte demo application is now over ten times faster (11.75s vs. 123.79s)! 
 +<​code>​ 
 +$ ./avrdude -c hidkey -C avrdude.conf -p attiny2313 -U flash:​w:​main.hex:​i 
 + 
 +avrdude: AVR device initialized and ready to accept instructions 
 + 
 +Reading | ##################################################​ | 100% 4.33s 
 + 
 +avrdude: Device signature = 0x1e910a 
 +avrdude: NOTE: "​flash"​ memory has been specified, an erase cycle will be performed 
 +         To disable this feature, specify the -D option. 
 +avrdude: erasing chip 
 +avrdude: reading input file "/​home/​steve/​dev/​hid_gpio/​avr_demo/​main.hex"​ 
 +avrdude: writing flash (86 bytes): 
 + 
 +Writing | ##################################################​ | 100% 11.75s 
 + 
 +avrdude: 86 bytes of flash written 
 +avrdude: verifying flash memory against /​home/​steve/​dev/​hid_gpio/​avr_demo/​main.hex:​ 
 +avrdude: load data flash data from input file /​home/​steve/​dev/​hid_gpio/​avr_demo/​main.hex:​ 
 +avrdude: input file /​home/​steve/​dev/​hid_gpio/​avr_demo/​main.hex contains 86 bytes 
 +avrdude: reading on-chip flash data: 
 + 
 +Reading | ##################################################​ | 100% 124.25s 
 + 
 +avrdude: verifying ... 
 +avrdude: 86 bytes of flash verified 
 + 
 +avrdude: safemode: Fuses OK 
 + 
 +avrdude done.  Thank you. 
 +</​code>​ 
 + 
 +Programming the whole flash of the ATiny2313 now only takes 4 minutes 37 seconds: 
 + 
 +<​code>​ 
 +$ ./avrdude -c hidkey -C avrdude.conf -p attiny2313 -U flash:​w:/​tmp/​usbtiny.hex:​i 
 +avrdude: AVR device initialized and ready to accept instructions 
 + 
 +Reading | ##################################################​ | 100% 4.33s 
 + 
 +avrdude: Device signature = 0x1e910a 
 +avrdude: NOTE: "​flash"​ memory has been specified, an erase cycle will be performed 
 +         To disable this feature, specify the -D option. 
 +avrdude: erasing chip 
 +avrdude: reading input file "/​tmp/​usbtiny.hex"​ 
 +avrdude: writing flash (2046 bytes): 
 + 
 +Writing | ##################################################​ | 100% 276.90s 
 + 
 +avrdude: 2046 bytes of flash written 
 +avrdude: verifying flash memory against /​tmp/​usbtiny.hex:​ 
 +avrdude: load data flash data from input file /​tmp/​usbtiny.hex:​ 
 +avrdude: input file /​tmp/​usbtiny.hex contains 2046 bytes 
 +avrdude: reading on-chip flash data: 
 + 
 +Reading | ########## ​                                        | 20% 593.63s^C 
 +</​code>​ 
 + 
 +I'd say that's quite an improvement,​ and very well acceptable for a chicken-and-egg bootstrap flasher :-) 
 + 
 +This project was featured on [[http://​hackaday.com/​2012/​11/​26/​usb-keyboard-becomes-an-avr-programmer/​|Hackaday]].
  
 == Reference Literature == == Reference Literature ==
hidkey_gpio.1353880988.txt.gz · Last modified: 2012/11/25 23:03 by steve_m