From 7a53739728caea10b0857596fe3e30606295e8b4 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Fri, 6 Mar 2020 17:14:35 +0100 Subject: [PATCH] fixing some fpga and iclass issues * make fpga_version_info.c phony and delete it on 'make clean' * wait for transfer to complete before returning from FpgaSendCommand() * log correct tag times in iclass simulation * shorten pulse from TC1 to TC0 in StartCountSspClk() * shorten ssp_frame pulse in fpga/hi_reader.v * some reformatting and whitespace fixes --- armsrc/Makefile | 7 +- armsrc/appmain.c | 6 +- armsrc/fpgaloader.c | 149 ++++++++++++------------- armsrc/fpgaloader.h | 12 +- armsrc/iclass.c | 19 +--- armsrc/iso15693.c | 61 +++++----- armsrc/iso15693.h | 33 +++--- armsrc/util.c | 41 +++---- common/Makefile_Enabled_Options.common | 2 +- fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/hi_reader.v | 22 +++- 11 files changed, 169 insertions(+), 183 deletions(-) diff --git a/armsrc/Makefile b/armsrc/Makefile index 7b9e1356..f4ad2ad6 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -83,8 +83,9 @@ all: $(OBJS) .DELETE_ON_ERROR: -# version.c should be remade on every compilation -.PHONY: version.c +# version.c and fpga_version_info.c to be remade on every compilation +.PHONY: version.c fpga_version_info.c + version.c: default_version.c perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@ @@ -132,7 +133,7 @@ clean: $(DELETE) $(OBJDIR)$(PATHSEP)*.d $(DELETE) $(OBJDIR)$(PATHSEP)*.z $(DELETE) $(OBJDIR)$(PATHSEP)*.bin - $(DELETE) version.c + $(DELETE) version.c fpga_version_info.c .PHONY: all clean help help: diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 4f0a19b9..56bf67e0 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1467,13 +1467,13 @@ void __attribute__((noreturn)) AppMain(void) { // Reset SPI AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST; + AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST; // required twice on some AT91SAM Revisions (see Errata in AT91SAM datasheet) // Reset SSC AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; - // Load the FPGA image, which we have stored in our flash. - // (the HF version by default) + // Load the FPGA image, which we have stored in our flash (HF version by default) FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - + StartTickCount(); #ifdef WITH_LCD diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index 8693d6b5..61db66d3 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -32,7 +32,7 @@ extern uint8_t _binary_obj_fpga_all_bit_z_start, _binary_obj_fpga_all_bit_z_end; static uint8_t *fpga_image_ptr = NULL; static uint32_t uncompressed_bytes_cnt; -#define OUTPUT_BUFFER_LEN 80 +#define OUTPUT_BUFFER_LEN 80 //----------------------------------------------------------------------------- // Set up the Serial Peripheral Interface as master @@ -49,16 +49,16 @@ void SetupSpi(int mode) // Disable PIO control of the following pins, allows use by the SPI peripheral AT91C_BASE_PIOA->PIO_PDR = - GPIO_NCS0 | - GPIO_NCS2 | - GPIO_MISO | - GPIO_MOSI | + GPIO_NCS0 | + GPIO_NCS2 | + GPIO_MISO | + GPIO_MOSI | GPIO_SPCK; AT91C_BASE_PIOA->PIO_ASR = - GPIO_NCS0 | - GPIO_MISO | - GPIO_MOSI | + GPIO_NCS0 | + GPIO_MISO | + GPIO_MOSI | GPIO_SPCK; AT91C_BASE_PIOA->PIO_BSR = GPIO_NCS2; @@ -71,41 +71,41 @@ void SetupSpi(int mode) switch (mode) { case SPI_FPGA_MODE: AT91C_BASE_SPI->SPI_MR = - ( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods) - (14 << 16) | // Peripheral Chip Select (selects FPGA SPI_NCS0 or PA11) - ( 0 << 7) | // Local Loopback Disabled - ( 1 << 4) | // Mode Fault Detection disabled - ( 0 << 2) | // Chip selects connected directly to peripheral - ( 0 << 1) | // Fixed Peripheral Select - ( 1 << 0); // Master Mode + ( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods) + (14 << 16) | // Peripheral Chip Select (selects FPGA SPI_NCS0 or PA11) + ( 0 << 7) | // Local Loopback Disabled + ( 1 << 4) | // Mode Fault Detection disabled + ( 0 << 2) | // Chip selects connected directly to peripheral + ( 0 << 1) | // Fixed Peripheral Select + ( 1 << 0); // Master Mode AT91C_BASE_SPI->SPI_CSR[0] = - ( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods) - ( 1 << 16) | // Delay Before SPCK (1 MCK period) - ( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud - ( 8 << 4) | // Bits per Transfer (16 bits) - ( 0 << 3) | // Chip Select inactive after transfer - ( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge - ( 0 << 0); // Clock Polarity inactive state is logic 0 + ( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods) + ( 1 << 16) | // Delay Before SPCK (1 MCK period) + ( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud + ( 8 << 4) | // Bits per Transfer (16 bits) + ( 0 << 3) | // Chip Select inactive after transfer + ( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge + ( 0 << 0); // Clock Polarity inactive state is logic 0 break; case SPI_LCD_MODE: AT91C_BASE_SPI->SPI_MR = - ( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods) - (11 << 16) | // Peripheral Chip Select (selects LCD SPI_NCS2 or PA10) - ( 0 << 7) | // Local Loopback Disabled - ( 1 << 4) | // Mode Fault Detection disabled - ( 0 << 2) | // Chip selects connected directly to peripheral - ( 0 << 1) | // Fixed Peripheral Select - ( 1 << 0); // Master Mode + ( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods) + (11 << 16) | // Peripheral Chip Select (selects LCD SPI_NCS2 or PA10) + ( 0 << 7) | // Local Loopback Disabled + ( 1 << 4) | // Mode Fault Detection disabled + ( 0 << 2) | // Chip selects connected directly to peripheral + ( 0 << 1) | // Fixed Peripheral Select + ( 1 << 0); // Master Mode AT91C_BASE_SPI->SPI_CSR[2] = - ( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods) - ( 1 << 16) | // Delay Before SPCK (1 MCK period) - ( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud - ( 1 << 4) | // Bits per Transfer (9 bits) - ( 0 << 3) | // Chip Select inactive after transfer - ( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge - ( 0 << 0); // Clock Polarity inactive state is logic 0 + ( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods) + ( 1 << 16) | // Delay Before SPCK (1 MCK period) + ( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud + ( 1 << 4) | // Bits per Transfer (9 bits) + ( 0 << 3) | // Chip Select inactive after transfer + ( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge + ( 0 << 0); // Clock Polarity inactive state is logic 0 break; - default: // Disable SPI + default: // Disable SPI AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS; break; } @@ -118,9 +118,9 @@ void SetupSpi(int mode) void FpgaSetupSsc(uint16_t FPGA_mode) { // First configure the GPIOs, and get ourselves a clock. AT91C_BASE_PIOA->PIO_ASR = - GPIO_SSC_FRAME | - GPIO_SSC_DIN | - GPIO_SSC_DOUT | + GPIO_SSC_FRAME | + GPIO_SSC_DIN | + GPIO_SSC_DOUT | GPIO_SSC_CLK; AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT; @@ -135,14 +135,14 @@ void FpgaSetupSsc(uint16_t FPGA_mode) { // 8, 16 or 32 bits per transfer, no loopback, MSB first, 1 transfer per sync // pulse, no output sync - if ((FPGA_mode & 0x1c0) == FPGA_MAJOR_MODE_HF_READER && FpgaGetCurrent() == FPGA_BITSTREAM_HF) { + if ((FPGA_mode & FPGA_MAJOR_MODE_MASK) == FPGA_MAJOR_MODE_HF_READER && FpgaGetCurrent() == FPGA_BITSTREAM_HF) { 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); - } + } - // TX clock comes from TK pin, no clock output, outputs change on falling - // edge of TK, frame sync is sampled on rising edge of TK, start TX on rising edge of TF + // TX clock comes from TK pin, no clock output, outputs change on rising edge of TK, + // TF (frame sync) is sampled on falling edge of TK, start TX on rising edge of TF AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5); // tx framing is the same as the rx framing @@ -157,8 +157,7 @@ void FpgaSetupSsc(uint16_t FPGA_mode) { // ourselves, not to another buffer). The stuff to manipulate those buffers // is in apps.h, because it should be inlined, for speed. //----------------------------------------------------------------------------- -bool FpgaSetupSscDma(uint8_t *buf, uint16_t sample_count) -{ +bool FpgaSetupSscDma(uint8_t *buf, uint16_t sample_count) { if (buf == NULL) return false; AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; // Disable DMA Transfer @@ -173,11 +172,11 @@ bool FpgaSetupSscDma(uint8_t *buf, uint16_t sample_count) //---------------------------------------------------------------------------- // Uncompress (inflate) the FPGA data. Returns one decompressed byte with -// each call. +// each call. //---------------------------------------------------------------------------- static int get_from_fpga_combined_stream(z_streamp compressed_fpga_stream, uint8_t *output_buffer) { - if (fpga_image_ptr == compressed_fpga_stream->next_out) { // need more data + if (fpga_image_ptr == compressed_fpga_stream->next_out) { // need more data compressed_fpga_stream->next_out = output_buffer; compressed_fpga_stream->avail_out = OUTPUT_BUFFER_LEN; fpga_image_ptr = output_buffer; @@ -190,7 +189,7 @@ static int get_from_fpga_combined_stream(z_streamp compressed_fpga_stream, uint8 } uncompressed_bytes_cnt++; - + return *fpga_image_ptr++; } @@ -207,7 +206,7 @@ static int get_from_fpga_stream(int bitstream_version, z_streamp compressed_fpga } return get_from_fpga_combined_stream(compressed_fpga_stream, output_buffer); - + } @@ -224,14 +223,14 @@ static void fpga_inflate_free(voidpf opaque, voidpf address) //---------------------------------------------------------------------------- -// Initialize decompression of the respective (HF or LF) FPGA stream +// Initialize decompression of the respective (HF or LF) FPGA stream //---------------------------------------------------------------------------- static bool reset_fpga_stream(int bitstream_version, z_streamp compressed_fpga_stream, uint8_t *output_buffer) { uint8_t header[FPGA_BITSTREAM_FIXED_HEADER_SIZE]; - + uncompressed_bytes_cnt = 0; - + // initialize z_stream structure for inflate: compressed_fpga_stream->next_in = &_binary_obj_fpga_all_bit_z_start; compressed_fpga_stream->avail_in = &_binary_obj_fpga_all_bit_z_end - &_binary_obj_fpga_all_bit_z_start; @@ -247,7 +246,7 @@ static bool reset_fpga_stream(int bitstream_version, z_streamp compressed_fpga_s for (uint16_t i = 0; i < FPGA_BITSTREAM_FIXED_HEADER_SIZE; i++) { header[i] = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer); } - + // Check for a valid .bit file (starts with bitparse_fixed_header) if(memcmp(bitparse_fixed_header, header, FPGA_BITSTREAM_FIXED_HEADER_SIZE) == 0) { return true; @@ -275,25 +274,25 @@ static void DownloadFPGA(int bitstream_version, int FpgaImageLen, z_streamp comp { //Dbprintf("DownloadFPGA(len: %d)", FpgaImageLen); - + int i=0; AT91C_BASE_PIOA->PIO_OER = GPIO_FPGA_ON; AT91C_BASE_PIOA->PIO_PER = GPIO_FPGA_ON; - HIGH(GPIO_FPGA_ON); // ensure everything is powered on + HIGH(GPIO_FPGA_ON); // ensure everything is powered on SpinDelay(50); LED_D_ON(); // These pins are inputs - AT91C_BASE_PIOA->PIO_ODR = - GPIO_FPGA_NINIT | - GPIO_FPGA_DONE; + AT91C_BASE_PIOA->PIO_ODR = + GPIO_FPGA_NINIT | + GPIO_FPGA_DONE; // PIO controls the following pins - AT91C_BASE_PIOA->PIO_PER = - GPIO_FPGA_NINIT | - GPIO_FPGA_DONE; + AT91C_BASE_PIOA->PIO_PER = + GPIO_FPGA_NINIT | + GPIO_FPGA_DONE; // Enable pull-ups AT91C_BASE_PIOA->PIO_PPUER = GPIO_FPGA_NINIT | @@ -305,8 +304,8 @@ static void DownloadFPGA(int bitstream_version, int FpgaImageLen, z_streamp comp LOW(GPIO_FPGA_DIN); // These pins are outputs AT91C_BASE_PIOA->PIO_OER = - GPIO_FPGA_NPROGRAM | - GPIO_FPGA_CCLK | + GPIO_FPGA_NPROGRAM | + GPIO_FPGA_CCLK | GPIO_FPGA_DIN; // enter FPGA configuration mode @@ -335,7 +334,7 @@ static void DownloadFPGA(int bitstream_version, int FpgaImageLen, z_streamp comp } DownloadFPGA_byte(b); } - + // continue to clock FPGA until ready signal goes high i=100000; while ( (i--) && ( !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_FPGA_DONE ) ) ) { @@ -407,14 +406,14 @@ static int bitparse_find_section(int bitstream_version, char section_name, unsig //---------------------------------------------------------------------------- -// Check which FPGA image is currently loaded (if any). If necessary +// Check which FPGA image is currently loaded (if any). If necessary // decompress and load the correct (HF or LF) image to the FPGA //---------------------------------------------------------------------------- void FpgaDownloadAndGo(int bitstream_version) { z_stream compressed_fpga_stream; uint8_t output_buffer[OUTPUT_BUFFER_LEN] = {0x00}; - + // check whether or not the bitstream is already loaded if (downloaded_bitstream == bitstream_version) { FpgaEnableTracing(); @@ -422,8 +421,8 @@ void FpgaDownloadAndGo(int bitstream_version) } // make sure that we have enough memory to decompress - BigBuf_free(); BigBuf_Clear_ext(false); - + BigBuf_free(); BigBuf_Clear_ext(false); + if (!reset_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer)) { return; } @@ -435,13 +434,13 @@ void FpgaDownloadAndGo(int bitstream_version) } inflateEnd(&compressed_fpga_stream); - + // turn off antenna FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - + // free eventually allocated BigBuf memory - BigBuf_free(); BigBuf_Clear_ext(false); -} + BigBuf_free(); BigBuf_Clear_ext(false); +} //----------------------------------------------------------------------------- @@ -451,8 +450,8 @@ void FpgaDownloadAndGo(int bitstream_version) //----------------------------------------------------------------------------- void FpgaSendCommand(uint16_t cmd, uint16_t v) { SetupSpi(SPI_FPGA_MODE); - while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete - AT91C_BASE_SPI->SPI_TDR = AT91C_SPI_LASTXFER | cmd | v; // send the data + AT91C_BASE_SPI->SPI_TDR = AT91C_SPI_LASTXFER | cmd | v; // write the data to be sent + while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete } //----------------------------------------------------------------------------- diff --git a/armsrc/fpgaloader.h b/armsrc/fpgaloader.h index 9746638d..57e9c28a 100644 --- a/armsrc/fpgaloader.h +++ b/armsrc/fpgaloader.h @@ -35,16 +35,17 @@ void SetAdcMuxFor(uint32_t whichGpio); #define FPGA_BITSTREAM_HF 2 // Definitions for the FPGA commands. +#define FPGA_CMD_MASK 0xF000 // BOTH -#define FPGA_CMD_SET_CONFREG (1<<12) +#define FPGA_CMD_SET_CONFREG (1<<12) // LF -#define FPGA_CMD_SET_DIVISOR (2<<12) -#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD (3<<12) - +#define FPGA_CMD_SET_DIVISOR (2<<12) +#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD (3<<12) // HF -#define FPGA_CMD_TRACE_ENABLE (2<<12) +#define FPGA_CMD_TRACE_ENABLE (2<<12) // Definitions for the FPGA configuration word. +#define FPGA_MAJOR_MODE_MASK 0x01C0 // LF #define FPGA_MAJOR_MODE_LF_ADC (0<<6) #define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<6) @@ -58,6 +59,7 @@ void SetAdcMuxFor(uint32_t whichGpio); // BOTH #define FPGA_MAJOR_MODE_OFF (7<<6) +#define FPGA_MINOR_MODE_MASK 0x003F // Options for LF_ADC #define FPGA_LF_ADC_READER_FIELD (1<<0) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index afe1a607..3f89ae85 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -538,7 +538,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { if (modulated_response_size > 0) { uint32_t response_time = reader_eof_time + DELAY_ICLASS_VCD_TO_VICC_SIM; TransmitTo15693Reader(modulated_response, modulated_response_size, &response_time, 0, false); - LogTrace_ISO15693(trace_data, trace_data_size, response_time*32, response_time*32 + modulated_response_size/2, NULL, false); + LogTrace_ISO15693(trace_data, trace_data_size, response_time*32, response_time*32 + modulated_response_size*32*64, NULL, false); } } @@ -566,17 +566,11 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain LED_A_ON(); + Iso15693InitTag(); + uint32_t simType = arg0; uint32_t numberOfCSNS = arg1; - // setup hardware for simulation: - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); - LED_D_OFF(); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); - StartCountSspClk(); - // Enable and clear the trace set_tracing(true); clear_trace(); @@ -589,9 +583,8 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain doIClassSimulation(ICLASS_SIM_MODE_CSN, NULL); } else if (simType == ICLASS_SIM_MODE_CSN_DEFAULT) { //Default CSN - uint8_t csn_crc[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 }; - // Use the CSN from commandline - memcpy(emulator, csn_crc, 8); + uint8_t csn[] = {0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0}; + memcpy(emulator, csn, 8); doIClassSimulation(ICLASS_SIM_MODE_CSN, NULL); } else if (simType == ICLASS_SIM_MODE_READER_ATTACK) { uint8_t mac_responses[USB_CMD_DATA_SIZE] = { 0 }; @@ -636,9 +629,7 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain static void ReaderTransmitIClass(uint8_t *frame, int len, uint32_t *start_time) { CodeIso15693AsReader(frame, len); - TransmitTo15693Tag(ToSend, ToSendMax, start_time); - uint32_t end_time = *start_time + 32*(8*ToSendMax-4); // substract the 4 padding bits after EOF LogTrace_ISO15693(frame, len, *start_time*4, end_time*4, NULL, true); } diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 9f6516aa..5672e66d 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -291,7 +291,6 @@ void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) { AT91C_BASE_SSC->SSC_THR = send_word; while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; AT91C_BASE_SSC->SSC_THR = send_word; - data <<= 1; } WDT_HIT(); @@ -299,7 +298,6 @@ void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) { LED_B_OFF(); *start_time = *start_time + DELAY_ARM_TO_TAG; - } @@ -1357,20 +1355,23 @@ void SnoopIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { // Initialize the proxmark as iso15k reader -void Iso15693InitReader() { +void Iso15693InitReader(void) { FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - // Start from off (no field generated) - LED_D_OFF(); + // switch field off and wait until tag resets FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); SpinDelay(10); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + // switch field on + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); + LED_D_ON(); + + // initialize SSC and select proper AD input FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - // Give the tags time to energize - LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); + // give tags some time to energize SpinDelay(250); } @@ -1570,29 +1571,14 @@ void ReaderIso15693(uint32_t parameter) { LED_A_ON(); + Iso15693InitReader(); + + StartCountSspClk(); set_tracing(true); uint8_t TagUID[8] = {0x00}; - - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - uint8_t answer[ISO15693_MAX_RESPONSE_LENGTH]; - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - // Setup SSC - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); - - // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); - - // Give the tags time to energize - LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); - SpinDelay(200); - StartCountSspClk(); - - // FIRST WE RUN AN INVENTORY TO GET THE TAG UID // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME @@ -1650,6 +1636,17 @@ void ReaderIso15693(uint32_t parameter) { } +// Initialize the proxmark as iso15k tag +void Iso15693InitTag(void) { + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); + LED_D_OFF(); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); + StartCountSspClk(); +} + + // Simulate an ISO15693 TAG. // For Inventory command: print command and send Inventory Response with given UID // TODO: interpret other reader commands and send appropriate response @@ -1657,20 +1654,14 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) { LED_A_ON(); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); - - StartCountSspClk(); - - uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; + Iso15693InitTag(); // Build a suitable response to the reader INVENTORY command BuildInventoryResponse(uid); // Listen to reader while (!BUTTON_PRESS()) { + uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; uint32_t eof_time = 0, start_time = 0; int cmd_len = GetIso15693CommandFromReader(cmd, sizeof(cmd), &eof_time); diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h index e48e4d4a..15dfe763 100644 --- a/armsrc/iso15693.h +++ b/armsrc/iso15693.h @@ -22,21 +22,22 @@ #define DELAY_ISO15693_VCD_TO_VICC_READER 1056 // 1056/3,39MHz = 311.5us from end of command EOF to start of tag response #define DELAY_ISO15693_VICC_TO_VCD_READER 1024 // 1024/3.39MHz = 302.1us between end of tag response and next reader command -void Iso15693InitReader(); -void CodeIso15693AsReader(uint8_t *cmd, int n); -void CodeIso15693AsTag(uint8_t *cmd, size_t len); -void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint32_t slot_time, bool slow); -int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time); -void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time); -int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time); -void SnoopIso15693(uint8_t jam_search_len, uint8_t *jam_search_string); -void AcquireRawAdcSamplesIso15693(void); -void ReaderIso15693(uint32_t parameter); -void SimTagIso15693(uint32_t parameter, uint8_t *uid); -void BruteforceIso15693Afi(uint32_t speed); -void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t data[]); -void SetTag15693Uid(uint8_t *uid); -void SetDebugIso15693(uint32_t flag); -bool LogTrace_ISO15693(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag); +extern void Iso15693InitReader(void); +extern void Iso15693InitTag(void); +extern void CodeIso15693AsReader(uint8_t *cmd, int n); +extern void CodeIso15693AsTag(uint8_t *cmd, size_t len); +extern void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint32_t slot_time, bool slow); +extern int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time); +extern void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time); +extern int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time); +extern void SnoopIso15693(uint8_t jam_search_len, uint8_t *jam_search_string); +extern void AcquireRawAdcSamplesIso15693(void); +extern void ReaderIso15693(uint32_t parameter); +extern void SimTagIso15693(uint32_t parameter, uint8_t *uid); +extern void BruteforceIso15693Afi(uint32_t speed); +extern void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t data[]); +extern void SetTag15693Uid(uint8_t *uid); +extern void SetDebugIso15693(uint32_t flag); +extern bool LogTrace_ISO15693(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag); #endif diff --git a/armsrc/util.c b/armsrc/util.c index 4bff3a26..b0cd1818 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -137,8 +137,7 @@ void LED(int led, int ms) // not clicked, or held down (for ms || 1sec) // In general, don't use this function unless you expect a // double click, otherwise it will waste 500ms -- use BUTTON_HELD instead -int BUTTON_CLICKED(int ms) -{ +int BUTTON_CLICKED(int ms) { // Up to 500ms in between clicks to mean a double click int ticks = (48000 * (ms ? ms : 1000)) >> 10; @@ -200,8 +199,7 @@ int BUTTON_CLICKED(int ms) } // Determine if a button is held down -int BUTTON_HELD(int ms) -{ +int BUTTON_HELD(int ms) { // If button is held for one second int ticks = (48000 * (ms ? ms : 1000)) >> 10; @@ -218,8 +216,7 @@ int BUTTON_HELD(int ms) uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; - for(;;) - { + for(;;) { uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; // As soon as our button let go, we didn't hold long enough @@ -227,8 +224,7 @@ int BUTTON_HELD(int ms) return BUTTON_SINGLE_CLICK; // Have we waited the full second? - else - if (now == (uint16_t)(start + ticks)) + else if (now == (uint16_t)(start + ticks)) return BUTTON_HOLD; WDT_HIT(); @@ -240,8 +236,7 @@ int BUTTON_HELD(int ms) // attempt at high resolution microsecond timer // beware: timer counts in 21.3uS increments (1024/48Mhz) -void SpinDelayUs(int us) -{ +void SpinDelayUs(int us) { int ticks = (48*us) >> 10; // Borrow a PWM unit for my real-time clock @@ -262,8 +257,7 @@ void SpinDelayUs(int us) } } -void SpinDelay(int ms) -{ +void SpinDelay(int ms) { // convert to uS and call microsecond delay function SpinDelayUs(ms*1000); } @@ -314,8 +308,7 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers // ti = GetTickCount() - ti; // Dbprintf("timer(1s): %d t=%d", ti, GetTickCount()); -void StartTickCount() -{ +void StartTickCount() { // This timer is based on the slow clock. The slow clock frequency is between 22kHz and 40kHz. // We can determine the actual slow clock frequency by looking at the Main Clock Frequency Register. uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & 0xffff; // = 16 * main clock frequency (16MHz) / slow clock frequency @@ -328,7 +321,7 @@ void StartTickCount() /* * Get the current count. */ -uint32_t RAMFUNC GetTickCount(){ +uint32_t RAMFUNC GetTickCount(void) { return AT91C_BASE_RTTC->RTTC_RTVR;// was * 2; } @@ -336,8 +329,7 @@ uint32_t RAMFUNC GetTickCount(){ // ------------------------------------------------------------------------- // microseconds timer // ------------------------------------------------------------------------- -void StartCountUS() -{ +void StartCountUS(void) { AT91C_BASE_PMC->PMC_PCER |= (0x1 << 12) | (0x1 << 13) | (0x1 << 14); // AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC1XC1S_TIOA0; AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE; @@ -359,14 +351,14 @@ void StartCountUS() } -uint32_t RAMFUNC GetCountUS(){ +uint32_t RAMFUNC GetCountUS(void) { return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV * 2) / 3); //was /15) * 10); } static uint32_t GlobalUsCounter = 0; -uint32_t RAMFUNC GetDeltaCountUS(){ +uint32_t RAMFUNC GetDeltaCountUS(void) { uint32_t g_cnt = GetCountUS(); uint32_t g_res = g_cnt - GlobalUsCounter; GlobalUsCounter = g_cnt; @@ -377,8 +369,7 @@ uint32_t RAMFUNC GetDeltaCountUS(){ // ------------------------------------------------------------------------- // Timer for iso14443 commands. Uses ssp_clk from FPGA // ------------------------------------------------------------------------- -void StartCountSspClk() -{ +void StartCountSspClk(void) { AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1) | (1 << AT91C_ID_TC2); // Enable Clock to all timers AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_TIOA1 // XC0 Clock = TIOA1 | AT91C_TCB_TC1XC1S_NONE // XC1 Clock = none @@ -395,7 +386,7 @@ void StartCountSspClk() | AT91C_TC_WAVE // Waveform Mode | AT91C_TC_AEEVT_SET // Set TIOA1 on external event | AT91C_TC_ACPC_CLEAR; // Clear TIOA1 on RC Compare - AT91C_BASE_TC1->TC_RC = 0x02; // RC Compare value = 0x02 + AT91C_BASE_TC1->TC_RC = 1; // RC Compare value = 1; pulse width to TC0 // use TC0 to count TIOA1 pulses AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // disable TC0 @@ -425,7 +416,7 @@ void StartCountSspClk() while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 1st ssp_clk after start of frame while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 2nd ssp_clk after start of frame - if ((AT91C_BASE_SSC->SSC_RFMR & SSC_FRAME_MODE_BITS_IN_WORD(32)) == SSC_FRAME_MODE_BITS_IN_WORD(16)) { + if ((AT91C_BASE_SSC->SSC_RFMR & SSC_FRAME_MODE_BITS_IN_WORD(32)) == SSC_FRAME_MODE_BITS_IN_WORD(16)) { // 16bit frame while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 3rd ssp_clk after start of frame while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; @@ -439,8 +430,8 @@ void StartCountSspClk() AT91C_BASE_TCB->TCB_BCR = 1; // assert Sync (set all timers to 0 on next active clock edge) // at the next (3rd/7th) ssp_clk rising edge, TC1 will be reset (and not generate a clock signal to TC0) // at the next (4th/8th) ssp_clk rising edge, TC0 (the low word of our counter) will be reset. From now on, - // whenever the last three bits of our counter go 0, we can be sure to be in the middle of a frame transfer. - // (just started with the transfer of the 3rd Bit). + // whenever the last three/four bits of our counter go 0, we can be sure to be in the middle of a frame transfer. + // The high word of the counter (TC2) will not reset until the low word (TC0) overflows. Therefore need to wait quite some time before // we can use the counter. while (AT91C_BASE_TC0->TC_CV < 0xFFFF); diff --git a/common/Makefile_Enabled_Options.common b/common/Makefile_Enabled_Options.common index d9f6d3b9..edc86b85 100644 --- a/common/Makefile_Enabled_Options.common +++ b/common/Makefile_Enabled_Options.common @@ -4,7 +4,7 @@ # #BEGIN APP_CFLAGS += -DWITH_ISO14443a_StandAlone \ - -DWITH_LF\ + -DWITH_LF \ -DWITH_ISO15693 \ -DWITH_ISO14443a \ -DWITH_ISO14443b \ diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index ea7c7ebf542072256f4e1e177089d13003642b3a..c5beb0b9afbe979fbf955e4b1102c1e4cbc3dd36 100644 GIT binary patch literal 42175 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 literal 42175 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 N6yfLSBUk_J{{rV?^``&; diff --git a/fpga/hi_reader.v b/fpga/hi_reader.v index fe5ae4e5..edb9a8a6 100644 --- a/fpga/hi_reader.v +++ b/fpga/hi_reader.v @@ -30,16 +30,16 @@ reg after_hysteresis, after_hysteresis_prev, after_hysteresis_prev_prev; reg [11:0] has_been_low_for; always @(negedge adc_clk) begin - if(& adc_d[7:0]) after_hysteresis <= 1'b1; - else if(~(| adc_d[7:0])) after_hysteresis <= 1'b0; + if (& adc_d[7:0]) after_hysteresis <= 1'b1; + else if (~(| adc_d[7:0])) after_hysteresis <= 1'b0; - if(after_hysteresis) + if (after_hysteresis) begin - has_been_low_for <= 7'b0; + has_been_low_for <= 12'd0; end else begin - if(has_been_low_for == 12'd4095) + if (has_been_low_for == 12'd4095) begin has_been_low_for <= 12'd0; after_hysteresis <= 1'b1; @@ -235,6 +235,16 @@ end // ssp clock and frame signal for communication to and from ARM +// _____ _____ _____ _ +// ssp_clk | |_____| |_____| |_____| +// _____ +// ssp_frame ___| |____________________________ +// ___________ ___________ ___________ _ +// ssp_d_in X___________X___________X___________X_ +// +// corr_i_cnt 0 1 2 3 4 5 6 7 8 9 10 11 12 ... +// + reg ssp_clk; reg ssp_frame; @@ -249,7 +259,7 @@ begin // (send one frame with 16 Bits) if (corr_i_cnt == 6'd1) ssp_frame <= 1'b1; - if (corr_i_cnt == 6'd5) + if (corr_i_cnt == 6'd3) ssp_frame <= 1'b0; end -- 2.39.2