rework iso14443b device functions including FPGA I/Q signal transfer (#669)

* rework iso14443b device functions
* hf_read_rx_xcorr.v: transfer i/q pair in one 16bit frame
* hi_read_tx.v: invert ssp_dout. When nothing is transferred (ssp_dout=0), this results in no modulation (carrier on)
* adjust arm sources accordingly
* iso14443b.c: switch off carrier after hf 14b sri512read and hf 14b srix4kread
* iso14443b.c: fix DMA circular buffer handling
This commit is contained in:
pwpiwi 2018-09-16 00:53:28 +02:00 committed by GitHub
commit 6a5d4e17f4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 212 additions and 321 deletions

View file

@ -112,10 +112,10 @@ void SetupSpi(int mode)
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Set up the synchronous serial port, with the one set of options that we // Set up the synchronous serial port with the set of options that fits
// always use when we are talking to the FPGA. Both RX and TX are enabled. // the FPGA mode. Both RX and TX are always enabled.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void FpgaSetupSsc(void) void FpgaSetupSsc(uint8_t FPGA_mode)
{ {
// First configure the GPIOs, and get ourselves a clock. // First configure the GPIOs, and get ourselves a clock.
AT91C_BASE_PIOA->PIO_ASR = AT91C_BASE_PIOA->PIO_ASR =
@ -134,11 +134,15 @@ void FpgaSetupSsc(void)
// on RX clock rising edge, sampled on falling edge // on RX clock rising edge, sampled on falling edge
AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1); AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1);
// 8 bits per transfer, no loopback, MSB first, 1 transfer per sync // 8, 16 or 32 bits per transfer, no loopback, MSB first, 1 transfer per sync
// pulse, no output sync // pulse, no output sync
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); if ((FPGA_mode & 0xe0) == FPGA_MAJOR_MODE_HF_READER_RX_XCORR) {
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
} else {
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
}
// clock comes from TK pin, no clock output, outputs change on falling // TX clock comes from TK pin, no clock output, outputs change on falling
// edge of TK, sample on rising edge of TK, start on positive-going edge of sync // edge of TK, sample on rising edge of TK, start on positive-going edge of sync
AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5); AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5);
@ -154,16 +158,15 @@ void FpgaSetupSsc(void)
// ourselves, not to another buffer). The stuff to manipulate those buffers // ourselves, not to another buffer). The stuff to manipulate those buffers
// is in apps.h, because it should be inlined, for speed. // is in apps.h, because it should be inlined, for speed.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool FpgaSetupSscDma(uint8_t *buf, int len) bool FpgaSetupSscDma(uint8_t *buf, uint16_t sample_count)
{ {
if (buf == NULL) return false; if (buf == NULL) return false;
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; // Disable DMA Transfer AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; // Disable DMA Transfer
AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) buf; // transfer to this memory address AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) buf; // transfer to this memory address
AT91C_BASE_PDC_SSC->PDC_RCR = len; // transfer this many bytes AT91C_BASE_PDC_SSC->PDC_RCR = sample_count; // transfer this many samples
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) buf; // next transfer to same memory address AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) buf; // next transfer to same memory address
AT91C_BASE_PDC_SSC->PDC_RNCR = len; // ... with same number of bytes AT91C_BASE_PDC_SSC->PDC_RNCR = sample_count; // ... with same number of samples AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // go!
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // go!
return true; return true;
} }

View file

@ -19,7 +19,7 @@
void FpgaSendCommand(uint16_t cmd, uint16_t v); void FpgaSendCommand(uint16_t cmd, uint16_t v);
void FpgaWriteConfWord(uint8_t v); void FpgaWriteConfWord(uint8_t v);
void FpgaDownloadAndGo(int bitstream_version); void FpgaDownloadAndGo(int bitstream_version);
void FpgaSetupSsc(void); void FpgaSetupSsc(uint8_t mode);
void SetupSpi(int mode); void SetupSpi(int mode);
bool FpgaSetupSscDma(uint8_t *buf, int len); bool FpgaSetupSscDma(uint8_t *buf, int len);
void Fpga_print_status(); void Fpga_print_status();

View file

@ -37,7 +37,7 @@ void HfSnoop(int samplesToSkip, int triggersToSkip)
// Select correct configs // Select correct configs
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Set up the synchronous serial port // Set up the synchronous serial port
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SNOOP);
// connect Demodulated Signal to ADC: // connect Demodulated Signal to ADC:
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNOOP); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNOOP);

View file

@ -676,7 +676,7 @@ void RAMFUNC SnoopIClass(void)
Demod.state = DEMOD_UNSYNCD; Demod.state = DEMOD_UNSYNCD;
// Setup for the DMA. // Setup for the DMA.
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A);
upTo = dmaBuf; upTo = dmaBuf;
lastRxCounter = DMA_BUFFER_SIZE; lastRxCounter = DMA_BUFFER_SIZE;
FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE);
@ -1163,7 +1163,7 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf)
StartCountSspClk(); StartCountSspClk();
// We need to listen to the high-frequency, peak-detected path. // We need to listen to the high-frequency, peak-detected path.
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A);
// To control where we are in the protocol // To control where we are in the protocol
int cmdsRecvd = 0; int cmdsRecvd = 0;
@ -1360,7 +1360,7 @@ static int SendIClassAnswer(uint8_t *resp, int respLen, int delay)
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K_8BIT); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K_8BIT);
AT91C_BASE_SSC->SSC_THR = 0x00; AT91C_BASE_SSC->SSC_THR = 0x00;
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
while(!BUTTON_PRESS()) { while(!BUTTON_PRESS()) {
if((AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)){ if((AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)){
b = AT91C_BASE_SSC->SSC_RHR; (void) b; b = AT91C_BASE_SSC->SSC_RHR; (void) b;
@ -1398,7 +1398,7 @@ static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int
int c; int c;
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
AT91C_BASE_SSC->SSC_THR = 0x00; AT91C_BASE_SSC->SSC_THR = 0x00;
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A);
if (wait) if (wait)
{ {
@ -1586,7 +1586,7 @@ void setupIclassReader()
clear_trace(); clear_trace();
// Setup SSC // Setup SSC
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A);
// Start from off (no field generated) // Start from off (no field generated)
// Signal field is off with the appropriate LED // Signal field is off with the appropriate LED
LED_D_OFF(); LED_D_OFF();

View file

@ -1889,7 +1889,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
void iso14443a_setup(uint8_t fpga_minor_mode) { void iso14443a_setup(uint8_t fpga_minor_mode) {
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Set up the synchronous serial port // Set up the synchronous serial port
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A);
// connect Demodulated Signal to ADC: // connect Demodulated Signal to ADC:
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);

View file

@ -1,5 +1,6 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Jonathan Westhues, split Nov 2006 // Jonathan Westhues, split Nov 2006
// piwi 2018
// //
// This code is licensed to you under the terms of the GNU GPL, version 2 or, // This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of // at your option, any later version. See the LICENSE.txt file for the text of
@ -16,8 +17,8 @@
#include "iso14443crc.h" #include "iso14443crc.h"
#define RECEIVE_SAMPLES_TIMEOUT 2000 #define RECEIVE_SAMPLES_TIMEOUT 1000 // TR0 max is 256/fs = 256/(848kHz) = 302us or 64 samples from FPGA. 1000 seems to be much too high?
#define ISO14443B_DMA_BUFFER_SIZE 256 #define ISO14443B_DMA_BUFFER_SIZE 128
// PCB Block number for APDUs // PCB Block number for APDUs
static uint8_t pcb_blocknum = 0; static uint8_t pcb_blocknum = 0;
@ -374,7 +375,7 @@ void SimulateIso14443bTag(void)
// We need to listen to the high-frequency, peak-detected path. // We need to listen to the high-frequency, peak-detected path.
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
cmdsRecvd = 0; cmdsRecvd = 0;
@ -440,7 +441,7 @@ void SimulateIso14443bTag(void)
LED_D_OFF(); LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK);
AT91C_BASE_SSC->SSC_THR = 0xff; AT91C_BASE_SSC->SSC_THR = 0xff;
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
// Transmit the response. // Transmit the response.
uint16_t i = 0; uint16_t i = 0;
@ -535,60 +536,11 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq)
#define SUBCARRIER_DETECT_THRESHOLD 8 #define SUBCARRIER_DETECT_THRESHOLD 8
// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by abs(ci) + abs(cq)
/* #define CHECK_FOR_SUBCARRIER() { \
v = ci; \
if(v < 0) v = -v; \
if(cq > 0) { \
v += cq; \
} else { \
v -= cq; \
} \
}
*/
// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq))) // Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq)))
#define AMPLITUDE(ci,cq) (MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2))
//note: couldn't we just use MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2) from common.h - marshmellow
#define CHECK_FOR_SUBCARRIER() { \
v = MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2); \
}
/*
if(ci < 0) { \
if(cq < 0) { \ // ci < 0, cq < 0
if (cq < ci) { \
v = -cq - (ci >> 1); \
} else { \
v = -ci - (cq >> 1); \
} \
} else { \ // ci < 0, cq >= 0
if (cq < -ci) { \
v = -ci + (cq >> 1); \
} else { \
v = cq - (ci >> 1); \
} \
} \
} else { \
if(cq < 0) { \ // ci >= 0, cq < 0
if (-cq < ci) { \
v = ci - (cq >> 1); \
} else { \
v = -cq + (ci >> 1); \
} \
} else { \ // ci >= 0, cq >= 0
if (cq < ci) { \
v = ci + (cq >> 1); \
} else { \
v = cq + (ci >> 1); \
} \
} \
} \
}
*/
switch(Demod.state) { switch(Demod.state) {
case DEMOD_UNSYNCD: case DEMOD_UNSYNCD:
CHECK_FOR_SUBCARRIER(); if(AMPLITUDE(ci,cq) > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected
if(v > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected
Demod.state = DEMOD_PHASE_REF_TRAINING; Demod.state = DEMOD_PHASE_REF_TRAINING;
Demod.sumI = ci; Demod.sumI = ci;
Demod.sumQ = cq; Demod.sumQ = cq;
@ -598,8 +550,7 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq)
case DEMOD_PHASE_REF_TRAINING: case DEMOD_PHASE_REF_TRAINING:
if(Demod.posCount < 8) { if(Demod.posCount < 8) {
CHECK_FOR_SUBCARRIER(); if (AMPLITUDE(ci,cq) > SUBCARRIER_DETECT_THRESHOLD) {
if (v > SUBCARRIER_DETECT_THRESHOLD) {
// set the reference phase (will code a logic '1') by averaging over 32 1/fs. // set the reference phase (will code a logic '1') by averaging over 32 1/fs.
// note: synchronization time > 80 1/fs // note: synchronization time > 80 1/fs
Demod.sumI += ci; Demod.sumI += ci;
@ -743,10 +694,11 @@ static void DemodInit(uint8_t *data)
*/ */
static void GetSamplesFor14443bDemod(int n, bool quiet) static void GetSamplesFor14443bDemod(int n, bool quiet)
{ {
int max = 0; int maxBehindBy = 0;
bool gotFrame = false; bool gotFrame = false;
int lastRxCounter, ci, cq, samples = 0; int lastRxCounter, samples = 0;
int8_t ci, cq;
// Allocate memory from BigBuf for some buffers // Allocate memory from BigBuf for some buffers
// free all previous allocations first // free all previous allocations first
BigBuf_free(); BigBuf_free();
@ -755,15 +707,19 @@ static void GetSamplesFor14443bDemod(int n, bool quiet)
uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE); uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE);
// The DMA buffer, used to stream samples from the FPGA // The DMA buffer, used to stream samples from the FPGA
int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); uint16_t *dmaBuf = (uint16_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE * sizeof(uint16_t));
// Set up the demodulator for tag -> reader responses. // Set up the demodulator for tag -> reader responses.
DemodInit(receivedResponse); DemodInit(receivedResponse);
// wait for last transfer to complete
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY))
// Setup and start DMA. // Setup and start DMA.
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE);
int8_t *upTo = dmaBuf; uint16_t *upTo = dmaBuf;
lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; lastRxCounter = ISO14443B_DMA_BUFFER_SIZE;
// Signal field is ON with the appropriate LED: // Signal field is ON with the appropriate LED:
@ -772,39 +728,40 @@ static void GetSamplesFor14443bDemod(int n, bool quiet)
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);
for(;;) { for(;;) {
int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR; int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1);
if(behindBy > max) max = behindBy; if(behindBy > maxBehindBy) {
maxBehindBy = behindBy;
while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1)) > 2) {
ci = upTo[0];
cq = upTo[1];
upTo += 2;
if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) {
upTo = dmaBuf;
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo;
AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE;
}
lastRxCounter -= 2;
if(lastRxCounter <= 0) {
lastRxCounter += ISO14443B_DMA_BUFFER_SIZE;
}
samples += 2;
if(Handle14443bSamplesDemod(ci, cq)) {
gotFrame = true;
break;
}
} }
if(samples > n || gotFrame) { if(behindBy < 1) continue;
ci = *upTo >> 8;
cq = *upTo;
upTo++;
lastRxCounter--;
if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content.
upTo = dmaBuf; // start reading the circular buffer from the beginning
lastRxCounter += ISO14443B_DMA_BUFFER_SIZE;
}
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated.
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and
AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; // DMA Next Counter registers
}
samples++;
if(Handle14443bSamplesDemod(ci, cq)) {
gotFrame = true;
break;
}
if(samples > n) {
break; break;
} }
} }
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; FpgaDisableSscDma();
if (!quiet) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.len = %d, Demod.sumI = %d, Demod.sumQ = %d", max, samples, gotFrame, Demod.len, Demod.sumI, Demod.sumQ); if (!quiet) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.len = %d, Demod.sumI = %d, Demod.sumQ = %d", maxBehindBy, samples, gotFrame, Demod.len, Demod.sumI, Demod.sumQ);
//Tracing //Tracing
if (tracing && Demod.len > 0) { if (tracing && Demod.len > 0) {
uint8_t parity[MAX_PARITY_SIZE]; uint8_t parity[MAX_PARITY_SIZE];
@ -820,11 +777,7 @@ static void TransmitFor14443b(void)
{ {
int c; int c;
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX);
while(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = 0xff;
}
// Signal field is ON with the appropriate Red LED // Signal field is ON with the appropriate Red LED
LED_D_ON(); LED_D_ON();
@ -832,31 +785,15 @@ static void TransmitFor14443b(void)
LED_B_ON(); LED_B_ON();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);
for(c = 0; c < 10;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = 0xff;
c++;
}
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
(void)r;
}
WDT_HIT();
}
c = 0; c = 0;
for(;;) { for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = ToSend[c]; AT91C_BASE_SSC->SSC_THR = ~ToSend[c];
c++; c++;
if(c >= ToSendMax) { if(c >= ToSendMax) {
break; break;
} }
} }
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
(void)r;
}
WDT_HIT(); WDT_HIT();
} }
LED_B_OFF(); // Finished sending LED_B_OFF(); // Finished sending
@ -874,19 +811,14 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len)
ToSendReset(); ToSendReset();
// Establish initial reference level
for(i = 0; i < 40; i++) {
ToSendStuffBit(1);
}
// Send SOF // Send SOF
for(i = 0; i < 10; i++) { for(i = 0; i < 10; i++) {
ToSendStuffBit(0); ToSendStuffBit(0);
} }
ToSendStuffBit(1);
ToSendStuffBit(1);
for(i = 0; i < len; i++) { for(i = 0; i < len; i++) {
// Stop bits/EGT
ToSendStuffBit(1);
ToSendStuffBit(1);
// Start bit // Start bit
ToSendStuffBit(0); ToSendStuffBit(0);
// Data bits // Data bits
@ -899,19 +831,18 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len)
} }
b >>= 1; b >>= 1;
} }
} // Stop bit
// Send EOF
ToSendStuffBit(1);
for(i = 0; i < 10; i++) {
ToSendStuffBit(0);
}
for(i = 0; i < 8; i++) {
ToSendStuffBit(1); ToSendStuffBit(1);
} }
// And then a little more, to make sure that the last character makes // Send EOF
// it out before we switch to rx mode. for(i = 0; i < 10; i++) {
for(i = 0; i < 24; i++) { ToSendStuffBit(0);
}
ToSendStuffBit(1);
// ensure that last byte is filled up
for(i = 0; i < 8; i++) {
ToSendStuffBit(1); ToSendStuffBit(1);
} }
@ -951,7 +882,7 @@ int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *respo
// send // send
CodeAndTransmit14443bAsReader(message_frame, message_length + 4); CodeAndTransmit14443bAsReader(message_frame, message_length + 4);
// get response // get response
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT*100, true); GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if(Demod.len < 3) if(Demod.len < 3)
{ {
return 0; return 0;
@ -1011,7 +942,7 @@ int iso14443b_select_card()
void iso14443b_setup() { void iso14443b_setup() {
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Set up the synchronous serial port // Set up the synchronous serial port
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX);
// connect Demodulated Signal to ADC: // connect Demodulated Signal to ADC:
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
@ -1019,9 +950,6 @@ void iso14443b_setup() {
LED_D_ON(); LED_D_ON();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);
// Start the timer
StartCountSspClk();
DemodReset(); DemodReset();
UartReset(); UartReset();
} }
@ -1047,7 +975,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
SpinDelay(200); SpinDelay(200);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
// Now give it time to spin up. // Now give it time to spin up.
// Signal field is on with the appropriate LED // Signal field is on with the appropriate LED
@ -1065,6 +993,8 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
if (Demod.len == 0) { if (Demod.len == 0) {
DbpString("No response from tag"); DbpString("No response from tag");
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return; return;
} else { } else {
Dbprintf("Randomly generated Chip ID (+ 2 byte CRC): %02x %02x %02x", Dbprintf("Randomly generated Chip ID (+ 2 byte CRC): %02x %02x %02x",
@ -1080,17 +1010,23 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if (Demod.len != 3) { if (Demod.len != 3) {
Dbprintf("Expected 3 bytes from tag, got %d", Demod.len); Dbprintf("Expected 3 bytes from tag, got %d", Demod.len);
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return; return;
} }
// Check the CRC of the answer: // Check the CRC of the answer:
ComputeCrc14443(CRC_14443_B, Demod.output, 1 , &cmd1[2], &cmd1[3]); ComputeCrc14443(CRC_14443_B, Demod.output, 1 , &cmd1[2], &cmd1[3]);
if(cmd1[2] != Demod.output[1] || cmd1[3] != Demod.output[2]) { if(cmd1[2] != Demod.output[1] || cmd1[3] != Demod.output[2]) {
DbpString("CRC Error reading select response."); DbpString("CRC Error reading select response.");
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return; return;
} }
// Check response from the tag: should be the same UID as the command we just sent: // Check response from the tag: should be the same UID as the command we just sent:
if (cmd1[1] != Demod.output[0]) { if (cmd1[1] != Demod.output[0]) {
Dbprintf("Bad response to SELECT from Tag, aborting: %02x %02x", cmd1[1], Demod.output[0]); Dbprintf("Bad response to SELECT from Tag, aborting: %02x %02x", cmd1[1], Demod.output[0]);
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return; return;
} }
@ -1102,6 +1038,8 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if (Demod.len != 10) { if (Demod.len != 10) {
Dbprintf("Expected 10 bytes from tag, got %d", Demod.len); Dbprintf("Expected 10 bytes from tag, got %d", Demod.len);
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return; return;
} }
// The check the CRC of the answer (use cmd1 as temporary variable): // The check the CRC of the answer (use cmd1 as temporary variable):
@ -1131,6 +1069,8 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if (Demod.len != 6) { // Check if we got an answer from the tag if (Demod.len != 6) { // Check if we got an answer from the tag
DbpString("Expected 6 bytes from tag, got less..."); DbpString("Expected 6 bytes from tag, got less...");
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return; return;
} }
// The check the CRC of the answer (use cmd1 as temporary variable): // The check the CRC of the answer (use cmd1 as temporary variable):
@ -1149,6 +1089,9 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
} }
i++; i++;
} }
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
} }
@ -1171,11 +1114,6 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
*/ */
void RAMFUNC SnoopIso14443b(void) void RAMFUNC SnoopIso14443b(void)
{ {
// We won't start recording the frames that we acquire until we trigger;
// a good trigger condition to get started is probably when we see a
// response from the tag.
int triggered = true; // TODO: set and evaluate trigger condition
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
BigBuf_free(); BigBuf_free();
@ -1183,10 +1121,10 @@ void RAMFUNC SnoopIso14443b(void)
set_tracing(true); set_tracing(true);
// The DMA buffer, used to stream samples from the FPGA // The DMA buffer, used to stream samples from the FPGA
int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); uint16_t *dmaBuf = (uint16_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE * sizeof(uint16_t));
int lastRxCounter; int lastRxCounter;
int8_t *upTo; uint16_t *upTo;
int ci, cq; int8_t ci, cq;
int maxBehindBy = 0; int maxBehindBy = 0;
// Count of samples received so far, so that we can include timing // Count of samples received so far, so that we can include timing
@ -1211,7 +1149,7 @@ void RAMFUNC SnoopIso14443b(void)
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Setup for the DMA. // Setup for the DMA.
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
upTo = dmaBuf; upTo = dmaBuf;
lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; lastRxCounter = ISO14443B_DMA_BUFFER_SIZE;
FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE);
@ -1219,46 +1157,48 @@ void RAMFUNC SnoopIso14443b(void)
bool TagIsActive = false; bool TagIsActive = false;
bool ReaderIsActive = false; bool ReaderIsActive = false;
// We won't start recording the frames that we acquire until we trigger.
// A good trigger condition to get started is probably when we see a
// reader command
bool triggered = false;
// And now we loop, receiving samples. // And now we loop, receiving samples.
for(;;) { for(;;) {
int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1);
(ISO14443B_DMA_BUFFER_SIZE-1);
if(behindBy > maxBehindBy) { if(behindBy > maxBehindBy) {
maxBehindBy = behindBy; maxBehindBy = behindBy;
} }
if(behindBy < 2) continue; if(behindBy < 1) continue;
ci = upTo[0]; ci = *upTo>>8;
cq = upTo[1]; cq = *upTo;
upTo += 2; upTo++;
lastRxCounter -= 2; lastRxCounter--;
if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content.
upTo = dmaBuf; upTo = dmaBuf; // start reading the circular buffer from the beginning again
lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; lastRxCounter += ISO14443B_DMA_BUFFER_SIZE;
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; if(behindBy > (9*ISO14443B_DMA_BUFFER_SIZE/10)) {
AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy);
break;
}
}
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated.
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and
AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; // DMA Next Counter registers
WDT_HIT(); WDT_HIT();
if(behindBy > (9*ISO14443B_DMA_BUFFER_SIZE/10)) { // TODO: understand whether we can increase/decrease as we want or not?
Dbprintf("blew circular buffer! behindBy=%d", behindBy);
break;
}
if(!tracing) {
DbpString("Reached trace limit");
break;
}
if(BUTTON_PRESS()) { if(BUTTON_PRESS()) {
DbpString("cancelled"); DbpString("cancelled");
break; break;
} }
} }
samples += 2; samples++;
if (!TagIsActive) { // no need to try decoding reader data if the tag is sending if (!TagIsActive) { // no need to try decoding reader data if the tag is sending
if(Handle14443bUartBit(ci & 0x01)) { if(Handle14443bUartBit(ci & 0x01)) {
if(triggered && tracing) { triggered = true;
if(tracing) {
LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true); LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true);
} }
/* And ready to receive another command. */ /* And ready to receive another command. */
@ -1268,7 +1208,8 @@ void RAMFUNC SnoopIso14443b(void)
DemodReset(); DemodReset();
} }
if(Handle14443bUartBit(cq & 0x01)) { if(Handle14443bUartBit(cq & 0x01)) {
if(triggered && tracing) { triggered = true;
if(tracing) {
LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true); LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true);
} }
/* And ready to receive another command. */ /* And ready to receive another command. */
@ -1280,8 +1221,8 @@ void RAMFUNC SnoopIso14443b(void)
ReaderIsActive = (Uart.state > STATE_GOT_FALLING_EDGE_OF_SOF); ReaderIsActive = (Uart.state > STATE_GOT_FALLING_EDGE_OF_SOF);
} }
if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending - and we cannot afford the time if(!ReaderIsActive && triggered) { // no need to try decoding tag data if the reader is sending or not yet triggered
if(Handle14443bSamplesDemod(ci | 0x01, cq | 0x01)) { if(Handle14443bSamplesDemod(ci/2, cq/2)) {
//Use samples as a time measurement //Use samples as a time measurement
if(tracing) if(tracing)
@ -1289,8 +1230,6 @@ void RAMFUNC SnoopIso14443b(void)
uint8_t parity[MAX_PARITY_SIZE]; uint8_t parity[MAX_PARITY_SIZE];
LogTrace(Demod.output, Demod.len, samples, samples, parity, false); LogTrace(Demod.output, Demod.len, samples, samples, parity, false);
} }
triggered = true;
// And ready to receive another response. // And ready to receive another response.
DemodReset(); DemodReset();
} }
@ -1301,7 +1240,6 @@ void RAMFUNC SnoopIso14443b(void)
FpgaDisableSscDma(); FpgaDisableSscDma();
LEDsoff(); LEDsoff();
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
DbpString("Snoop statistics:"); DbpString("Snoop statistics:");
Dbprintf(" Max behind by: %i", maxBehindBy); Dbprintf(" Max behind by: %i", maxBehindBy);
Dbprintf(" Uart State: %x", Uart.state); Dbprintf(" Uart State: %x", Uart.state);
@ -1327,7 +1265,11 @@ void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, u
{ {
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc();
// switch field on and give tag some time to power up
LED_D_ON();
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX);
SpinDelay(10);
if (datalen){ if (datalen){
set_tracing(true); set_tracing(true);

View file

@ -227,26 +227,14 @@ static void TransmitTo15693Tag(const uint8_t *cmd, int len, int *samples, int *w
{ {
int c; int c;
// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
if(*wait < 10) { *wait = 10; } if(*wait < 10) { *wait = 10; }
// for(c = 0; c < *wait;) {
// if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
// AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing!
// c++;
// }
// if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
// volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
// (void)r;
// }
// WDT_HIT();
// }
c = 0; c = 0;
for(;;) { for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = cmd[c]; AT91C_BASE_SSC->SSC_THR = ~cmd[c];
c++; c++;
if(c >= len) { if(c >= len) {
break; break;
@ -300,36 +288,25 @@ static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int *
{ {
int c = 0; int c = 0;
uint8_t *dest = BigBuf_get_addr(); uint8_t *dest = BigBuf_get_addr();
int getNext = 0;
int8_t prev = 0;
// NOW READ RESPONSE // NOW READ RESPONSE
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
c = 0; c = 0;
getNext = false;
for(;;) { for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
int8_t b; uint16_t iq = AT91C_BASE_SSC->SSC_RHR;
b = (int8_t)AT91C_BASE_SSC->SSC_RHR;
// The samples are correlations against I and Q versions of the // The samples are correlations against I and Q versions of the
// tone that the tag AM-modulates, so every other sample is I, // tone that the tag AM-modulates. We just want power.
// every other is Q. We just want power, so abs(I) + abs(Q) is int8_t i = iq >> 8;
// close to what we want. int8_t q = iq;
if(getNext) { uint8_t r = AMPLITUDE(i, q);
uint8_t r = AMPLITUDE(b, prev);
dest[c++] = r; dest[c++] = r;
if(c >= 4000) { if(c >= 4000) {
break; break;
}
} else {
prev = b;
} }
getNext = !getNext;
} }
} }
@ -441,36 +418,26 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int
{ {
int c = 0; int c = 0;
uint8_t *dest = BigBuf_get_addr(); uint8_t *dest = BigBuf_get_addr();
int getNext = 0;
int8_t prev = 0;
// NOW READ RESPONSE // NOW READ RESPONSE
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
//spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads
c = 0; c = 0;
getNext = false;
for(;;) { for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
int8_t b = (int8_t)AT91C_BASE_SSC->SSC_RHR; uint16_t iq = AT91C_BASE_SSC->SSC_RHR;
// The samples are correlations against I and Q versions of the // The samples are correlations against I and Q versions of the
// tone that the tag AM-modulates, so every other sample is I, // tone that the tag AM-modulates. We just want power,
// every other is Q. We just want power, so abs(I) + abs(Q) is // so abs(I) + abs(Q) is close to what we want.
// close to what we want. int8_t i = iq >> 8;
if(getNext) { int8_t q = iq;
uint8_t r = AMPLITUDE(b, prev); uint8_t r = AMPLITUDE(i, q);
dest[c++] = r; dest[c++] = r;
if(c >= BIGBUF_SIZE) { if(c >= BIGBUF_SIZE) {
break; break;
}
} else {
prev = b;
} }
getNext = !getNext;
} }
} }
@ -585,8 +552,6 @@ void AcquireRawAdcSamplesIso15693(void)
uint8_t *dest = BigBuf_get_addr(); uint8_t *dest = BigBuf_get_addr();
int c = 0; int c = 0;
int getNext = 0;
int8_t prev = 0;
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
BuildIdentifyRequest(); BuildIdentifyRequest();
@ -598,13 +563,13 @@ void AcquireRawAdcSamplesIso15693(void)
SpinDelay(100); SpinDelay(100);
// Now send the command // Now send the command
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
c = 0; c = 0;
for(;;) { for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = ToSend[c]; AT91C_BASE_SSC->SSC_THR = ~ToSend[c];
c++; c++;
if(c == ToSendMax+3) { if(c == ToSendMax+3) {
break; break;
@ -613,32 +578,25 @@ void AcquireRawAdcSamplesIso15693(void)
WDT_HIT(); WDT_HIT();
} }
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
c = 0; c = 0;
getNext = false;
for(;;) { for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
int8_t b; uint16_t iq = AT91C_BASE_SSC->SSC_RHR;
b = (int8_t)AT91C_BASE_SSC->SSC_RHR;
// The samples are correlations against I and Q versions of the // The samples are correlations against I and Q versions of the
// tone that the tag AM-modulates, so every other sample is I, // tone that the tag AM-modulates. We just want power,
// every other is Q. We just want power, so abs(I) + abs(Q) is // so abs(I) + abs(Q) is close to what we want.
// close to what we want. int8_t i = iq >> 8;
if(getNext) { int8_t q = iq;
uint8_t r = AMPLITUDE(b, prev); uint8_t r = AMPLITUDE(i, q);
dest[c++] = r; dest[c++] = r;
if(c >= 4000) { if(c >= 4000) {
break; break;
}
} else {
prev = b;
} }
getNext = !getNext;
} }
} }
} }
@ -649,16 +607,14 @@ void RecordRawAdcSamplesIso15693(void)
uint8_t *dest = BigBuf_get_addr(); uint8_t *dest = BigBuf_get_addr();
int c = 0; int c = 0;
int getNext = 0;
int8_t prev = 0;
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Setup SSC // Setup SSC
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
// Start from off (no field generated) // Start from off (no field generated)
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(200); SpinDelay(200);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
@ -667,33 +623,24 @@ void RecordRawAdcSamplesIso15693(void)
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
c = 0; c = 0;
getNext = false;
for(;;) { for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
int8_t b; uint16_t iq = AT91C_BASE_SSC->SSC_RHR;
b = (int8_t)AT91C_BASE_SSC->SSC_RHR;
// The samples are correlations against I and Q versions of the // The samples are correlations against I and Q versions of the
// tone that the tag AM-modulates, so every other sample is I, // tone that the tag AM-modulates. We just want power,
// every other is Q. We just want power, so abs(I) + abs(Q) is // so abs(I) + abs(Q) is close to what we want.
// close to what we want. int8_t i = iq >> 8;
if(getNext) { int8_t q = iq;
uint8_t r = AMPLITUDE(b, prev); uint8_t r = AMPLITUDE(i, q);
dest[c++] = r; dest[c++] = r;
if(c >= 14000) { if(c >= 14000) {
break; break;
}
} else {
prev = b;
} }
getNext = !getNext;
WDT_HIT();
} }
} }
Dbprintf("fin record"); Dbprintf("finished recording");
} }
@ -714,7 +661,7 @@ void Iso15693InitReader() {
SpinDelay(10); SpinDelay(10);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
// Give the tags time to energize // Give the tags time to energize
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
@ -973,7 +920,7 @@ void ReaderIso15693(uint32_t parameter)
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Setup SSC // Setup SSC
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
// Start from off (no field generated) // Start from off (no field generated)
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
@ -1075,7 +1022,7 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid)
memset(buf, 0x00, 100); memset(buf, 0x00, 100);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
// Start from off (no field generated) // Start from off (no field generated)
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);

View file

@ -63,11 +63,11 @@ static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */
// I/O interface abstraction (FPGA -> ARM) // I/O interface abstraction (FPGA -> ARM)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static inline uint8_t rx_byte_from_fpga() { static inline uint16_t rx_frame_from_fpga() {
for(;;) { for(;;) {
WDT_HIT(); WDT_HIT();
// wait for byte be become available in rx holding register // wait for frame be become available in rx holding register
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
return AT91C_BASE_SSC->SSC_RHR; return AT91C_BASE_SSC->SSC_RHR;
} }
@ -88,33 +88,32 @@ static inline uint8_t rx_byte_from_fpga() {
// To reduce CPU time the amplitude is approximated by using linear functions: // To reduce CPU time the amplitude is approximated by using linear functions:
// am = MAX(ABS(i),ABS(q)) + 1/2*MIN(ABS(i),ABSq)) // am = MAX(ABS(i),ABS(q)) + 1/2*MIN(ABS(i),ABSq))
// //
// Note: The SSC receiver is never synchronized the calculation my be performed
// on a I/Q pair from two subsequent correlations, but does not matter.
//
// The bit time is 99.1us (21 I/Q pairs). The receiver skips the first 5 samples // The bit time is 99.1us (21 I/Q pairs). The receiver skips the first 5 samples
// and averages the next (most stable) 8 samples. The final 8 samples are dropped // and averages the next (most stable) 8 samples. The final 8 samples are dropped
// also. // also.
// //
// The demedulated should be alligned to the bit periode by the caller. This is // The demodulated should be alligned to the bit period by the caller. This is
// done in rx_bit and rx_ack. // done in rx_bit and rx_ack.
static inline bool rx_bit() { static inline bool rx_bit() {
int32_t cq = 0; int32_t sum_cq = 0;
int32_t ci = 0; int32_t sum_ci = 0;
// skip first 5 I/Q pairs // skip first 5 I/Q pairs
for(size_t i = 0; i<5; ++i) { for(size_t i = 0; i<5; ++i) {
(int8_t)rx_byte_from_fpga(); (void)rx_frame_from_fpga();
(int8_t)rx_byte_from_fpga();
} }
// sample next 8 I/Q pairs // sample next 8 I/Q pairs
for(size_t i = 0; i<8; ++i) { for(size_t i = 0; i<8; ++i) {
cq += (int8_t)rx_byte_from_fpga(); uint16_t iq = rx_frame_from_fpga();
ci += (int8_t)rx_byte_from_fpga(); int8_t ci = (int8_t)(iq >> 8);
int8_t cq = (int8_t)(iq & 0xff);
sum_ci += ci;
sum_cq += cq;
} }
// calculate power // calculate power
int32_t power = (MAX(ABS(ci), ABS(cq)) + (MIN(ABS(ci), ABS(cq)) >> 1)); int32_t power = (MAX(ABS(sum_ci), ABS(sum_cq)) + MIN(ABS(sum_ci), ABS(sum_cq))/2);
// compare average (power / 8) to threshold // compare average (power / 8) to threshold
return ((power >> 3) > INPUT_THRESHOLD); return ((power >> 3) > INPUT_THRESHOLD);
@ -131,12 +130,12 @@ static inline bool rx_bit() {
static inline void tx_bit(bool bit) { static inline void tx_bit(bool bit) {
// insert pause // insert pause
LOW(GPIO_SSC_DOUT); HIGH(GPIO_SSC_DOUT);
last_frame_end += RWD_TIME_PAUSE; last_frame_end += RWD_TIME_PAUSE;
while(GET_TICKS < last_frame_end) { }; while(GET_TICKS < last_frame_end) { };
HIGH(GPIO_SSC_DOUT);
// return to high, wait for bit periode to end // return to carrier on, wait for bit periode to end
LOW(GPIO_SSC_DOUT);
last_frame_end += (bit ? RWD_TIME_1 : RWD_TIME_0) - RWD_TIME_PAUSE; last_frame_end += (bit ? RWD_TIME_1 : RWD_TIME_0) - RWD_TIME_PAUSE;
while(GET_TICKS < last_frame_end) { }; while(GET_TICKS < last_frame_end) { };
} }
@ -166,10 +165,10 @@ static void tx_frame(uint32_t frame, uint8_t len) {
}; };
// add pause to mark end of the frame // add pause to mark end of the frame
LOW(GPIO_SSC_DOUT); HIGH(GPIO_SSC_DOUT);
last_frame_end += RWD_TIME_PAUSE; last_frame_end += RWD_TIME_PAUSE;
while(GET_TICKS < last_frame_end) { }; while(GET_TICKS < last_frame_end) { };
HIGH(GPIO_SSC_DOUT); LOW(GPIO_SSC_DOUT);
} }
static uint32_t rx_frame(uint8_t len) { static uint32_t rx_frame(uint8_t len) {
@ -265,12 +264,12 @@ static void init_reader(bool clear_mem) {
LED_D_ON(); LED_D_ON();
// configure SSC with defaults // configure SSC with defaults
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
// re-claim GPIO_SSC_DOUT as GPIO and enable output // re-claim GPIO_SSC_DOUT as GPIO and enable output
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
HIGH(GPIO_SSC_DOUT); LOW(GPIO_SSC_DOUT);
// init crc calculator // init crc calculator
crc_init(&legic_crc, 4, 0x19 >> 1, 0x05, 0); crc_init(&legic_crc, 4, 0x19 >> 1, 0x05, 0);

View file

@ -284,7 +284,7 @@ static void init_tag() {
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// configure SSC with defaults // configure SSC with defaults
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
// first pull output to low to prevent glitches then re-claim GPIO_SSC_DOUT // first pull output to low to prevent glitches then re-claim GPIO_SSC_DOUT
LOW(GPIO_SSC_DOUT); LOW(GPIO_SSC_DOUT);

View file

@ -1818,7 +1818,7 @@ void Cotag(uint32_t arg0) {
SetAdcMuxFor(GPIO_MUXSEL_LOPKD); SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// Now set up the SSC to get the ADC samples that are now streaming at us. // Now set up the SSC to get the ADC samples that are now streaming at us.
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_LF_ADC);
// start clock - 1.5ticks is 1us // start clock - 1.5ticks is 1us
StartTicks(); StartTicks();

View file

@ -101,7 +101,7 @@ void LFSetupFPGAForADC(int divisor, bool lf_field)
// Give it a bit of time for the resonant antenna to settle. // Give it a bit of time for the resonant antenna to settle.
SpinDelay(50); SpinDelay(50);
// Now set up the SSC to get the ADC samples that are now streaming at us. // Now set up the SSC to get the ADC samples that are now streaming at us.
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_LF_ADC);
} }
/** /**

Binary file not shown.

View file

@ -197,9 +197,9 @@ begin
end end
end end
// set ssp_frame signal for corr_i_cnt = 0..3 and corr_i_cnt = 32..35 // set ssp_frame signal for corr_i_cnt = 0..3
// (send two frames with 8 Bits each) // (send one frame with 16 Bits)
if(corr_i_cnt[5:2] == 4'b0000 || corr_i_cnt[5:2] == 4'b1000) if(corr_i_cnt[5:2] == 4'b0000)
ssp_frame = 1'b1; ssp_frame = 1'b1;
else else
ssp_frame = 1'b0; ssp_frame = 1'b0;

View file

@ -42,11 +42,11 @@ begin
pwr_hi <= ck_1356megb; pwr_hi <= ck_1356megb;
pwr_oe1 <= 1'b0; pwr_oe1 <= 1'b0;
pwr_oe3 <= 1'b0; pwr_oe3 <= 1'b0;
pwr_oe4 <= ~ssp_dout; pwr_oe4 <= ssp_dout;
end end
else else
begin begin
pwr_hi <= ck_1356megb & ssp_dout; pwr_hi <= ck_1356megb & ~ssp_dout;
pwr_oe1 <= 1'b0; pwr_oe1 <= 1'b0;
pwr_oe3 <= 1'b0; pwr_oe3 <= 1'b0;
pwr_oe4 <= 1'b0; pwr_oe4 <= 1'b0;