diff options
| -rw-r--r-- | openpicc/application/pio_irq.c | 52 | ||||
| -rw-r--r-- | openpicc/application/ssc_picc.c | 3 | ||||
| -rw-r--r-- | openpicc/application/tc_cdiv_sync.c | 7 | ||||
| -rw-r--r-- | openpicc/os/boot/boot.s | 25 | 
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 | 
