summaryrefslogtreecommitdiff
path: root/openpicc
diff options
context:
space:
mode:
authorhenryk <henryk@6dc7ffe9-61d6-0310-9af1-9938baff3ed1>2008-03-09 00:40:55 +0000
committerhenryk <henryk@6dc7ffe9-61d6-0310-9af1-9938baff3ed1>2008-03-09 00:40:55 +0000
commit2bf5a3ae4e9356d80d6434e40e1e864ceb08d734 (patch)
tree2b36dfdfe8699009f4cfd2d71ebbf93329557155 /openpicc
parentb5be7c184f7d07b49a04098cd41d980f90f7e699 (diff)
Fix sending
Add Tx abort and SSC reset functionalities There is a bug workaround for a peculiarity in the SSC Tx: When it is set to START CONTINOUS while a transmission is in progress (started by START TF RISING EDGE, which is necessary for the correct timing) it will lose one (or two?) bits of sample data. The resetting of the start condition itself is necessary because the SSC will only transmit up to 64 bytes (32 bit times 16) per start condition Add performance counters for sent and received frames git-svn-id: https://svn.openpcd.org:2342/trunk@445 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
Diffstat (limited to 'openpicc')
-rw-r--r--openpicc/application/cmd.c2
-rw-r--r--openpicc/application/iso14443_layer2a.c10
-rw-r--r--openpicc/application/ssc.c128
-rw-r--r--openpicc/application/ssc.h7
4 files changed, 126 insertions, 21 deletions
diff --git a/openpicc/application/cmd.c b/openpicc/application/cmd.c
index 5991694..58b341d 100644
--- a/openpicc/application/cmd.c
+++ b/openpicc/application/cmd.c
@@ -30,7 +30,7 @@ xTaskHandle xCmdRecvUsbTask;
xTaskHandle xFieldMeterTask;
xSemaphoreHandle xFieldMeterMutex;
-volatile int fdt_offset=-20;
+volatile int fdt_offset=-20 -16; // -16 for the SSC Tx set to continous bug
volatile int load_mod_level_set=3;
#if ( configUSE_TRACE_FACILITY == 1 )
diff --git a/openpicc/application/iso14443_layer2a.c b/openpicc/application/iso14443_layer2a.c
index 17cbca8..91df6b9 100644
--- a/openpicc/application/iso14443_layer2a.c
+++ b/openpicc/application/iso14443_layer2a.c
@@ -155,6 +155,16 @@ int iso14443_transmit(ssc_dma_tx_buffer_t *buffer, unsigned int fdt, u_int8_t as
return 0;
}
+int iso14443_tx_abort(void)
+{
+ int ret = 0;
+ taskENTER_CRITICAL();
+ ret = ssc_send_abort(ssc);
+ tx_pending = 0;
+ taskEXIT_CRITICAL();
+ return ret;
+}
+
int iso14443_wait_for_carrier(unsigned int timeout)
{
(void)timeout;
diff --git a/openpicc/application/ssc.c b/openpicc/application/ssc.c
index 7c63104..d1d4e48 100644
--- a/openpicc/application/ssc.c
+++ b/openpicc/application/ssc.c
@@ -79,6 +79,9 @@ static struct {
[METRIC_MANAGEMENT_ERRORS_2] = {METRIC_MANAGEMENT_ERRORS_2, "Internal buffer management error type 2", 0},
[METRIC_MANAGEMENT_ERRORS_3] = {METRIC_MANAGEMENT_ERRORS_3, "Internal buffer management error type 3", 0},
[METRIC_LATE_TX_FRAMES] = {METRIC_LATE_TX_FRAMES, "Late Tx frames", 0},
+ [METRIC_RX_FRAMES] = {METRIC_RX_FRAMES, "Rx frames", 0},
+ [METRIC_TX_FRAMES] = {METRIC_TX_FRAMES, "Tx frames", 0},
+ [METRIC_TX_ABORTED_FRAMES] = {METRIC_TX_ABORTED_FRAMES, "Aborted Tx frames", 0},
};
static ssc_dma_rx_buffer_t _rx_buffers[SSC_DMA_BUFFER_COUNT];
@@ -186,29 +189,60 @@ void ssc_frame_started(void)
_ssc_rx_irq(_ssc.ssc->SSC_SR, 1, pdFALSE);
}
+static void __ramfunc _ssc_tx_end(ssc_handle_t *sh, int is_an_abort)
+{
+ AT91F_PDC_DisableTx(sh->pdc);
+ AT91F_SSC_DisableTx(sh->ssc);
+ sh->ssc->SSC_IDR = SSC_TX_IRQ_MASK;
+
+ AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, AT91C_PA15_TF, 0);
+ usb_print_string_f(">",0);
+
+ AT91F_PDC_SetTx(sh->pdc, 0, 0);
+ AT91F_PDC_SetNextTx(sh->pdc, 0, 0);
+
+ if(sh->tx_buffer) {
+ sh->tx_buffer->state = FREE;
+ sh->tx_running = 0;
+ }
+
+ if(sh->rx_running) {
+ /* Receiver has been suspended by the pending transmission. Restart it. */
+ AT91F_SSC_EnableRx(sh->ssc);
+ }
+
+ if(sh->callback) {
+ if(is_an_abort)
+ sh->callback(CALLBACK_TX_FRAME_ABORTED, sh->tx_buffer);
+ else
+ sh->callback(CALLBACK_TX_FRAME_ENDED, sh->tx_buffer);
+ }
+
+ sh->tx_buffer = NULL;
+}
+
static int __ramfunc _ssc_tx_irq(u_int32_t sr, portBASE_TYPE task_woken)
{
ssc_handle_t *sh = &_ssc;
- if( sr & AT91C_SSC_TXEMPTY ) {
- /* Tx has ended */
- AT91F_PDC_DisableTx(sh->pdc);
- AT91F_SSC_DisableTx(sh->ssc);
- sh->ssc->SSC_IDR = SSC_TX_IRQ_MASK;
-
- if(sh->tx_buffer) {
- sh->tx_buffer->state = FREE;
- sh->tx_running = 0;
- }
-
- if(sh->rx_running) {
- /* Receiver has been suspended by the pending transmission. Restart it. */
- AT91F_SSC_EnableRx(sh->ssc);
- }
+ if( sr & AT91C_SSC_TXSYN ) {
+ /* Tx starting, hardwire TF pin to high */
+ AT91F_PIO_SetOutput(AT91C_BASE_PIOA, AT91C_PA15_TF);
+ AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, AT91C_PA15_TF);
+ usb_print_string_f("<",0);
+ /* Also set SSC mode to continous
+ * FIXME BUG: This will somehow drop some samples or something on the SSC*/
+ sh->ssc->SSC_TCMR = (sh->ssc->SSC_TCMR & ~AT91C_SSC_START) | AT91C_SSC_START_CONTINOUS;
+
if(sh->callback)
- sh->callback(CALLBACK_TX_FRAME_ENDED, sh->tx_buffer);
- sh->tx_buffer = NULL;
+ sh->callback(CALLBACK_TX_FRAME_BEGIN, NULL);
+ }
+
+ if( sr & AT91C_SSC_TXEMPTY ) {
+ /* Tx has ended */
+ ssc_metrics[METRIC_TX_FRAMES].value++;
+ _ssc_tx_end(sh, 0);
}
return task_woken;
@@ -460,6 +494,7 @@ static inline int _init_ssc_rx(ssc_handle_t *sh)
OPENPICC_PIO_FRAME,
0);
+ /* FIXME: This is handled by tc_cdiv_sync and shouldn't be necessary */
AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC_PIO_SSC_DATA_CONTROL);
AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPICC_PIO_SSC_DATA_CONTROL);
@@ -571,12 +606,11 @@ ssc_handle_t* ssc_open(u_int8_t init_rx, u_int8_t init_tx, enum ssc_mode mode, s
if(!sh->rx_enabled) {
ssc_close(sh);
return NULL;
- } else {
- _ssc_rx_mode_set(sh, mode);
}
}
if(sh->rx_enabled || sh->tx_enabled) {
+ _ssc_rx_mode_set(sh, mode);
AT91F_AIC_ConfigureIt(AT91C_ID_SSC,
OPENPICC_IRQ_PRIO_SSC,
AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, (THandler)&ssc_irq);
@@ -646,7 +680,7 @@ int ssc_send(ssc_handle_t* sh, ssc_dma_tx_buffer_t *buffer)
AT91F_PDC_SetNextTx(sh->pdc, 0, 0);
buffer->state = PENDING;
- sh->ssc->SSC_IER = AT91C_SSC_TXEMPTY;
+ sh->ssc->SSC_IER = AT91C_SSC_TXEMPTY | AT91C_SSC_TXSYN;
/* Enable DMA */
sh->ssc->SSC_THR = 0;
AT91F_PDC_EnableTx(sh->pdc);
@@ -664,6 +698,18 @@ int ssc_send(ssc_handle_t* sh, ssc_dma_tx_buffer_t *buffer)
return 0;
}
+int ssc_send_abort(ssc_handle_t* sh)
+{
+ if(!sh) return -EINVAL;
+ if(!sh->tx_enabled) return -EINVAL;
+ if(!sh->tx_running) return -EINVAL;
+
+ ssc_metrics[METRIC_TX_ABORTED_FRAMES].value++;
+ _ssc_tx_end(sh, 1);
+
+ return 0;
+}
+
int ssc_close(ssc_handle_t* sh)
{
if(sh->rx_running)
@@ -682,6 +728,48 @@ int ssc_close(ssc_handle_t* sh)
return 0;
}
+/* Hard reset the SSC to flush all buffers and whatnot. Call with IRQs disabled */
+void ssc_hard_reset(ssc_handle_t *sh)
+{
+ if(sh == NULL) return;
+ if(!sh->rx_enabled && !sh->tx_enabled) return;
+
+ u_int32_t
+ cmr = sh->ssc->SSC_CMR,
+ rcmr = sh->ssc->SSC_RCMR,
+ rfmr = sh->ssc->SSC_RFMR,
+ tcmr = sh->ssc->SSC_TCMR,
+ tfmr = sh->ssc->SSC_TFMR,
+ rc0r = sh->ssc->SSC_RC0R,
+ rc1r = sh->ssc->SSC_RC1R,
+ sr = sh->ssc->SSC_SR,
+ imr = sh->ssc->SSC_IMR;
+
+ sh->ssc->SSC_CR = AT91C_SSC_SWRST;
+
+ sh->ssc->SSC_CMR = cmr;
+ sh->ssc->SSC_RCMR = rcmr;
+ sh->ssc->SSC_RFMR = rfmr;
+ sh->ssc->SSC_TCMR = tcmr;
+ sh->ssc->SSC_TFMR = tfmr;
+ sh->ssc->SSC_RC0R = rc0r;
+ sh->ssc->SSC_RC1R = rc1r;
+
+ sh->ssc->SSC_IDR = ~imr;
+ sh->ssc->SSC_IER = imr;
+
+ if(sr & AT91C_SSC_RXEN)
+ AT91F_SSC_EnableRx(sh->ssc);
+ else
+ AT91F_SSC_DisableRx(sh->ssc);
+
+ if(sr & AT91C_SSC_TXEN)
+ AT91F_SSC_EnableTx(sh->ssc);
+ else
+ AT91F_SSC_DisableTx(sh->ssc);
+}
+
+
int ssc_get_metric(ssc_metric metric, char **description, int *value)
{
char *_name="Undefined";
diff --git a/openpicc/application/ssc.h b/openpicc/application/ssc.h
index 2f72e93..9edec64 100644
--- a/openpicc/application/ssc.h
+++ b/openpicc/application/ssc.h
@@ -12,6 +12,9 @@ typedef enum {
METRIC_MANAGEMENT_ERRORS_2, // Internal buffer management error type 2
METRIC_MANAGEMENT_ERRORS_3, // Internal buffer management error type 3
METRIC_LATE_TX_FRAMES, // Frames that only reached the SSC when TF already was high
+ METRIC_RX_FRAMES, // Frames received
+ METRIC_TX_FRAMES, // Frames sent
+ METRIC_TX_ABORTED_FRAMES, // Aborted send frames
_MAX_METRICS,
} ssc_metric;
@@ -26,6 +29,7 @@ typedef enum {
CALLBACK_RX_FRAME_ENDED, // *data is ssc_dma_rx_buffer *buffer
CALLBACK_TX_FRAME_BEGIN,
CALLBACK_TX_FRAME_ENDED,
+ CALLBACK_TX_FRAME_ABORTED,
CALLBACK_SETUP, // *data is ssh_handle_t *sh
CALLBACK_TEARDOWN, // *data is ssh_handle_t *sh
} ssc_callback_reason;
@@ -44,6 +48,9 @@ extern ssc_handle_t* ssc_open(u_int8_t init_rx, u_int8_t init_tx, enum ssc_mode
extern int ssc_recv(ssc_handle_t* sh, ssc_dma_rx_buffer_t* *buffer, unsigned int timeout);
extern int ssc_send(ssc_handle_t* sh, ssc_dma_tx_buffer_t* buffer);
+extern int ssc_send_abort(ssc_handle_t* sh);
+
+extern void ssc_hard_reset(ssc_handle_t *sh);
extern int ssc_close(ssc_handle_t* sh);
personal git repositories of Harald Welte. Your mileage may vary