From aa804cf4ef8ed3236ae0065952d1faef735b3824 Mon Sep 17 00:00:00 2001 From: henryk Date: Fri, 23 Nov 2007 17:32:14 +0000 Subject: Add a work around to have each pio data change fiq followed by a regular IRQ in order to enable some code to be run synchronized with critical sections git-svn-id: https://svn.openpcd.org:2342/trunk@348 6dc7ffe9-61d6-0310-9af1-9938baff3ed1 --- openpicc/application/pio_irq.c | 52 ++++++++++++++++++++++++++++++++++--- openpicc/application/ssc_picc.c | 3 --- openpicc/application/tc_cdiv_sync.c | 7 +++-- openpicc/os/boot/boot.s | 25 +++++++++++------- 4 files changed, 69 insertions(+), 18 deletions(-) (limited to 'openpicc') diff --git a/openpicc/application/pio_irq.c b/openpicc/application/pio_irq.c index a92ceaa..04763a3 100644 --- a/openpicc/application/pio_irq.c +++ b/openpicc/application/pio_irq.c @@ -1,5 +1,6 @@ /* PIO IRQ Implementation for OpenPCD * (C) 2006 by Harald Welte + * (C) 2007 Henryk Plötz * * 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 @@ -40,6 +41,37 @@ struct pioirq_state { static struct pioirq_state pirqs; static unsigned long count = 0; +/* This FIQ implementation of pio data change works in close cooperation with function my_fiq_handler + * in os/boot/boot.s + * This code uses fast forcing for the PIOA irq so that each PIOA data change triggers + * a FIQ. The FreeRTOS code has been modified to not mask FIQ ever. This means that the FIQ + * code will run asynchronously with regards to the other code and especially might invade critical + * sections. The actual FIQ code must therefore be as short as possible and may not call into the + * FreeRTOS API (or parts of the application that call into the FreeRTOS API). + * Instead a trick will be attempted: The PIOA IRQ will be set to fast forcing with my_fiq_handler + * as handler and the FIQ handler then does the absolutely time critical tasks without calling any + * other code. Additionally a second, normal IRQ handler is set up for a reserved IRQ on the AIC + * that is not connected to any peripherals (see #define of PIO_SECONDARY_IRQ). After handling + * the time critical tasks the FIQ handler will then manually assert this IRQ which will then + * be handled by the AIC and priority controller and also execute synchronized with regards to + * critical sections. + * Potential problem: look for race conditions between PIO data change FIQ and handling + * of PIO_SECONDARY_IRQ. + * + * Note: Originally I wanted to use 15 for the PIO_SECONDARY_IRQ but it turns out that that + * won't work (the identifier is marked as reserved). Use 31 (external IRQ1) instead. Another + * candidate would be 7 (USART1). + */ +#define USE_FIQ +#define PIO_SECONDARY_IRQ 31 +extern void my_fiq_handler(void); +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; + + /* low-level handler, used by Cstartup_app.S PIOA fast forcing and * by regular interrupt handler below */ void __ramfunc __pio_irq_demux(u_int32_t pio) @@ -94,6 +126,16 @@ static void pio_irq_demux(void) portRESTORE_CONTEXT(); } +/* nearly regular interrupt handler, in case fast forcing for PIOA is enabled and the secondary irq hack used */ +static void pio_irq_demux_secondary(void) __attribute__ ((naked)); +static void pio_irq_demux_secondary(void) +{ + portSAVE_CONTEXT(); + __pio_irq_demux(pio_irq_isr_value); + AT91F_AIC_ClearIt(PIO_SECONDARY_IRQ); + portRESTORE_CONTEXT(); +} + void pio_irq_enable(u_int32_t pio) { AT91F_PIO_InterruptEnable(AT91C_BASE_PIOA, pio); @@ -147,9 +189,6 @@ void pio_irq_init_once(void) if(!initialized) pio_irq_init(); } -#define USE_FIQ -extern void my_fiq_handler(void); -extern void fiq_handler(void); void pio_irq_init(void) { @@ -161,6 +200,13 @@ void pio_irq_init(void) 0, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &my_fiq_handler); /* enable fast forcing for PIOA interrupt */ *AT91C_AIC_FFER = (1 << AT91C_ID_PIOA); + + /* Set up a regular IRQ handler to be triggered from within the FIQ */ + AT91F_AIC_ConfigureIt(PIO_SECONDARY_IRQ, + OPENPICC_IRQ_PRIO_PIO, + AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE, &pio_irq_demux_secondary); + AT91F_AIC_ClearIt(PIO_SECONDARY_IRQ); + AT91F_AIC_EnableIt(PIO_SECONDARY_IRQ); #else AT91F_AIC_ConfigureIt(AT91C_ID_PIOA, OPENPICC_IRQ_PRIO_PIO, diff --git a/openpicc/application/ssc_picc.c b/openpicc/application/ssc_picc.c index acdf9ae..e9fdbfb 100644 --- a/openpicc/application/ssc_picc.c +++ b/openpicc/application/ssc_picc.c @@ -102,9 +102,6 @@ static const u_int16_t ssc_dmasize[] = { AT91C_SSC_TXBUFE | \ AT91C_SSC_TXSYN) -/* This stores the value that SSC_RCMR should be set to when a frame start is detected. - * Will be used in my_fiq_handler in os/boot/boot.s */ -u_int32_t ssc_rcmr_on_start = 0; void ssc_rx_mode_set(enum ssc_mode ssc_mode) { u_int8_t data_len=0, num_data=0, sync_len=0; diff --git a/openpicc/application/tc_cdiv_sync.c b/openpicc/application/tc_cdiv_sync.c index 0486f90..3405ca2 100644 --- a/openpicc/application/tc_cdiv_sync.c +++ b/openpicc/application/tc_cdiv_sync.c @@ -20,7 +20,8 @@ static void pio_data_change(u_int32_t pio) * edge */ if (*AT91C_PIOA_PDSR & OPENPICC_PIO_FRAME) { vLedSetGreen(1); - *AT91C_TC0_CCR = AT91C_TC_SWTRG; + /* This code is now replaced by hard-coded assembler code in os/boot/boot.s my_fiq_handler */ + /* *AT91C_TC0_CCR = AT91C_TC_SWTRG;*/ DEBUGPCR("CDIV_SYNC_FLIP SWTRG CV=0x%08x", *AT91C_TC0_CV); vLedSetGreen(0); @@ -72,7 +73,9 @@ void tc_cdiv_sync_init(void) AT91F_PIOA_CfgPMC(); AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC_PIO_SSC_DATA_CONTROL); - pio_irq_register(OPENPICC_PIO_FRAME, &pio_data_change); + /* This code is now replaced by hard-coded assembler code in os/boot/boot.s my_fiq_handler */ + /*pio_irq_register(OPENPICC_PIO_FRAME, &pio_data_change);*/ + (void)pio_data_change; //vLedSetGreen(0); tc_cdiv_sync_disable(); diff --git a/openpicc/os/boot/boot.s b/openpicc/os/boot/boot.s index 8faf7f3..a7e9c32 100644 --- a/openpicc/os/boot/boot.s +++ b/openpicc/os/boot/boot.s @@ -3,7 +3,7 @@ .extern main .extern exit .extern AT91F_LowLevelInit - .extern ssc_rcmr_on_start + .extern pio_irq_isr_value .text .code 32 @@ -59,6 +59,9 @@ .equ PIO_LED1, (1 << 25) .equ PIO_LED2, (1 << 12) .equ MC_RCR, 0xFFFFFF00 +.equ AIC_ISCR, (0x12C) +.equ PIO_SECONDARY_IRQ, 31 +.equ PIO_SECONDARY_IRQ_BIT, (1 << PIO_SECONDARY_IRQ) /* FIQ latency is approx 1us. At 13.56 MHz carrier frequency this means that * 13.56 cycles of the carrier have passed when the FIQ kicks in and this is @@ -265,9 +268,8 @@ fiq_handler: .func my_fiq_handler my_fiq_handler: /* code that uses pre-initialized FIQ reg */ - /* r8 AT91C_BASE_AIC (dfu init) + /* r8 tmp r9 AT91C_TC_SWTRG - //r9 AT91C_BASE_SSC r10 AT91C_BASE_PIOA r11 tmp r12 AT91C_BASE_TC0 @@ -280,20 +282,23 @@ my_fiq_handler: str r11, [r10, #PIOA_CODR] /* enable LED */ #endif ldr r8, [r10, #PIOA_ISR] + + /* Store the retrieved PIO ISR value into pio_irq_isr_value */ + ldr r11, =pio_irq_isr_value + str r8, [r11] + tst r8, #PIO_DATA /* check for PIO_DATA change */ ldrne r11, [r10, #PIOA_PDSR] tstne r11, #PIO_DATA /* check for PIO_DATA == 1 */ strne r9, [r12, #TC_CCR] /* software trigger */ - /*movne r11, #TC0_FRAME_OFFSET - strne r11, [r12, #0x10] /* Set TC0_CV to TC0_FRAME_OFFSET */ - - /* Enable SSC Rx clock from RK */ - /*ldrne r11, =ssc_rcmr_on_start - ldrne r11, [r11] - strne r11, [r9, #SSC_RCMR]*/ movne r11, #PIO_DATA strne r11, [r10, #PIOA_IDR] /* disable further PIO_DATA FIQ */ + + /* Trigger PIO_SECONDARY_IRQ */ + mov r11, #PIO_SECONDARY_IRQ_BIT + ldr r8, =AT91C_BASE_AIC + str r11, [r8, #AIC_ISCR] #ifdef LED_TRIGGER mov r11, #PIO_LED1 -- cgit v1.2.3