summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--openpicc/application/pio_irq.c52
-rw-r--r--openpicc/application/ssc_picc.c3
-rw-r--r--openpicc/application/tc_cdiv_sync.c7
-rw-r--r--openpicc/os/boot/boot.s25
4 files changed, 69 insertions, 18 deletions
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 <hwelte@hmw-consulting.de>
+ * (C) 2007 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
@@ -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
personal git repositories of Harald Welte. Your mileage may vary