![]() |
|
|
|
|
|
We wrote the firmware code for our PIC chip in assembly with Microchip's development tools. Following are highlights of some major revisions that we made as we developed our reader. We designed the USB reader as a keyboard in a manner similar to many computer bar code readers with the intended application of a web form. You can also download a zip file containing each of the code versions. Revision 0.1First, we used the pulse width modulation feature on the microprocessor to output the 125kHz signal for our coil. This completed our circuit, and allowed us to recieve input to the microprocessor. Next, we knew the we had to get a device that enumerated as a keyboard and sent data to the computer. Microchip published an example of a PS2 to USB keyboard converter based on the first version of their reference USB firmware, which we used as a starting point. To process the data, we distinguished between zero and one bits by starting a timer on each pulse rise that sent an interrupt after one period of a 13.9 kHz signal (7.2e-5 seconds), or half way between the frequency for a zero (15.625 kHz) and a one (12.5 kHz). When the timer sent an interrupt, it set the next bit in a cache of four bits. The bit would remain clear if a zero were sent, because the timer would not get to its maximum value and it would not interrupt before it was reset. After caching four bits, the value of the cache was looked up on a table of keycodes for hexadecimal numbers (0-9 and a-f), and this keycode was sent to the computer over USB. This solution did give us a raw bitstream of the data emitted by the cards, but it dropped the large majority of bits and did not send any sequentail bits. It took 2.56e-4 seconds to send four zeros and 3.2e-4 seconds to send four ones from the card to the reader, but the reader was only able to send four bits every 10 milliseconds over USB. Thus, on average, only one in every thrity-five bits was sent to the computer. Revision 0.2Knowing that going forward the code would only get more complex, we decided to switch to Microchip's 2.0 reference design for USB firmware. We used a combination of the first version and the new code to get the device working as before, but based on the new foundation. Next, we decided to fill the 80 bytes of memory in Bank 1--currently unused by our program--with cached data before sending it over USB. That way, we could get a stream of sequential bits and begin to figure out the format. Since it was easier to read back a byte of information from our cache at a time and since we were only sending four bytes per character, we send two charcters at a time by placing them both in the buffer for sending data. This buffer can hold up to six keycodes. In this version, instead of using interrupts for the threshold timer, we switched to simply checking if the interrupt flag was set the next time a rise was detected. After getting this code to work, we found that the computer interpretted zeros or ones in sequence as holding down a key, so it suppressed repetition. Thus, we still were losing a large number of bits, and the data was unusable. Revision 0.3To solve the "holding the key down" problem, we made the code alternate between sending two characters (one byte) and nothing every loop. We also had the code send "gg" at the end of each sequence of bits so that we could tell which bits were in a continuous stream. While this version of the firmware gave us sequences of useful data, by using a signal generator to source signals ranging from 12.5 kHz to 15.625 kHz, we noticed that the cutoff threshold was quite imprecise. At frequencies faster than 13.9 kHz, the reader should only send zeros, and at frequencies slower than 13.9 kHz, the reader should only send ones. However, at frequencies even a little faster than 12.5 kHz or slower than 15.625 kHz, the reader sent noisy data with incorrect bits. Thus, we were not confident that all of the data that we received was accurrate, since the device had little tolerance for error. Revision 0.4In order to get more accurrate timing, we made a rise generate an interrupt rather than detecting when the flag for a rise was set in the main loop. This increased the tolerance of the system a great deal, and the firmware could correctly interpret pulse widths as ones or zeros as close as 0.2 kHz away from our threshold of 13.9 kHz with high reliability. This version of the firware was the first one that gave us any useful data. By acquiring a lot of data from five cards, we were able to identify that the cards all outputted repeating sequences of 540 bits. We also noticed that they used a preamble of 15 ones, that they used a postamble of 19 zeroes, and that the data contained long groups of ones or zeros. Revision 0.5Having figured out that the preamble of 15 ones could be used to detect the beginning of a card number and that the code had large groups of ones and zeros, we modified the firmware to recongnize a card number's beginning and store the number of repeated bits in a buffer instead of the raw bits. When the firmware encountered a group of zeros with 19 zeros, it signaled the end of a sequence. If a group of zeros was larger than 19 zeros, it subtracted 19, buffered the result, and signaled the sequence end. We checked to make sure that a read was valid by ensuring that the next sequence received identically matched the stored sequence. If it matched, the buffered group lengths were sent to via USB as keystrokes. Otherwise, the firmware cleared the last stored number and started buffering data again. No groups other than the preamble or postamble were larger than 16, so we used hexadecimal digits to represent the number of repetitions in each group. From this data we figured out that we could decode the data by alternating between 0 and 1 for each group and inserting a 1 or 0 for groups of 5, 6, or 7 and a 11 or 00 for groups of 10, 11, 12, or 13. This would give us the Manchester encoded data, and we could finish decoding by ignoring every other bit. The result of this decoding would be a 45 bit number, the last bit being a parity bit checksum. Revision 0.6This was the final revision of our firmware. Instead of sending all of the data, it handled all of the decoding in the firmware and only sent the 44 bits of actual data. Every four bits were converted to their hexadecimal equivalent before sending over USB as keystrokes. Instead of sending two keystrokes at a time (which also caused the "holding down the key" problem that we saw before) we updated the code to send one keystroke at a time and nothing every other loop. The final firmware acts as a USB keyboard and sends 11 hexadecimal characters that represent the 44 bits of data stored on the prox cards followed by a carriage return character. It does not send anything when there is a collision problem, such as when two cards are placed near the device, or it only reads one of the cards. The firmware notices when no card is near it, and only will send a card number once every time that a card is placed near it. When the card is removed from read range, the device resets and allows reads again. The final firmware also sends output to drive a buzzer sound and make the LED brighten after a successful card read. |
|