everhack Stuff I've been messing with, or just thinking about.

6Oct/113

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)
 {
 }
}
Comments (3) Trackbacks (0)
  1. I would like to know more about how rfid chips frequncey can be intrrupted could you please e mail me if you know thankyou.

  2. Hello
    you inform me where I buy the carriage belt cricut expression , in miami?

    Thank


Leave a comment

No trackbacks yet.