RFID Reader, part 4, detecting bits! (well, 1′s at least)
After wrestling and backing up a bit and rewriting a good part of it, I finally got the analog comparator and input capture scheme working.
Timer1 counts continuously while the antenna signal is being generated.
The analog comparator is configured to trigger the Timer 1 Input Capture interrupt whenever the signal detector voltage crosses an analog threshold voltage.
Whenever there is a rising edge (input signal rises above threshold), I check to see if timer1 has exceeded a certain value or not. If there's been no rising edge within a certain length of time, we either have a "1" bit, OR we have no card at all.
"No card" is handled by only allowing a minimum AND maximum "low time" (I.e. 1's can only be SO long).
The picture below shows the modulated antenna signal in blue, and the detected 1-bits in yellow. Now I'm finally able to get started on actually storing 0's and 1's.
Since the input capture interrupt is called twice on every cycle, we need to know if it has been longer than about 5 or 6 complete cycles since the last FALLING edge.
Looking at the Microchip spec now, I realize I didn't QUITE implement it properly.
According to this picture, I should actually be timing the duration of consecutive cycles above AND below the threshold. I was only timing the length of the LOW portion. I'm not certain whether it really matters or not, time will tell.
Anyhow, this should be "good enough" for now, the next thing I'll work on is actually storing the consecutive bits and looking for a header of some kind to determine the beginning of the string. I also planned to implement some error correction by requiring several consecutive matching reads before deciding that we've actually detected the signal correctly and completely.
RFID Reader, part 3
After a 6-week hiatus, I finally picked the RFID reader project back up. My ultimate goals have evolved a long way, but I'll reveal those later.
For now, I'm still working on the part where I need to detect the incoming signal.
Using the Teensy 2.0:
-I'm using timer4 in phase & frequency correct mode, clk/1 prescaler, with a 128 cycle period. Using the dead-band generator at 50% duty cycle, I'm getting a differential signal output to pins OC4A and ~OC4A, and am using this to drive my antenna.
-Like everyone else before me, I pass the antenna signal through a signal diode, high-pass-filter and decoupling capacitor.
The last thing I did before I stopped working on this previously, was to connect the signal to the ADC and sample as fast as possible, and light the LED if the voltage was above a hardcoded threshold value (about 0.5v I think).
Although this does successfully "work", and starts to light up when a card is within about 3" of the reader, it also has lots of false positives and lights up when you just mess with the antenna in any way.
I constantly go back to Beth Scott's "simplest RFID reader?" forum post, as well as the Microchip 125khz RFID system design guide and AVR 32U4 datasheet for ideas and inspiration.
My latest new attempt is using an analog threshold voltage, the analog comparator, and the timer1 input capture interrupt & edge detector. The idea is, timer1 constantly counts from 0 to 0xffff with prescaler set to CLK/64 (250khz). The TOP value could be adjusted to match the bit length of the RFID protocol to be read (*2 since we're running at double the frequency).
Reading the datasheet, I decided to try connecting AIN+ to the threshold voltage, and AIN- to the antenna signal, and enable the Timer1 Input capture feature. I set the edge detector to trigger the input capture interrupt on a Falling edge, which I figured would result when the AIN- voltage drops below the AIN+ voltage.
The input capture interrupt starts with the current value of Timer1 in the 16-bit input capture register. I figure all I need to do is store the value of the timer each time the interrupt fires. A string of 1's or other "lead-in" for an actual card value will help me determine the "beginning" or "0 offset" value of timer1.
For now, I just am trying to still flash the light whenever the interrupt fires, but my first attempt at 1am didn't result in any visible result. As is always the case, I'm sure I've just missed some essential register setting and will need to review all the init code against the datasheet again, as well as trying to get my bus pirate logic analyzer mode working again so I can get a better debug view at the pin level.
Just for grins here's my code at the moment.
#include <avr/interrupt.h>
#include <avr/io.h>
volatile uint16_t pdval;
#define CARRIERPOS_PIN 10
#define CARRIERPOS_REG PORTC6
#define CARRIERNEG_PIN 9
#define CARRIERPOS_REG PORTC7
#define LED_PIN 11
#define LED_PORT PORTD
#define LED_REG PORTD6
#define THRESHOLD_INPUT_PIN 24
#define THRESHOLD_INPUT_REG AIN0 // aka PE6
#define THRESHOLD_INPUT_PORT PORTE
#define ANTENNA_INPUT_PIN 20
#define ANTENNA_INPUT_REG PF1 // goes to AIN- via ADMUX
#define ANTENNA_INPUT_PORT PORTF
#define LED_ON() (LED_PORT |= _BV(LED_REG))
#define LED_OFF() (LED_PORT &= ~_BV(LED_REG))
// Inline assembly: The nop = do nothing for one clock cycle.
#define nop() __asm__ __volatile__("nop")
/**
Timer4 is used in Phase/Frequency correct mode to generate a 125khz differential output
signal used to stimulate the reader antenna.
*/
void initTimer4()
{
// pwm with dead time generator
TCCR4A = _BV(PWM4A) | _BV(COM4A0);
// no prescaler (CK/1)
TCCR4B = _BV(CS40);
// phase & frequency correct pwm
TCCR4D = _BV(WGM40);
TCCR4E = _BV(ENHC4);
//duty cycle for oscillator toggle
OCR4A = 64;
// 125k would be no prescaler, period = 128
OCR4C = 64;
}
/**
we'll try to use the input capture feature of Timer1 to determine -when- each 1 occurred.
We'll be listening for 1's, and as soon as we recognize a start sequence, we'll reset Timer1 to 0.
It will increment at 125khz along with Timer4 which is generating the differential antenna output signal.
Each time the ADC interrupt fires to indicate the antenna signal on AIN- exceeding the threshold voltage
on AIN+, we will trigger the input capture and take note of the value of Timer1. This will give us our
the cycle number in which it occurred relative to the start sequence. This would be a Falling Output Edge (I think)
since AIN- is exceeding AIN+ when the input signal rises above the threshold value.
*/
void initTimer1()
{
// CTC mode 4; TOP = OCR1A, enable input capture noise canceler, 4 cycle delay
// input capture set to falling edge select (0), CLK/1 prescaler
TCCR1B = (1<<ICNC1) | (1<<WGM12) | (1<<CS10);
// 65535 cycles to overflow at CLK/1 prescaler, maximum possible bit offset
OCR1A = 0xFFFF;
// enable input capture interrupt on analog comparator
TIMSK1 |= (1<<ICIE1);
// clear the input capture flag after enabling interrupts to avoid a false interrupt call
TIFR1 |= (1<<ICF1);
}
void initAnalogComparator()
{
// turn off ADEN bit to disable ADC
ADCSRA &= (0<<ADEN);
// connect ADC MUX to comparator AIN-
ADCSRB |= (1<<ACME);
// enable input capture function of Timer1. comparatur
ACSR = (1<ACIC);
// note: ICIE1 must be set to 1 in TIMSK1 to enable Timer1 Input Capture Interrupt
}
// each time the input capture interrupt is triggered, a falling edge was detected
// by the analog comparator. store the value in
ISR(TIMER1_CAPT_vect)
{
// TODO: read ICR1L first, then ICR1H. to actually read the byte
// for now we'll just turn the LED on for 8 cycles and then turn it back off.
LED_ON();
nop();
nop();
nop();
nop();
nop();
nop();
nop();
nop();
LED_OFF();
}
void setup()
{
cli();
// 125khz carrier oscillator pins 8&9, OC4A/~OC4A
pinMode(CARRIERPOS_PIN, OUTPUT);
pinMode(CARRIERNEG_PIN, OUTPUT);
pinMode(ANTENNA_INPUT_PIN, INPUT);
pinMode(THRESHOLD_INPUT_PIN, INPUT);
// led
pinMode(LED_PIN, OUTPUT);
// timer4 generates the 125k differential carrier signal
initTimer4();
// timer1 counts to 65536 over and over again to timestamp the falling edges
// it might be reset to 0 when we recognize a data header (series of 1s)...
initTimer1();
// input capture interrupt on Timer1 is triggered each time
// the antenna signal exceeds the threshold value, giving a falling edge on the
// comparator. for now, the LED is flashed every time the interrupt is triggered.
initAnalogComparator();
// enable global interrupts()
sei();
}
void loop()
{
while(1)
{
}
}
RFID reader, part 2
After a few more days of hacking on this I'm a lot closer than I was.
At first, my avr-rfid antenna was oscillating strongly enough for the processor to run and start trying to send the code; but I couldn't see any induced signal in the reader (transmitter)'s antenna.
Finally I decided to pay attention to the schematic note "tune for 125khz resonance with C1" (http://scanlime.org/2008/08/simplest-rfid-reader/) and start playing with the reader coil windings. Previously I had been trying to tune the capacitor to the coil instead of fixing the capacitor at the spec (1nf) and tuning the coil to resonate properly.
I realized in the process I had only about 19 turns of wire in my coil instead of 30+ like are called for, and just not enough inductance. I ended up adding about 10 or 11 extra turns to around 30 like I should have done to start with, sanding off a little of the insulation every couple turns to recheck the oscillation.
I also dispensed with the single-layer wrapping of the coil wires, and instead cut "V" grooves about 1/4" down from the corners of the wood block. Now the wire is more of just a tight bundle instead of thin and wide like a ribbon.
Anyhow, after retuning my reader coil to the maximum voltage at 125khz with the 1nf capacitor, I hooked it all back up to the Teensy and VOILA I now see a pretty good variation in the reader coil when the card is near, meaning BITS!. Not only that, but i also see the same types of variation when I try my Hackerspace badge and my work badge, so I'm definitely getting closer!
I have not yet started implementing the detector code, which I'll have to port from Scanlime's original propeller assembly.. Looking at the 'scope signal I admit I still can't quite tell a 1 from a 0 though, only that there's SOME kind of deliberate modulation going on
In the photo attached, the upper (yellow) signal is the oscillation in the AVR-RFID tag. It looks to me like the first few and last few pulses are 1 cycle shorter than the ones in the middle.
The lower (blue) trace is the oscillation in the reader coil. When there's no tag near, the peaks go away and the signal is a nice flat 125khz sine wave. Once the tag gets close enough to run and start pulsing (1 inch or so), the wave pattern appears superimposed on it.
It looks to me like the valleys go just a little lower each time the tag pulse is wider....
The Teensy is working a little harder now, generating:
- 125khz differential 5v signal to oscillate the reader antenna
- pwm signal at 1000hz through a matched RC low pass filter to give a smooth but variable analog threshold voltage. This voltage is automatically tuned (in scanlime's implementation), along with the actual reader frequency for peak performance.
-still TODO: pulse counting on the detector circuit signal to start trying to detect some actual bits.
AVR RFID reader part 1
I've been taking a break from Cricut coding to do some more work on the RFID stuff.
I decided that before I try to fix my (not working) AVR-RFID card, I should probably have my own reader. And why buy a reader when I really want to understand how it all works?
I'm following the spirit of the instructions posted at this forum by Scanlime (http://forums.parallax.com/showthread.php?105889-World-s-simplest-RFID-reader). I have two (real & working) sample cards of the right type to use as guinea pigs.
Instead of a propeller, I'm using a Teensy 2.0 AVR32U4 in "phase & frequency correct" pwm mode, using the dead time generator to create a 125khz differential signal between pins 11 & 12. Since 11 also happens to be the Teensy's LED pin, it also ends up pulsing brightly at 125khz.
The Teensy is a really great little device that I found on the hack shelf at the ATX Hackerspace, it's very compact with built-in high speed usb2, based on the ATMEGA32U4. (datasheet )
I have not yet implemented the detector circuit (that's next).
Following scanlime's directions, I wound 30 or so turns of #26 magnet wire around a spray painted wooden block" (the green wire from the Radio Shack magnet wire assortment); then a 1nf capacitor in series to the AVR's output pins, running the program below, and finally the 'scope probe up to the L/C junction to see what was up.
Good news, it was oscillating at 125khz, but the wave was not smooth, more rounded with some dips in the curve.
(no screenshot of the funky waveform, sorry)
I swapped out the capacitor a few times on my breadboard and eventually settled on 3.2nf giving the most "wavelike" curve I could manage (as seen above). 21.8v peak to peak Im pretty sure not 218.. The shape of the waveform looks to me like I may need just a little more capacitance to be quite right, but im hopeful that it wont really matter anyway.
I'll get an inductance meter reading on the reader antenna next Monday night just for curiosity sake.
(sorry no photo of the antenna yet)
Here is my current arduino code for the 125khz differential oscillator. There's not much there but those register settings are so crucial to getting it all working! I really need to learn how to do in-circuit debugging.
#include <avr/interrupt.h>
#include <avr/io.h>
void setup()
{
cli();
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
// phase & frequency correct pwm mode 9
// PWM4A enables PWM mode based on comparator OCR4A
TCCR4C = _BV(PWM4D) | _BV(COM4D0);
// no prescaler
TCCR4B = _BV(CS40);
// enable dead time
TCCR4D = _BV(WGM40);
// 1024 prescaler
//TCCR1B = _BV(WGM13) | _BV(CS12) | _BV(CS10);
// 125k would be no prescaler, period = 128
OCR4C = 128;
OCR4D = 64;
}
void loop()
{
while(1)
{
delay(10);
}
}
sei();
}
Freecut 0.2 progress
I finally got a few more hours to spend on getting Freecut 0.2 running on the Cricut Create this weekend, and finally got the motors and cutter solenoid up and running. The only remaining things I haven't tried are the dials and flash (I don't have any need for them yet).
I've delayed checking in my changes because I haven't got a Personal model hacked yet to make sure everything still works on it. I'm expecting another one in the mail this week so I'm hoping I'll be able to get to this in the next week or two.
In the meantime, I'm also pressing forward with working to implement HPGL and/or DMPL cutting protocol in place of the existing made-up one that Freecut 0.1 uses. Unfortunately my C-string-programming skills are pretty rusty so it might be a little challenging.
avr rfids, take 1.5….
I spent a few hours reading about 125k antenna formulas and designs to try and better understand the relationship between desired frequency, loops of wire, wire gauge, and the value of the tuning capacitor.
Microchip AN678 RFID Coil Design
I worked through some of the formulas in this datasheet, plugging in 100 turns, 66mm, 30 gauge to see what it would come up with for inductance, ideal # of turns, and capacitor value, to see if they would match the 1nf & 100 turn values specified in scanlime's blog entry. I wrote a simple java program to calculate the values for me after not finding what I thought I was looking for on various online antenna calculators (they seemed to be all too complicated).
I found this interesting note along the way which I had not seen elsewhere: "... For copper wire, the loss is approximated by the DC resistance of the coil, if the wire radius is greater than cm. At 125 kHz, the critical radius is 0.019 cm. This is equivalent to #26 gauge wire. Therefore, for minimal loss, wire gauge numbers of greater than #26 should be avoided if coil Q is to be maximized....".
So, #26 gauge wire next time!
Unfortunately my program isn't putting out believeable numbers yet, so I have more work to do.
In the meantime, I also discovered this other datasheet for a neat little 0.32 cent RFID chip (the Philips Hi Tag-S) that has a good description of the details of the encoding methods used starting in Section 7.3 (including our manchester, for future reference)
And here's another good discussion of the antenna design and coupling (different frequencies, same concepts and formulas).
Design Examples for
13.56MHz and 900 MHz RFID Antenna
I played with the open source 4NEC2 Antenna Modeler & Analyzer for a while trying the helical generator, but it kept blowing up at simulation time with my RFID design, complaining that the antenna was connected to ground at the end (duh, this is what the tutorial shows, I don't get it!).
AVR HID RFID, take 1…
I've been slowly making progress building my own AVR RFID according to the instructions in this blog: http://scanlime.org/2011/05/duct-tape-rfid-tag-1/
After building the assembly code for HID tag type, I obtained a ATTiny85 and a handful of ATMega168s. I wanted to prototype first with the Tiny85s, but I have a cheap and plentiful source for the 168s and wanted to use those if possible: http://store.atxhackerspace.org/
Building the code for the ATMega168 turned out to be challenging, as I kept getting the same compiler error over and over and just couldn't fix it with any of the most common suggestions I found by googling:
C:AppDataLocalTemp/cc69IjcD.o: In function `loop': (.text+0x1d12): relocation truncated to fit: R_AVR_13_PCREL against `no symbol'
This comment gave me the clue:
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=764390
"... IOW, you are trying to RJMP to a location that
cannot be reached that way. .."
Researching rjmp vs jmp I found this thread..
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=21053&start=0
I changed the "rjmp loop" to "jmp loop" and it compiles now. Whether it works or not, we'll see
Back to the Tiny85, I got one and soldered it to a $2 Surfboard from Frys. This was my first experience hand soldering SMD components and it was pretty challenging but I managed to do a pretty good job. This was a little crazier by the fact that I had purchased 0203-sized (grain of sand) sized parts without thinking it through.
In the end, I was able to successfully solder the 2 caps in place on the surfboard. (Circled in red)
To make the antenna, I laboriously made a 66mm form out of cardboard, started winding it, and noticed a nearby beer can. Just for fun, I measured the beer can and it turned out to be... 66 mm! What are the odds?
I wound approximately 100 turns of 30 gauge magnet wire (or maybe 98... or 102...
, slipped it off the can, and stuck it to a clear packing tape backing. I soldered a 1x4 male 0.1 header strip flat against the contacts to connect the bus pirate probes up to for (very slow) programming purposes.
Ultimately, unfortunately my first test was a failure. Swiping the "badge" by the hackerspace and my office readers does not result in a beep. I'm certain the hackerspace badge is the right type. After looking closer, I realized I had attached the capacitor in series with the antenna rather than in parallel.
After fixing the error this morning (with a parts-bin capacitor roughly 100 times larger than the original
, the badge still does not garner a beep from the card reader.
I have to say, I'm pretty pleased with myself for just getting this far, it does look pretty neat even when it doesn't work.
Next steps: probe the antenna leads with the oscilloscope while trying to read the badge to check for resonance; also go back to the formula and try to recalculate the antenna length. Perhaps using a heavier-gauge wire or a slightly incorrect number of turns of wire resulted in a change in the resonant frequency? (I don't really know what I'm doing here yet, just learning as I go
I'll also probably also attempt to build my own reader at some point using these instructions here by the same author: http://forums.parallax.com/showthread.php?105889-World-s-simplest-RFID-reader
Custom Catan Tiles
Just a little something I was playing with.. Email me (gossiphog@gmail.com) if you want the template.
Last Broken Cricut, Fixed!
Woo woo, I'm now 6 for 6 on repairing the "broken" Cricuts I got off eBay. (ok, Danny M. gets 95% of the credit for the one with the busted middle-layer board traces)
The last holdout was a Personal model, which would beep three times when powered up. Nothing from the LCD, all the keyboard lights would come on.
I started by plugging a known-good power supply into it, just in case, but it didn't make any difference.
Next, I removed the bottom cover where the motherboard lives, and immediately spotted the culprit. The LCD header was unplugged.
After plugging it back in and powering it back up, angels sang, it started right up and gave me the "Cricut 1.0 OK"!
Incidentally, I had been wondering if the earliest firmware versions had perhaps not been read-only, so I plugged in my handy programmer card and attempted to download the firmware.
At first I thought I had hit paydirt, the file was NOT all 0s like the others, but alas, I realized the bytes were all sequential numbers in an interesting pattern (high-byte increasing across, low byte increasing downwards).
This machine looks pretty much unused and gleaming. I wonder if it was bad right from the factory? How else could a header just come unplugged like that?













