This commit is contained in:
iceman1001 2020-01-12 00:19:12 +01:00
commit 5b7882fc4f

View file

@ -1,11 +1,17 @@
/*
This code demodulates and modulates signal as described in ISO/IEC 18092.
That includes packets used for Felica, NFC Tag 3, etc. (which do overlap)
simple envelope following algorithm is used (modification of fail0verflow LF one)
is used to combat some nasty aliasing effect with testing phone (envelope looked like sine wave)
//this code demodulates and modulates signal as described in ISO/IEC 18092. That includes packets used for Felica, NFC Tag 3, etc. (which do overlap) Speeds supported: only 212 kbps (fc/64) for now. Todo: 414 kbps
//simple envelope following algorithm is used (modification of fail0verflow LF one) is used to combat some nasty aliasing effect with testing phone (envelope looked like sine wave) though for reader, the selection has to come from ARM. modulation waits for market sprocket -doesn't really mean anything
// only 212 kbps (fc/64) for now 414 is relatively straightforward... though for reader, the selection has to come from ARM
// modulation waits for
//market sprocket -doesn't really mean anything ;)
//redefining mod_type: bits 210: bit 2 - reader drive/power on/off, bit 1 - speed bit, 0:212, 1 -424 bit 0: listen or modulate
mod_type: bits 210:
bit 2 : reader drive/power on/off
bit 1 : speed bit, 0 : 212, 1 :424
bit 0 : listen or modulate
*/
module hi_flite( module hi_flite(
pck0, ck_1356meg, ck_1356megb, pck0, ck_1356meg, ck_1356megb,
@ -14,7 +20,7 @@ module hi_flite(
ssp_frame, ssp_din, ssp_dout, ssp_clk, ssp_frame, ssp_din, ssp_dout, ssp_clk,
cross_hi, cross_lo, cross_hi, cross_lo,
dbg, dbg,
mod_type // used mod_type
); );
input pck0, ck_1356meg, ck_1356megb; input pck0, ck_1356meg, ck_1356megb;
@ -25,79 +31,69 @@ module hi_flite(
output ssp_frame, ssp_din, ssp_clk; output ssp_frame, ssp_din, ssp_clk;
input cross_hi, cross_lo; input cross_hi, cross_lo;
output dbg; output dbg;
input [2:0] mod_type; // used. input [2:0] mod_type;
assign dbg=0; assign dbg=0;
wire power= mod_type[2]; wire power = mod_type[2];
wire speed= mod_type[1]; wire speed = mod_type[1];
wire disabl= mod_type[0]; wire disabl = mod_type[0];
// Most off, oe4 for modulation; // Most off, oe4 for modulation;
// Trying reader emulation (would presumably just require switching power on, but I am not sure) // Trying reader emulation (would presumably just require switching power on, but I am not sure)
//;// 1'b0;
assign pwr_lo = 1'b0; assign pwr_lo = 1'b0;
// 512x64/fc -wait before ts0, 32768 ticks
// tslot: 256*64/fc
//512x64/fc -wait before ts0, 32768 ticks
//tslot: 256*64/fc
assign adc_clk = ck_1356meg; assign adc_clk = ck_1356meg;
///heuristic values for initial thresholds. seem to work OK ///heuristic values for initial thresholds. seem to work OK
`define imin 70//(13'd256) `define imin 70 // (13'd256)
`define imax 180//(-13'd256) `define imax 180 // (-13'd256)
`define ithrmin 91//-13'd8 `define ithrmin 91 // -13'd8
`define ithrmax 160// 13'd8 `define ithrmax 160 // 13'd8
`define min_bitdelay_212 8 `define min_bitdelay_212 8
//minimum values and corresponding thresholds //minimum values and corresponding thresholds
reg [8:0] curmin=`imin; reg [8:0] curmin=`imin;
reg [8:0] curminthres=`ithrmin; reg [8:0] curminthres=`ithrmin;
reg [8:0] curmaxthres=`ithrmax; reg [8:0] curmaxthres=`ithrmax;
reg [8:0] curmax=`imax; reg [8:0] curmax=`imax;
//signal state, 1-not modulated, 0 -modulated //signal state, 1-not modulated, 0 -modulated
reg after_hysteresis = 1'b1; reg after_hysteresis = 1'b1;
//state machine for envelope tracking //state machine for envelope tracking
reg [1:0] state=1'd0; reg [1:0] state=1'd0;
//lower edge detected, trying to detect first bit of SYNC (b24d, 1011001001001101) //lower edge detected, trying to detect first bit of SYNC (b24d, 1011001001001101)
reg try_sync=1'b0; reg try_sync=1'b0;
//detected first sync bit, phase frozen //detected first sync bit, phase frozen
reg did_sync=0; reg did_sync=0;
`define bithalf_212 32 // half-bit length for 212 kbit
`define bitmlen_212 63 // bit transition edge
`define bithalf_212 32 //half-bit length for 212 kbit `define bithalf_424 16 // half-bit length for 212 kbit
`define bitmlen_212 63 //bit transition edge `define bitmlen_424 31 // bit transition edge
`define bithalf_424 16 //half-bit length for 212 kbit wire [7:0] bithalf = speed ? `bithalf_424 : `bithalf_212;
`define bitmlen_424 31 //bit transition edge wire [7:0] bitmlen = speed ? `bitmlen_424 : `bitmlen_212;
wire [7:0]bithalf= speed ? `bithalf_424 : `bithalf_212;
wire [7:0]bitmlen= speed ? `bitmlen_424 : `bitmlen_212;
//ssp clock and current values //ssp clock and current values
reg ssp_clk; reg ssp_clk;
reg ssp_frame; reg ssp_frame;
reg curbit=1'b0; reg curbit = 1'b0;
reg [7:0] fccount=8'd0; // in-bit tick counter. Counts carrier cycles from the first lower edge detected, reset on every manchester bit detected reg [7:0] fccount = 8'd0; // in-bit tick counter. Counts carrier cycles from the first lower edge detected, reset on every manchester bit detected
reg [7:0] tsinceedge=8'd0;// ticks from last edge, desync if the valye is too large reg [7:0] tsinceedge = 8'd0;// ticks from last edge, desync if the valye is too large
reg zero=1'b0; // Manchester first halfbit low second high corresponds to this value. It has been known to change. SYNC is used to set it reg zero = 1'b0; // Manchester first halfbit low second high corresponds to this value. It has been known to change. SYNC is used to set it
//ssp counter for transfer and framing //ssp counter for transfer and framing
reg [8:0] ssp_cnt=9'd0; reg [8:0] ssp_cnt = 9'd0;
always @(posedge adc_clk) always @(posedge adc_clk)
ssp_cnt <= (ssp_cnt + 1); ssp_cnt <= (ssp_cnt + 1);
@ -108,238 +104,202 @@ always @(posedge adc_clk)
always @(negedge adc_clk) always @(negedge adc_clk)
begin begin
//count fc/64 - transfer bits to ARM at the rate they are received //count fc/64 - transfer bits to ARM at the rate they are received
if( ((~speed) && (ssp_cnt[5:0] == 6'b000000)) || (speed &&(ssp_cnt[4:0] == 5'b00000))) if( ((~speed) && (ssp_cnt[5:0] == 6'b000000)) || (speed && (ssp_cnt[4:0] == 5'b00000)))
begin begin
ssp_clk <= 1'b1; ssp_clk <= 1'b1;
// if(mod_type[2])
// begin
// ssp_din<=outp[0];//after_hysteresis;
//outp<={1'b0,outp[7:1]};
// end
// else
ssp_din <= curbit; ssp_din <= curbit;
//sample ssp_dout
end end
if( ( (~speed) && (ssp_cnt[5:0] == 6'b100000)) ||(speed && ssp_cnt[4:0] == 5'b10000)) if( ( (~speed) && (ssp_cnt[5:0] == 6'b100000)) ||(speed && ssp_cnt[4:0] == 5'b10000))
ssp_clk <= 1'b0; ssp_clk <= 1'b0;
//create frame pulses. TBH, I still don't know what they do exactly, but they are crucial for ARM->FPGA transfer. If the frame is in the beginning of the byte, transfer slows to a crawl for some reason //create frame pulses. TBH, I still don't know what they do exactly, but they are crucial for ARM->FPGA transfer. If the frame is in the beginning of the byte, transfer slows to a crawl for some reason
// took me a day to figure THAT out. // took me a day to figure THAT out.
if(( (~speed) && (ssp_cnt[8:0] == 9'd31))||(speed && ssp_cnt[7:0] == 8'd15)) if(( (~speed) && (ssp_cnt[8:0] == 9'd31)) || (speed && ssp_cnt[7:0] == 8'd15))
begin begin
ssp_frame <= 1'b1; ssp_frame <= 1'b1;
end end
if(( (~speed) && (ssp_cnt[8:0] == 9'b1011111))||(speed &&ssp_cnt[7:0] == 8'b101111) ) if(( (~speed) && (ssp_cnt[8:0] == 9'b1011111)) || (speed &&ssp_cnt[7:0] == 8'b101111) )
begin begin
ssp_frame <= 1'b0; ssp_frame <= 1'b0;
end end
end end
//send current bit (detected in SNIFF mode or the one being modulated in MOD mode, 0 otherwise) //send current bit (detected in SNIFF mode or the one being modulated in MOD mode, 0 otherwise)
reg ssp_din;//= outp[0]; reg ssp_din;
//previous signal value, mostly to detect SYNC //previous signal value, mostly to detect SYNC
reg prv =1'b1; reg prv = 1'b1;
reg[7:0] mid=8'd128; //for simple error correction in mod/demod detection, use maximum of modded/demodded in given interval. Maybe 1 bit is extra? but better safe than sorry.
// for simple error correction in mod/demod detection, use maximum of modded/demodded in given interval. Maybe 1 bit is extra? but better safe than sorry.
reg[7:0] mid = 8'd128;
// set TAGSIM__MODULATE on ARM if we want to write... (frame would get lost if done mid-frame...) // set TAGSIM__MODULATE on ARM if we want to write... (frame would get lost if done mid-frame...)
// start sending over 1s on ssp->arm when we start sending preamble // start sending over 1s on ssp->arm when we start sending preamble
// reg sending = 1'b0; // are we actively modulating?
reg counting_desync=1'b0; // are we counting bits since last frame? reg [11:0] bit_counts = 12'd0; // for timeslots. only support ts=0 for now, at 212 speed -512 fullbits from end of frame. One hopes. might remove those?
reg sending=1'b0; // are we actively modulating?
reg [11:0] bit_counts=12'd0;///for timeslots... only support ts=0 for now, at 212 speed -512 fullbits from end of frame. One hopes. might remove those?
//reg [2:0]old_mod;
//always @(mod_type) //when moving from modulate_mode
//begin
//if (mod_type[2]==1&&old_mod[2]==0)
// bit_counts=0;
//old_mod=mod_type;
//end
//we need some way to flush bit_counts triggers on mod_type changes don't compile //we need some way to flush bit_counts triggers on mod_type changes don't compile
reg dlay; reg dlay;
always @(negedge adc_clk) //every data ping? always @(negedge adc_clk) // every data ping?
begin begin
//envelope follow code... //envelope follow code...
//////////// ////////////
if (fccount == bitmlen)
//move the counter to the outside...
// if (adc_d>=curminthres||try_sync)
if(fccount==bitmlen)
begin begin
if((~try_sync)&&(adc_d<curminthres)&&disabl ) if ((~try_sync) && (adc_d < curminthres) && disabl )
begin begin
fccount<=1; fccount <= 1;
end end
else else
begin begin
fccount<=0; fccount <= 0;
end end
// if (counting_desync) dlay <= ssp_dout;
// begin if (bit_counts > 768) // should be over ts0 now, without ARM interference... stop counting...
dlay<=ssp_dout;
if(bit_counts>768) // should be over ts0 now, without ARM interference... stop counting...
begin begin
bit_counts<=0; bit_counts <= 0;
// counting_desync<=0;
end end
else else
if((power)) if (power)
bit_counts<=0; bit_counts <= 0;
else else
bit_counts<=bit_counts+1; bit_counts <= bit_counts + 1;
// end
end end
else else
begin begin
if((~try_sync)&&(adc_d<curminthres) &&disabl) if((~try_sync) && (adc_d < curminthres) && disabl)
begin begin
fccount<=1; fccount <= 1;
end end
else else
begin begin
fccount<=fccount+1; fccount <= fccount + 1;
end end
end end
if (adc_d>curmaxthres) //rising edge // rising edge
if (adc_d > curmaxthres)
begin begin
case (state) case (state)
0: begin 0: begin
curmax <= adc_d>`imax? adc_d :`imax; curmax <= adc_d > `imax? adc_d : `imax;
state <= 2; state <= 2;
end end
1: begin 1: begin
curminthres <= ( (curmin>>1)+(curmin>>2)+(curmin>>4)+(curmax>>3)+(curmax>>4)); //threshold: 0.1875 max + 0.8125 min curminthres <= ((curmin >> 1) + (curmin >> 2) + (curmin >> 4) + (curmax >> 3) + (curmax >> 4)); //threshold: 0.1875 max + 0.8125 min
curmaxthres <= ( (curmax>>1)+(curmax>>2)+(curmax>>4)+(curmin>>3)+(curmin>>4)); curmaxthres <= ((curmax >> 1) + (curmax >> 2) + (curmax >> 4) + (curmin >> 3) + (curmin >> 4));
curmax <= adc_d>155? adc_d :155; // to hopefully prevent overflow from spikes going up to 255 curmax <= adc_d > 155 ? adc_d : 155; // to hopefully prevent overflow from spikes going up to 255
state <= 2; state <= 2;
end end
2: begin 2: begin
if (adc_d>curmax) if (adc_d > curmax)
curmax <= adc_d; curmax <= adc_d;
end end
default: default:
begin begin
end end
endcase endcase
after_hysteresis <=1'b1; after_hysteresis <= 1'b1;
if(try_sync) if(try_sync)
tsinceedge<=0; tsinceedge <= 0;
end end
else if (adc_d<curminthres) //falling edge else if (adc_d<curminthres) //falling edge
begin begin
case (state) case (state)
0: begin 0: begin
curmin <=adc_d<`imin? adc_d :`imin; curmin <= adc_d<`imin? adc_d :`imin;
state <=1; state <= 1;
end end
1: begin 1: begin
if (adc_d<curmin) if (adc_d<curmin)
curmin <= adc_d; curmin <= adc_d;
end end
2: begin 2: begin
curminthres <= ( (curmin>>1)+(curmin>>2)+(curmin>>4)+(curmax>>3)+(curmax>>4)); curminthres <= ( (curmin >> 1) + (curmin >> 2) + (curmin >> 4) + (curmax >> 3) + (curmax >> 4));
curmaxthres <= ( (curmax>>1)+(curmax>>2)+(curmax>>4)+(curmin>>3)+(curmin>>4)); curmaxthres <= ( (curmax >> 1) + (curmax >> 2) + (curmax >> 4) + (curmin >> 3) + (curmin >> 4));
curmin <=adc_d<`imin? adc_d :`imin; curmin <= adc_d < `imin ? adc_d : `imin;
state <=1; state <= 1;
end end
default: default:
begin begin
end end
endcase endcase
after_hysteresis <=0; after_hysteresis <= 0;
if (~try_sync ) //begin modulation, lower edge... if (~try_sync ) //begin modulation, lower edge...
begin begin
try_sync <=1; try_sync <= 1;
//counting_desync<=1'b0;
fccount <= 1; fccount <= 1;
did_sync<=0; did_sync <= 0;
curbit<=0; curbit <= 0;
mid <=8'd127; mid <= 8'd127;
tsinceedge<=0; tsinceedge <= 0;
prv <=1; prv <= 1;
end end
else else
begin begin
tsinceedge<=0; tsinceedge <= 0;
end end
end end
else //stable state, low or high else //stable state, low or high
begin begin
curminthres <= ( (curmin>>1)+(curmin>>2)+(curmin>>4)+(curmax>>3)+(curmax>>4)); curminthres <= ( (curmin >> 1) + (curmin >> 2) + (curmin >> 4) + (curmax >> 3) + (curmax >> 4));
curmaxthres <= ( (curmax>>1)+(curmax>>2)+(curmax>>4)+(curmin>>3)+(curmin>>4)); curmaxthres <= ( (curmax >> 1) + (curmax >> 2) + (curmax >> 4) + (curmin >> 3) + (curmin >> 4));
state <=0; state <= 0;
if (try_sync ) if (try_sync )
begin begin
if (tsinceedge>=(128)) if (tsinceedge >= (128))
begin begin
//we might need to start counting... assuming ARM wants to reply to the frame. //we might need to start counting... assuming ARM wants to reply to the frame.
// counting_desync<=1'b1; bit_counts <= 1;// i think? 128 is about 2 bits passed... but 1 also works
bit_counts<=1;// i think? 128 is about 2 bits passed... but 1 also works try_sync <= 0;
try_sync<=0; did_sync <= 0;//desync
did_sync<=0;//desync curmin <= `imin; //reset envelope
curmin <=`imin; //reset envelope curmax <= `imax;
curmax <=`imax; curminthres <= `ithrmin;
curminthres <=`ithrmin; curmaxthres <= `ithrmax;
curmaxthres <=`ithrmax; prv <= 1;
prv <=1; tsinceedge <= 0;
tsinceedge <=0; after_hysteresis <= 1'b1;
after_hysteresis <=1'b1; curbit <= 0;
curbit <=0; mid <= 8'd128;
mid <=8'd128;
end end
else else
tsinceedge<=(tsinceedge+1); tsinceedge <= (tsinceedge + 1);
end end
end end
if (try_sync && tsinceedge < 128)
if (try_sync && tsinceedge<128)
begin begin
//detect bits in their middle ssp sampling is in sync, so it would sample all bits in order //detect bits in their middle ssp sampling is in sync, so it would sample all bits in order
if (fccount==bithalf) if (fccount == bithalf)
begin begin
if ((~did_sync) && ((prv==1&&(mid>128))||(prv==0&&(mid<=128)))) if ((~did_sync) && ((prv == 1 && (mid > 128))||(prv == 0 && (mid <= 128))))
begin begin
//sync the Zero, and set curbit roperly //sync the Zero, and set curbit roperly
did_sync <=1'b1; did_sync <= 1'b1;
zero <= ~prv;// 1-prv zero <= ~prv;// 1-prv
curbit <=1; curbit <= 1;
end end
else else
curbit <= (mid>128) ? (~zero):zero; curbit <= (mid > 128) ? (~zero) : zero;
prv <=(mid>128) ?1:0; prv <= (mid > 128) ? 1 : 0;
if(adc_d>curmaxthres) if (adc_d > curmaxthres)
mid <=8'd129; mid <= 8'd129;
else if (adc_d<curminthres) else if (adc_d < curminthres)
mid <=8'd127; mid <= 8'd127;
else else
begin begin
if (after_hysteresis) if (after_hysteresis)
begin begin
mid <=8'd129; mid <= 8'd129;
end end
else else
begin begin
mid<=8'd127; mid <= 8'd127;
end end
end end
@ -348,26 +308,26 @@ begin
begin begin
if (fccount==bitmlen) if (fccount==bitmlen)
begin begin
// fccount <=0; // fccount <= 0;
prv <=(mid>128)?1:0; prv <= (mid > 128) ? 1 : 0;
mid <=128; mid <= 128;
end end
else else
begin begin
// minimum-maximum calc // minimum-maximum calc
if(adc_d>curmaxthres) if(adc_d > curmaxthres)
mid <=mid+1; mid <= mid + 1;
else if (adc_d<curminthres) else if (adc_d < curminthres)
mid <=mid-1; mid <= mid - 1;
else else
begin begin
if (after_hysteresis) if (after_hysteresis)
begin begin
mid <=mid+1; mid <= mid + 1;
end end
else else
begin begin
mid<=mid-1; mid <= mid - 1;
end end
end end
end end
@ -376,7 +336,7 @@ begin
else else
begin begin
end end
sending <=0; // sending <= 0;
end end
//put modulation here to maintain the correct clock. Seems that some readers are sensitive to that //put modulation here to maintain the correct clock. Seems that some readers are sensitive to that
reg pwr_hi; reg pwr_hi;
@ -385,32 +345,26 @@ reg pwr_oe2;
reg pwr_oe3; reg pwr_oe3;
reg pwr_oe4; reg pwr_oe4;
wire mod=((fccount>=bithalf)^dlay)&(~disabl); wire mod = ((fccount >= bithalf) ^ dlay) & (~disabl);
always @(ck_1356megb or ssp_dout or power or disabl or mod) always @(ck_1356megb or ssp_dout or power or disabl or mod)
begin
if (power)
begin begin
if (power)
begin
pwr_hi <= ck_1356megb; pwr_hi <= ck_1356megb;
pwr_oe1 <= 1'b0;//mod; pwr_oe1 <= 1'b0;//mod;
pwr_oe2 <= 1'b0;//mod; pwr_oe2 <= 1'b0;//mod;
pwr_oe3 <= 1'b0;//mod; pwr_oe3 <= 1'b0;//mod;
pwr_oe4 <= mod;//1'b0; pwr_oe4 <= mod;//1'b0;
end end
else else
begin begin
pwr_hi <= 1'b0; pwr_hi <= 1'b0;
pwr_oe1 <= 1'b0; pwr_oe1 <= 1'b0;
pwr_oe2 <= 1'b0; pwr_oe2 <= 1'b0;
pwr_oe3 <= 1'b0; pwr_oe3 <= 1'b0;
pwr_oe4 <= mod; pwr_oe4 <= mod;
end end
end end
//assign pwr_oe4 = 1'b0;// mod_sig_coil & (modulate_mode)&sending & (~mod_type[2]);
//try shallow mod for reader?
//assign pwr_hi= (mod_type[2]) & ck_1356megb;
//assign pwr_oe1= 1'b0; //mod_sig_coil & (modulate_mode)&sending & (mod_type[2]);
//assign pwr_oe2 = 1'b0;// mod_sig_coil & (modulate_mode)&sending & (mod_type[2]);
//assign pwr_oe3 = 1'b0; //mod_sig_coil & (modulate_mode)&sending & (mod_type[2]);
endmodule endmodule