Add new miller decoder (not working yet)

Vastly improve timing through CPU cycle counting. Jitter is now like 40ns (the SSC_DATA edge detection fuzziness)  in 2 main clusters 4 CPU cycles (83ns) apart, plus an occasional glitch adding 4 CPU cycles in either direction


git-svn-id: https://svn.openpcd.org:2342/trunk@385 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
This commit is contained in:
henryk 2007-12-12 01:50:14 +00:00
parent 3d0e1db9d1
commit 202b56a42c
9 changed files with 187 additions and 35 deletions

View File

@ -90,6 +90,7 @@ ARM_SRC= \
application/usb_print.c \
application/iso14443_layer3a.c \
application/iso14443a_manchester.c \
application/iso14443a_miller.c \
application/load_modulation.c \
application/decoder_miller.c \
application/decoder_nrzl.c \

View File

@ -37,13 +37,14 @@
#include "load_modulation.h"
#include "decoder.h"
#include "iso14443a_manchester.h"
#include "iso14443a_miller.h"
#include "led.h"
static enum ISO14443_STATES state = STARTING_UP;
const iso14443_frame ATQA_FRAME = {
TYPE_A,
{{STANDARD_FRAME, PARITY}},
2,
2,
0, 0,
{4, 0},
{}
@ -85,11 +86,11 @@ const iso14443_frame NULL_FRAME = {
void iso14443_transmit(ssc_dma_tx_buffer_t *buf, int fdt, int div)
{
tc_cdiv_set_divider(div);
if(fdt == ISO14443A_TRANSMIT_AT_NEXT_INTERVAL_0 ||
fdt == ISO14443A_TRANSMIT_AT_NEXT_INTERVAL_1) {
/* FIXME Implement */
return;
}
if(fdt == ISO14443A_TRANSMIT_AT_NEXT_INTERVAL_0) {
fdt = tc_fdt_get_next_slot(ISO14443A_FDT_SHORT_0, ISO14443A_FDT_SLOTLEN);
} else if (fdt == ISO14443A_TRANSMIT_AT_NEXT_INTERVAL_1) {
fdt = tc_fdt_get_next_slot(ISO14443A_FDT_SHORT_1, ISO14443A_FDT_SLOTLEN);
}
ssc_tx_fiq_fdt_cdiv = fdt -3*div -1;
tc_fdt_set(ssc_tx_fiq_fdt_cdiv -MAX_TF_FIQ_ENTRY_DELAY -MAX_TF_FIQ_OVERHEAD);
ssc_tx_fiq_fdt_ssc = fdt -div +1;
@ -162,7 +163,7 @@ static int prefill_buffer(ssc_dma_tx_buffer_t *dest, const iso14443_frame *src)
}
static u_int8_t received_buffer[256];
static iso14443_frame received_frame;
static void enable_reception(enum ssc_mode mode) {
tc_fdt_set(0xff00);
@ -307,6 +308,12 @@ void iso14443_layer3a_state_machine (void *pvParameters)
LAYER3_DEBUG(", woke up to send ATQA\n\r");
atqa_sent = 0;
}
if(1) {
DumpStringToUSB("Decoded: ");
iso14443a_decode_miller(&received_frame, buffer->data, buffer->len);
DumpBufferToUSB((char*)received_frame.data, 100);
DumpStringToUSB("\n\r");
}
/* For debugging, wait 1ms, then wait for another frame
* Normally we'd go to anticol from here*/
vTaskDelay(portTICK_RATE_MS);
@ -320,12 +327,12 @@ void iso14443_layer3a_state_machine (void *pvParameters)
break;
case ACTIVE:
case ACTIVE_STAR:
if(0) {
#if 0
DumpStringToUSB("Decoded: ");
decoder_decode(DECODER_MILLER, (const char*)buffer->data, buffer->len, received_buffer);
DumpBufferToUSB((char*)received_buffer, 100);
DumpStringToUSB("\n\r");
}
#endif
/* Wait for another frame */
if(0) {
ssc_rx_mode_set(SSC_MODE_14443A_STANDARD);
@ -336,7 +343,7 @@ void iso14443_layer3a_state_machine (void *pvParameters)
if(prefill_buffer(&ssc_tx_buffer, &NULL_FRAME)) {
usb_print_string_f("Sending response ...",0);
ssc_tx_buffer.state = PROCESSING;
iso14443_transmit(&ssc_tx_buffer, 1, 8);
iso14443_transmit(&ssc_tx_buffer, ISO14443A_TRANSMIT_AT_NEXT_INTERVAL_1, 8);
while( ssc_tx_buffer.state != FREE ) {
vTaskDelay(portTICK_RATE_MS);
}

View File

@ -16,21 +16,6 @@ enum ISO14443_STATES {
};
/******************** RX ************************************/
/* Magic delay, don't know where it comes from */
#define MAGIC_OFFSET -32
/* Delay from modulation till detection in SSC_DATA */
#define DETECTION_DELAY 11
/* See fdt_timinig.dia for these values */
#define MAX_TF_FIQ_ENTRY_DELAY 16
#define MAX_TF_FIQ_OVERHEAD 75 /* guesstimate */
extern volatile int fdt_offset;
/* standard derived magic values */
#define ISO14443A_FDT_SLOTLEN 128
#define ISO14443A_FDT_OFFSET_1 84
#define ISO14443A_FDT_OFFSET_0 20
#define ISO14443A_FDT_SHORT_1 (ISO14443A_FDT_SLOTLEN*9 + ISO14443A_FDT_OFFSET_1 +fdt_offset +MAGIC_OFFSET -DETECTION_DELAY)
#define ISO14443A_FDT_SHORT_0 (ISO14443A_FDT_SLOTLEN*9 + ISO14443A_FDT_OFFSET_0 +fdt_offset +MAGIC_OFFSET -DETECTION_DELAY)
#ifdef FOUR_TIMES_OVERSAMPLING
/* definitions for four-times oversampling */
/* Sample values for the REQA and WUPA short frames */
@ -82,6 +67,21 @@ extern volatile int fdt_offset;
#endif
/******************** TX ************************************/
/* Magic delay, don't know where it comes from */
#define MAGIC_OFFSET -32
/* Delay from modulation till detection in SSC_DATA */
#define DETECTION_DELAY 11
/* See fdt_timinig.dia for these values */
#define MAX_TF_FIQ_ENTRY_DELAY 16
#define MAX_TF_FIQ_OVERHEAD 75 /* guesstimate */
extern volatile int fdt_offset;
/* standard derived magic values */
#define ISO14443A_FDT_SLOTLEN 128
#define ISO14443A_FDT_OFFSET_1 84
#define ISO14443A_FDT_OFFSET_0 20
#define ISO14443A_FDT_SHORT_1 (ISO14443A_FDT_SLOTLEN*9 + ISO14443A_FDT_OFFSET_1 +fdt_offset +MAGIC_OFFSET -DETECTION_DELAY)
#define ISO14443A_FDT_SHORT_0 (ISO14443A_FDT_SLOTLEN*9 + ISO14443A_FDT_OFFSET_0 +fdt_offset +MAGIC_OFFSET -DETECTION_DELAY)
/* in bytes, not counting parity */
#define MAXIMUM_FRAME_SIZE 256

View File

@ -1,5 +1,6 @@
/* ISO14443A Manchester encoder for OpenPICC
* (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2007 by Henryk Plötz <henryk@ploetzli.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@ -0,0 +1,112 @@
/* ISO14443A Manchester encoder for OpenPICC
* (C) 2007 by Henryk Plötz <henryk@ploetzli.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <openpicc.h>
#include <FreeRTOS.h>
#include <string.h>
#include "iso14443_layer3a.h"
#include "usb_print.h"
#include "cmd.h"
#ifdef FOUR_TIMES_OVERSAMPLING
#define OVERSAMPLING_RATE 4
/* definitions for four-times oversampling */
#define SEQ_X 0x4
#define SEQ_Y 0x0
#define SEQ_Z 0x1
#else
#define OVERSAMPLING_RATE 2
#define SEQ_X 0x2
#define SEQ_Y 0x0
#define SEQ_Z 0x1
#endif
enum miller_sequence {
SEQUENCE_X,
SEQUENCE_Y,
SEQUENCE_Z,
};
#define BIT_ENDMARKER -1
int iso14443a_decode_miller(iso14443_frame *frame,
const u_int8_t *sample_buf, const u_int16_t sample_buf_len)
{
signed int i, j, bit = 0, last_bit = 0;
enum miller_sequence current_seq;
unsigned int bitpos = 0;
memset(frame, 0, sizeof(frame));
frame->type = TYPE_A;
frame->parameters.a.parity = GIVEN_PARITY;
for(i=0; i<sample_buf_len && bit != BIT_ENDMARKER; i++) {
for(j=0; j<(signed)(sizeof(sample_buf[0])*8)/OVERSAMPLING_RATE && bit != BIT_ENDMARKER; j++) {
int sample = (sample_buf[i]>>(j*OVERSAMPLING_RATE)) & ~(~0 << OVERSAMPLING_RATE);
switch(sample) {
case SEQ_X: current_seq = SEQUENCE_X; break;
case SEQ_Y: current_seq = SEQUENCE_Y; break;
case SEQ_Z: current_seq = SEQUENCE_Z; break;
default: current_seq = SEQUENCE_Y;
}
switch(current_seq) {
case SEQ_X:
DumpStringToUSB("X");
bit = 1; break;
case SEQ_Y: /* Fall-through to SEQ_Z */
DumpStringToUSB("Y");
if(last_bit == 0) {
bit = BIT_ENDMARKER;
break;
}
case SEQ_Z:
DumpStringToUSB("Z");
bit = 0; break;
}
switch(bit) {
case BIT_ENDMARKER:
bitpos--;
break;
case 0: /* Fall-through */
case 1: {
int bytepos = bitpos/9;
if(bitpos % 9 == 8) { /* Parity bit */
frame->parity[ bytepos/8 ] |= (bit<<(bytepos%8));
} else {
frame->data[ bytepos ] |= (bit<<(bitpos%9));
}
}
}
last_bit = bit;
bitpos++;
}
}
frame->numbytes = bitpos/9;
frame->numbits = bitpos%9;
DumpStringToUSB("\n\r");
return 0;
}

View File

@ -0,0 +1,6 @@
#ifndef ISO14443A_MILLER_H_
#define ISO14443A_MILLER_H_
extern int iso14443a_decode_miller(iso14443_frame *frame, const u_int8_t *sample_buf, const u_int16_t sample_buf_len);
#endif /*ISO14443A_MILLER_H_*/

View File

@ -50,16 +50,12 @@ void tc_fdt_set(u_int16_t count)
tcfdt->TC_RA = count;
}
void __ramfunc tc_fdt_set_to_next_slot(int last_bit)
int tc_fdt_get_next_slot(int reference_time, int slotlen)
{
int reference_time;
if(last_bit == 0) reference_time = ISO14443A_FDT_OFFSET_0;
else reference_time = ISO14443A_FDT_OFFSET_1;
if(tcfdt->TC_SR & AT91C_TC_CLKSTA)
/*if(tcfdt->TC_SR & AT91C_TC_CLKSTA)
while(tcfdt->TC_CV != 0xFFFF && (tcfdt->TC_CV - reference_time) % 128 != 0);
tcfdt->TC_CCR = AT91C_TC_SWTRG;
tc_fdt_set(2*128);
tcfdt->TC_CCR = AT91C_TC_SWTRG;*/
return tcfdt->TC_CV + (slotlen-((tcfdt->TC_CV - reference_time) % slotlen)) + 3*slotlen;
}

View File

@ -5,6 +5,6 @@
extern void tc_fdt_init(void);
extern void tc_fdt_set(u_int16_t count);
extern void __ramfunc tc_fdt_set_to_next_slot(int last_bit);
extern int tc_fdt_get_next_slot(int reference_time, int slotlen);
#endif

View File

@ -250,10 +250,39 @@ my_fiq_handler:
ldr r11, =ssc_tx_fiq_fdt_cdiv
ldr r11, [r11] /* r11 == ssc_tx_fiq_fdt_cdiv */
/* Problem: LDR from the timer still takes too long and causes us to miss the exact time.
* Strategy: Spin on TC2 till we are very near the actual time. Then load the timer value, calculate
* the difference to the target, then do a countdown spin without reading the timer.
*
* At 47.923200 MHz 7 processor cycles are 2 carrier cycles of the 13.56MHz carrier
*/
.equ SUB_TIME, 20 /* subtract 20 carrier cycles == 70 processor cycles */
.equ ADD_TIME, (70-20) /* Add x processor cycles */
mov r8, #SUB_TIME
sub r11, r11, r8
.wait_for_fdt_cdiv:
ldr r8, [r12, #TC2_CV]
cmp r8, r11
bmi .wait_for_fdt_cdiv /* spin while TC2.CV is less fdt_cdiv */
bmi .wait_for_fdt_cdiv /* spin while TC2.CV is less fdt_cdiv-SUB_TIM */
ldr r8, [r12, #TC2_CV]
sub r11, r11, r8 /* r11 == fdt_cdiv-SUB_TIME - TC2.CV */
mov r8, #0x07
mul r11, r8, r11 /* r11 = r11 * 7 */
mov r11, r11, ASR #1 /* r11 = r11 / 2 */
mov r8, #ADD_TIME
add r11, r11, r8 /* r11 = r11 + ADD_TIME */
mov r11, r11, ASR #2 /* r11 = r11 / 4 (4 is the number of cycles per loop run below) */
mov r8, #1
.wait_for_my_time:
subs r11, r11, r8
bge .wait_for_my_time
str r9, [r12, #TC_CCR] /* SWTRG on TC0 */