SAM7 interrupt problem with FreeRTOS

johannes_sch wrote on Sunday, November 04, 2007:

I have a problem with the SPI0 interrupt on the AT91SAM7XC256 when using FreeRTOS.
After running the SPI initialization code 1) the SPI ISR is immediately called once, like in the standalone application using no OS, and after serving the ISR the program is continued as usual. But using FreeRTOS the SPI ISR 2) is called and called again in an endless manner, the according Interrupt Pending bit PID4=SPI0 in the AIC Interrupt Pending Register stays set, not even the vPreemptiveTick ISR is called although its priority is the highest. Using an other declaration type of the SPI ISR 3) does not change anything.

The SPI initialization code is called in a separate task, the whole program is derived from the lwIP_Demo_Rowley_ARM7 which works fine in case I disable the SPI interrupt (the EMAC and USB interrupts, which are declarated the same way, work pretty fine).

Any ideas whats going wrong here?
Thanks in advance,

1) SPI initialization code:
void SPI0_Init(void)
        // Configure SPI0 PIOs (CS3=PA15, MISO=PA16, MOSI=PA17, SCK=PA18)
        AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, AT91C_PA15_SPI0_NPCS3 + AT91C_PA16_SPI0_MISO + AT91C_PA17_SPI0_MOSI + AT91C_PA18_SPI0_SPCK, 0);   
        // Configure PMC by enabling SPI clock
        // Configure SPI interrupt
        AT91F_AIC_ConfigureIt(AT91C_ID_SPI0, (AT91C_AIC_PRIOR_LOWEST + 0), AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, (void(*)(void)) vSPI0_ISR_Wrapper);
        AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SPI0);   
        // Reset the SPI (note it is possible to reset the SPI even if SPI is disabled)
        AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SWRST;    // SPI is in slave mode after reset
        // Enable SPI
        // Set Mode Register
        AT91C_BASE_SPI0->SPI_MR = AT91C_SPI_MSTR + AT91C_SPI_MODFDIS + (AT91C_SPI_PCS & 7<<16);    // Master, Fixed Peripheral, CS’s direct connected, Take CS3
        // Set Chip Select Register
        AT91C_BASE_SPI0->SPI_CSR[3] = AT91C_SPI_CPOL + AT91C_SPI_CSAAT + AT91C_SPI_BITS_8 + (AT91C_SPI_SCBR & 4<<8); // p.278
        // Workaround Bug p.668
        AT91C_BASE_SPI0->SPI_CSR[0] = AT91C_SPI_CPOL + AT91C_SPI_CSAAT + AT91C_SPI_BITS_8 + (AT91C_SPI_SCBR & 4<<8); // p.278

2) SPI0 ISR type 1

void vSPI0_ISR_Wrapper( void ) __attribute__((naked));

void vSPI0_ISR_Handler( void );

void vSPI0_ISR_Handler( void )
volatile unsigned portLONG ulIntStatus;
portBASE_TYPE xSwitchRequired = pdFALSE;

    ulIntStatus = AT91C_BASE_SPI0->SPI_SR;

    if( ulIntStatus & AT91C_SPI_ENDRX )


    if( xSwitchRequired )

void  vSPI0_ISR_Wrapper( void )



3) SPI ISR type 2

void vSPI0_ISR_Wrapper( void ) __attribute__((interrupt("IRQ")));

void vSPI0_ISR_Wrapper( void )
volatile unsigned portLONG ulIntStatus;

    ulIntStatus = AT91C_BASE_SPI0->SPI_SR;

    if( ulIntStatus & AT91C_SPI_ENDRX )


davedoors wrote on Monday, November 05, 2007:

As your code listing 3 has the same behavior I would suggest that FreeRTOS is not anything to do with the problem as listing 3 is just a standard IRQ function.

I have the SPI working but using the PDC to generate interrupts.  To clear the interrupt I read the status register and write to AIC_EOICR as you are doing.  I also disable the ENDRX interrupt, which gets enabled again when the next Rx is about to occur.  I cannot remember my thinking when writing the interrupt but I know it works well.  Maybe the interrupt keeps firing until the reason for it goes away, meaning the register is full again.  This is how the UART works on the SAM7 I think so it is reasonable for the SPI to do the same.

johannes_sch wrote on Monday, November 05, 2007:

Hi Dave,
Thank you very much for your help, the PDC which I’m also using in my application was exactly the problem as you described. Although, I’m still a little confused because the Interrupt works properly in my standalone-application using no operating system at all, but otherwise exactly (up to the critial section macros) the same initialization code and the same interrupt code…
Anyway, now it works.
Thank you very much,

jon_newcomb wrote on Tuesday, November 06, 2007:

I was repeatedly plagued by crashes after peripheral initialisation, such as the OS not starting if the UART RX was connected to ground - but worked OK if pulled high… button presses causing crashes if pressed during startup…

This was due to ISRs triggering BEFORE a call to vTaskStartScheduler() had been made.

When the ISR called portEND_SWITCHING_ISR(), it restored the context of the last task - which prior to running vTaskStartScheduler() was just uninitialised memory… needless to say, it didn’t live long after that!

I played around by trying to prevent ISRs triggering until the vTaskStartScheduler() had been called, but still kept on getting caught out… in the end I moved all peripheral initialisation into a single ‘startup task’ (which implies its run after vTaskStartScheduler() has been called). The last part of the ‘startup task’ then up kicked of the rest of the application tasks. All my problems went after that.

Looking at all the example code, peripheral initialisation for UARTS etc. is done prior to calling vTaskStartScheduler()… I never really felt comfortable making such a large change to the basic structure of even the simplest examples… yes, they worked in the beginning, but when code was fleshed out and bits of hardware connected in… things started to fall apart.

What are others views on the subject of peripheral initialisation… before or after vTaskStartScheduler()?

davedoors wrote on Tuesday, November 06, 2007:

You can also get a problem when an interrupt attempts to use a queue or semaphore that has not yet been created.

The SAM7 does some odd things.  It often fires an interrupt during peripheral initialization.  This happens on several different peripherals.  It also is not easy to reset correctly meaning code will often work following a power down reset but not following a reset via the JTAG.

The FreeRTOS code examples for GCC SAM7 demos [I think] has a line in the hardware setup function called from main to kill everything in the interrupt controller to get around the JTAG reset problem.  Also interrupts generally remain disabled until the scheduler is started as a side effect of having the nesting count set to non zero by default.

My preference is to initialize peripherals in the task that uses the peripheral.  Care must be taken with sequencing to ensure the peripheral is initialized before any other task uses it as well.

void aFunction( void *pv )
         /* Task code. */

dspaude wrote on Tuesday, November 06, 2007:

I used a startup task for some of my initialization, but I did most of my hardware (SAM7) initialization before  the OS started. The way I dealt with the interrupt endlessly triggering was to have a global startup flag that would allow the interrupt to be fully handled otherwise it would just do what was necessary to clear the interrupt, not allow any OS calls, and exit the ISR. Before the system is fully up certain interrupts should be ignored anyway.

dsvend wrote on Tuesday, April 08, 2008:


i have run into the same problem. I did the INTs initialization inside a task, after the scheduler has started, but it did not fix it.

Could you find a solution ?



karthiksubbu wrote on Thursday, April 17, 2008:


I have a similar problems with interrupts. Sorry for the big post.

I am using FreeRTOS v4.72 for AT91SAM7X256 with IAR 5.11.

I am using UART Interrupts for transferring serial data. Along with this I also have the LED tasks.

I find that after a reset in the debugger, the UART interrupts stop working. I either have to try reseting many times till it starts working at some point or use the Reset button on the AT91SAM7X-EK Eval board. Sometimes even the Reset button has no impact.

Most of the times the problem would be with the interrupts with the LEDs working just fine. But in some cases even the LEDs stop working.

I thought this could be a problem with the debugger so I switched out of the Debug mode to normal mode and tried the manual reset and found that the interrupts were still not working.

I decided to check with a lower version of FreeRTOS and IAR compiler and used FreeRTOS v4.70 and IAR 4.41A and found that the application works fine without any reset problems.

After going thru some posts in the forum, i got to know that .mac file and interrupts being enabled before the Scheduler start could cause problems. So i went ahead to modify my code and ensured that initializations are handled after Kernel starts, interrupts are disabled in the Startup file and also added the code to Reset AIC in the .mac file. In spite all these I had no luck and the problem persisted.

After a lot of tweaking around I discovered that the problem vanished when I changed the .mac file. FreeRTOS provides three .mac files namely SAM7.mac, SAM7_FLASH.mac and SAM7_RAM.mac. The demo selects SAM7.mac. I changed it to SAM7_FLASH.mac and there was no issue with the reset or the interrupts.

I am still not sure if this is the exact solution. Also I found that there are extra functions in the SAM7.mac than compared to SAM7_FLASH.mac. I am not sure about the impact of using the FLASH.mac version of the file. Could someone throw some light on this issue.

Any suggestion / explanation would be of great help.

Thanks a lot.

davedoors wrote on Thursday, April 17, 2008:

I think you did the right thing. Its almost certainly a problem with the macro file not initializing the processor into the state you want when doing a soft reset over the JTAG.