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 +++-- 3 files changed, 54 insertions(+), 8 deletions(-) (limited to 'openpicc/application') 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(); -- cgit v1.2.3