From 3d2ce8df12898dbdb0b545340fe536b470c7a998 Mon Sep 17 00:00:00 2001 From: henryk Date: Thu, 29 Nov 2007 20:38:00 +0000 Subject: Fix SSC TX registers (especially the clock source selection), peripheral configuration in ssc_tx_init Implement software (FIQ based) workaround for the problem that TF seemingly cannot be used as a start condition git-svn-id: https://svn.openpcd.org:2342/trunk@360 6dc7ffe9-61d6-0310-9af1-9938baff3ed1 --- openpicc/application/pio_irq.c | 2 +- openpicc/application/ssc_picc.c | 45 +++++++++++++++++++++++++++++++++++------ openpicc/config/board.h | 1 + openpicc/os/boot/boot.s | 24 ++++++++++++++++++++++ 4 files changed, 65 insertions(+), 7 deletions(-) (limited to 'openpicc') diff --git a/openpicc/application/pio_irq.c b/openpicc/application/pio_irq.c index 5359bbf..3a753d4 100644 --- a/openpicc/application/pio_irq.c +++ b/openpicc/application/pio_irq.c @@ -68,7 +68,7 @@ extern void fiq_handler(void); /* Will be used in pio_irq_demux_secondary below and contains the PIO_ISR value * from when the FIQ was raised */ -u_int32_t pio_irq_isr_value; +volatile u_int32_t pio_irq_isr_value; /* low-level handler, used by Cstartup_app.S PIOA fast forcing and diff --git a/openpicc/application/ssc_picc.c b/openpicc/application/ssc_picc.c index de2121d..a5f1075 100644 --- a/openpicc/application/ssc_picc.c +++ b/openpicc/application/ssc_picc.c @@ -44,6 +44,7 @@ #include "tc_cdiv_sync.h" #include "tc_fdt.h" +#include "pio_irq.h" #include "usb_print.h" #include "iso14443_layer3a.h" @@ -170,6 +171,14 @@ out_set_mode: ssc_state.mode = ssc_mode; } +/* For some reason AT91C_SSC_START_RISE_RF (or AT91C_SSC_START_HIGH_RF or ...) doesn't + * work as a start condition. Instead we'll configure TF as a PIO input pin, enable + * a PIO change interrupt, have Fast Forcing enabled for the PIO change interrupt and + * then activate the SSC TX in the FIQ handler on rising TF. ssc_tx_pending is queried + * by the fiq handler to see whether to start the transmitter. */ +#define USE_SSC_TX_TF_WORKAROUND +volatile u_int32_t ssc_tx_pending = 0; +void ssc_tf_irq(u_int32_t pio); void ssc_tx_start(ssc_dma_tx_buffer_t *buf) { u_int8_t data_len, num_data, sync_len; @@ -181,16 +190,19 @@ void ssc_tx_start(ssc_dma_tx_buffer_t *buf) /* disable all Tx related interrupt sources */ AT91F_SSC_DisableIt(ssc, SSC_TX_IRQ_MASK); +#ifdef USE_SSC_TX_TF_WORKAROUND + start_cond = AT91C_SSC_START_CONTINOUS; +#else start_cond = AT91C_SSC_START_RISE_RF; - sync_len = 0; - ssc->SSC_RC0R = 0; +#endif + sync_len = 1; data_len = 32; num_data = buf->len/(data_len/8); /* FIXME This is broken for more than 64 bytes */ ssc->SSC_TFMR = ((data_len-1) & 0x1f) | (((num_data-1) & 0x0f) << 8) | (((sync_len-1) & 0x0f) << 16); - ssc->SSC_TCMR = AT91C_SSC_CKS_RK | AT91C_SSC_CKO_NONE | start_cond; + ssc->SSC_TCMR = 0x01 | AT91C_SSC_CKO_NONE | start_cond; AT91F_PDC_SetTx(tx_pdc, buf->data, num_data); @@ -200,10 +212,28 @@ void ssc_tx_start(ssc_dma_tx_buffer_t *buf) /* Enable DMA */ AT91F_PDC_EnableTx(tx_pdc); /* Start Transmission */ +#ifndef USE_SSC_TX_TF_WORKAROUND AT91F_SSC_EnableTx(AT91C_BASE_SSC); +#else + ssc_tx_pending = 1; + pio_irq_enable(OPENPICC_SSC_TF); + if(AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, OPENPICC_SSC_TF)) { + /* TF was probably already high when we enabled the PIO change interrupt for it. */ + ssc_tf_irq(OPENPICC_SSC_TF); + } +#endif } - +#ifdef USE_SSC_TX_TF_WORKAROUND +void ssc_tf_irq(u_int32_t pio) { + (void)pio; + pio_irq_disable(OPENPICC_SSC_TF); + if(ssc_tx_pending) { /* Transmit has not yet been started by the FIQ */ + AT91F_SSC_EnableTx(AT91C_BASE_SSC); + ssc_tx_pending = 0; + } +} +#endif //static struct openpcd_hdr opcd_ssc_hdr = { @@ -429,8 +459,11 @@ void ssc_tx_init(void) * PA17 !! */ AT91F_PIO_CfgInput(AT91C_BASE_PIOA, OPENPICC_MOD_PWM); AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, OPENPICC_MOD_SSC | - OPENPICC_SSC_DATA | OPENPICC_SSC_DATA | - AT91C_PIO_PA15, 0); + OPENPICC_SSC_CLOCK | OPENPICC_SSC_TF, 0); +#ifdef USE_SSC_TX_TF_WORKAROUND + AT91F_PIO_CfgInput(AT91C_BASE_PIOA, OPENPICC_SSC_TF); + pio_irq_register(OPENPICC_SSC_TF, ssc_tf_irq); +#endif tx_pdc = (AT91PS_PDC) &(ssc->SSC_RPR); } diff --git a/openpicc/config/board.h b/openpicc/config/board.h index 61eab3c..8f8e59a 100644 --- a/openpicc/config/board.h +++ b/openpicc/config/board.h @@ -65,6 +65,7 @@ #define OPENPICC_MOD_SSC AT91C_PA17_TD #define OPENPICC_SSC_DATA AT91C_PA18_RD #define OPENPICC_SSC_CLOCK AT91C_PA19_RK +#define OPENPICC_SSC_TF AT91C_PIO_PA15 #define OPENPICC_PIO_FRAME AT91C_PIO_PA20 #define OPENPICC_PIO_SSC_DATA_CONTROL AT91C_PIO_PA21 diff --git a/openpicc/os/boot/boot.s b/openpicc/os/boot/boot.s index cedd3ee..43c4885 100644 --- a/openpicc/os/boot/boot.s +++ b/openpicc/os/boot/boot.s @@ -4,6 +4,7 @@ .extern exit .extern AT91F_LowLevelInit .extern pio_irq_isr_value + .extern ssc_tx_pending .text .code 32 @@ -45,10 +46,13 @@ .equ AT91C_BASE_PIOA, 0xFFFFF400 .equ AT91C_BASE_TC0, 0xFFFA0000 .equ AT91C_BASE_SSC, 0xFFFD4000 +.equ SSC_CR, 0x0 .equ SSC_RCMR, 0x10 +.equ SSC_CR_TXEN, 0x100 .equ AT91C_TC_SWTRG, (1 << 2) .equ AT91C_TC_CLKEN, (1 << 0) .equ PIO_DATA, (1 << 27) +.equ PIO_SSC_TF, (1 << 15) .equ PIOA_SODR, 0x30 .equ PIOA_CODR, 0x34 .equ PIOA_PDSR, 0x3c @@ -219,6 +223,26 @@ my_fiq_handler: movne r11, #PIO_DATA strne r11, [r10, #PIOA_IDR] /* disable further PIO_DATA FIQ */ + tst r8, #PIO_SSC_TF /* check for SSC Transmit Frame signal */ + ldrne r11, [r10, #PIOA_PDSR] + tstne r11, #PIO_SSC_TF /* check for SSC_TF == 1 */ + + movne r11, #PIO_SSC_TF + strne r11, [r10, #PIOA_IDR] /* disable further SSC_TF FIQ */ + + ldrne r11, =ssc_tx_pending + ldrne r8, [r11] + tstne r8, #0x01 /* Check whether a TX is pending */ + + beq .no_ssc + mov r8, #0x00 + str r8, [r11] /* Set ssc_tx_pending to 0 */ + + ldr r11, =AT91C_BASE_SSC + mov r8, #SSC_CR_TXEN + str r8, [r11, #SSC_CR] /* Write TXEN to SSC_CR, enables tx */ + +.no_ssc: /* Trigger PIO_SECONDARY_IRQ */ mov r11, #PIO_SECONDARY_IRQ_BIT ldr r8, =AT91C_BASE_AIC -- cgit v1.2.3