ARM with edge triggered vPreemptiveTick ISR

david_farrell wrote on Friday, August 15, 2008:

I have found that edge trigger interrupts work better (at least with my
rev of a AT91SAM7X256).  One caveat, the SAM7 AIX is supposed to clear ICCR
automatically (which is why I switched to edge in the first place) but I
seem to need to add:
“AT91C_BASE_AIC->AIC_ICCR = (0x1 << AT91C_ID_SYS);” to get it to work, maybe
I’m doing something else wrong?

By adding the above I was able to xTaskCreate( vQEITask,…) the same
vQEITask twice.  This task toggles a pin every 10ms. I can see on a
scope the second instance toggles about 35us after the first, works
great, every 10ms two pulses.  If I use level interrupts the second
instance of the task does not seem to run.  My guess is that one of the
interrupts is being missed…

Anyone else have similar experiences?

David.

rtel wrote on Friday, August 15, 2008:

Thanks for the info.

To be honest I cannot remember why I went for level rather than edge, maybe I copied the code from somewhere.  I know that my SAM7X devices were pre-production (seemed I got them months before they were publicly available) and had various errata - maybe that is it.  Can you post your changes here?

Regards.

david_farrell wrote on Friday, August 15, 2008:

Sorry about the pieces.  Since I’m trying to match
Atmel lib boards/components etc layout and I’m using
CodeSourcery G++ personal edition there are many changes
for layout alone diff’s are not too useful.  Ultimately I
plan on using the AT91SAM9XE256 in my design. I plan
on contributing both ports when done.

You should know, I have not tested vNonPreemptiveTick
with this!

Also as shown with ulFractional below I am looking to use the
AT91C_BASE_PITC->PITC_PIVR register as a fractional tick
counter. This in combination with your xTickCount gives a
precise time stamp.  I want to sync multiple board ticks via
gps 1pps and/or IEEE-1588. Most other chips support similar
reads of the counter although many down-count.

In port.c:

#define portINT_EDGE_SENSITIVE  AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE
#define portINT_PRIORITY 6

static void prvSetupTimerInterrupt( void )
{
#if configUSE_PREEMPTION == 0

#else
AIC_ConfigureIT( AT91C_ID_SYS, (portINT_PRIORITY | portINT_EDGE_SENSITIVE),
  ( void (*)(void) ) vPreemptiveTick );
#endif

}

In portISR.c

void vPreemptiveTick( void ) __attribute__((naked));
void vPreemptiveTick( void )
{
  /* Save the context of the current task. */
  portSAVE_CONTEXT();

  ulFractionalClock = AT91C_BASE_PITC->PITC_PIVR; /* clear PITS bit in PIT_SR */

  /* The following should be automatic with edge, but nogo ARGH! */
  AT91C_BASE_AIC->AIC_ICCR = (0x1 << AT91C_ID_SYS);
       
  /* Increment the tick count - this may wake a task. */
  vTaskIncrementTick();

  /* Find the highest priority task that is ready to run. */
  vTaskSwitchContext();
   
  /* End the interrupt in the AIC. In board_cstartup handler. */       
  AT91C_BASE_AIC->AIC_EOICR = 0;
       
  portRESTORE_CONTEXT();
}

Regards,

David.

david_farrell wrote on Sunday, August 17, 2008:

After reviewing my code I have one more thought to add.
One possible reason to use level vs edge is that more than one
source may cause the interrupt. The level is cleared when you
clear all possible sources. Edge does not have this option.
I only use the PIT interrupt with AT91C_ID_SYS.