Rfid Spin
Rfid Spin
THRESHOLD
R2 L1 R4 C3 D1 R3 C4 R1 C2 C1 CARRIER-
C1,C3 C2 C4 R1 R2,R4 R3 D1 L1
1000 nF 2200 nF 1500 pF 1 M 100 k 1.8 M Some garden variety sigal diode from my junk drawer. About 30 turns of magnet wire on a 5.5x7 inch wooden block. (Tune for 125 kHz resonance with C1.)
Micah Dowty <[email protected]> --XXX: This is really messy. It doesn't do automatic threshold control, nor does it report back useful information like the length of the card's packet, or the presense/absence of a card. You may have to fidget with the value of init_frqb to adjust the threshold bias manually. Watch the debug2 output with an oscilloscope. It should be normally high, with series of quick pulses on every FSK attenuation cycle. Tested with HID proximity cards. Seems to be a 16-bit all-ones header, followed by 16*32=512 bits of data. } CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 CARRIER_HZ = 125_000 CARRIER_NEG_PIN THRESHOLD_PIN INPUT_PIN CARRIER_POS_PIN DEBUG_PIN DEBUG2_PIN OBJ text : "TV_Text" = = = = = = 7 6 5 1 0 2 ' ' ' ' ' Carrier wave pin, to capacitor PWM output for detection threshold Input signal Carrier wave pin, to coil For the 'scope
VAR long debug long buffer[128] long capture1[16] long capture2[16] PUB main | i text.start(12) text.str(string("Minimalist RFID reader", 13, "Micah Dowty <[email protected]>", 1 3)) start repeat longmove(@capture1, @buffer, 16) waitcnt(clkfreq/4 + cnt) longmove(@capture2, @buffer, 16) ' Only display if we get two identical samples, to cut out noise. if isMatch and capture2[0] display buffer[0]~ waitcnt(clkfreq/2 + cnt) PRI isMatch : r | i repeat i from 0 to 15 if capture1[i] <> capture2[i] r := FALSE return r := TRUE PRI display | i text.out(13) repeat i from 0 to 15 text.hex(capture1[i], 8) text.out(" ") text.out(13) PUB start init_frqa := fraction(CARRIER_HZ, clkfreq) debounce := clkfreq / (CARRIER_HZ / 4) bit_threshold := clkfreq / (CARRIER_HZ / 9) cognew(@entry, @debug) PRI fraction(a, b) : f a <<= 1 repeat 32 f <<= 1 if a => b a -= b f++ a <<= 1 DAT org entry mov mov dira, init_dira ctra, init_ctra ' CTRA generates the car
rier wave threshold bias mov packet_loop word_loop gaps. bit_loop or :edge_wait edge... or waitpne mov andn mov sub cmp jmp andn outa, #4 ' XXX: Debug2 high input_mask, input_mask this_edge, cnt outa, #4 ' XXX: Debug2 low r0, this_edge r0, prev_edge r0, debounce wc #:edge_wait outa, #1 ' How long was that? ' Too short. Look for an ' XXX: Debug low outa, #1 ' XXX: Debug high mov prev_edge, this_edge waitpeq input_mask, input_mask ' Wait for another pulse mov mov mov frqb, init_frqb buf_offset, #0 num_ones, #0 bit_count, #32 mov mov frqa, init_frqa ctrb, init_ctrb ' CTRB generates a pulse
other edge.
if_c
D our ' bit threshold, to recover bits. mov sub cmp add mov rcl r0, this_edge r0, first_edge r0, bit_threshold wc num_ones, #1 num_ones, #0 shift_reg, #1 ' tag is generating. Compare the signal's period against
' Now the difference between first_edge and this_edge ' is the period of the FSK modulated signal that the RFI
if_c if_nc
nning of the packet. if_z cmp jmp mov djnz num_ones, #16 wz #packet_loop first_edge, this_edge bit_count, #bit_loop ' Start a new bit
' If we finished a word, write it to hub memory. add and mov add buf_offset, #4 buf_offset, #$7F r0, par r0, buf_offset
init_dira long (|< CARRIER_POS_PIN) | (|< CARRIER_NEG_PIN) | (|< THRESH OLD_PIN) | (|< DEBUG_PIN) | (|< DEBUG2_PIN) init_frqa long 0 init_ctra long (%00101 << 26) | (CARRIER_POS_PIN << 9) | CARRIER_NEG_PI N init_ctrb long (%00110 << 26) | THRESHOLD_PIN input_mask long |< INPUT_PIN init_frqb adj_gain ain debounce bit_threshold first_edge prev_edge this_edge buf_offset bit_count num_ones shift_reg r0 long long long long long long long long long long long res $7E000000 $0 0 0 0 0 0 0 0 0 0 1 fit ' Default threshold ' Automatic threshold adjustment g