Interrupts and AT91

I’m a real newb to the AT91SAM7X and on a bit of a learning curve. I’m having some issues trying to get an ISR on one of my PIOB inputs working. I’m using GNUARM and FreeRTOS on a small robotics project. Under FreeRTOS I’m successfully running a simple task ( blink Led) that as the name says just blinks a led, it gives me some indication that things a running, and I also have my non context switching ISR that I want to run based on a digital input PIOB, that will eventually be my wheel encoder ISR. It appears my ISR is being called when I put a high on the PIOB input port, I have my ISR turning on one of my development board Leds, this is happening the first time, then freezes the controller So I’m wondering. Do I have to re-enable interrupts manually after I complete my ISR??? Another thing I thought what could be causing it could be ISR Stack Size. Anyone know where this is set? However I don’t think it is stack size of the ISR as I have tested it by cutting the ISR back to just about nothing, and it still froze. Anyway my Interrupt setup code so far if anyone can see any serious holes that they could drive a truck though that a beginner like me might be missing. -—GPIOB_ISR.c—- /#include "Board.h" /* Scheduler includes. */ #include "FreeRTOS.h" #include "task.h" #include "queue.h" #include "semphr.h" #include "appboard.h" #include "buzzbot.h" /*———————————————————–*/ extern struct Encoder_ Encoder; /*———————————————————–*/ /* This does not cause a Context switch so is declared as IRQ */ void PIOB_ISR(void) __attribute__((interrupt("IRQ"))); /*———————————————————–*/ /* * wheel encoder runs each time interrupt occurs generated from PIOB */ void PIOB_ISR(void) { //portENTER_SWITCHING_ISR(); portENTER_CRITICAL() ; // This reads and clears the IRQ Status Register on the PIO unsigned int ulIRQ = AT91C_BASE_PIOB->PIO_ISR; //if (ulIRQ & L_WHEEL) { //TODO just for testing of ISR, need to determine source of interrupt etc // Encoder.l_Distance++; // } //if (ulIRQ & R_WHEEL) { // Encoder.r_Distance++; //} // give some thing visual if (AppLed_GetState(0)) AppLed_SetState(0,0); else AppLed_SetState(0,1); Debug( 2, "PIOB_ISR Hit!!!!" ); /* Clear AIC to complete ISR processing */ AT91C_BASE_AIC->AIC_EOICR = 0; portEXIT_CRITICAL() /* Do a task switch if needed */ //portEXIT_SWITCHING_ISR( 0 ); } -— interrupt setup code —– /* ———————————————————–*/ /* Configures PIOB for interrupt on change of state */ int Din_PIOB_Setup(void) { //unsigned int oldHandler; unsigned int mask ; // interrupts need the clock AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOB; // Configure AIC //AT91C_AIC_SRCTYPE_POSITIVE_EDGE,AT91C_AIC_SRCTYPE_EXT_LOW_LEVEL, AT91C_AIC_SRCTYPE_HIGH_LEVEL,AT91C_AIC_SRCTYPE_EXT_NEGATIVE_EDGE // gets old IRQ handler //oldHandler = AT91C_BASE_AIC->AIC_SVR[AT91C_ID_PIOB]; mask = 0x1 << AT91C_ID_PIOB ; //* Disable the interrupt on the interrupt controller AT91C_BASE_AIC->AIC_IDCR = mask ; //* Save the interrupt handler routine pointer and the interrupt priority AT91C_BASE_AIC->AIC_SVR[AT91C_ID_PIOB] = (unsigned int) PIOB_ISR ; //* Store the Source Mode Register AT91C_BASE_AIC->AIC_SMR[AT91C_ID_PIOB] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | 7 ; // IRQ Priority //* Clear the interrupt on the interrupt controller AT91C_BASE_AIC->AIC_ICCR = mask ; //* Enable the interrupt on the interrupt controller AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_PIOB ; //AT91F_AIC_EnableIt(AT91C_BASE_AIC, 0x1 << AT91C_ID_PIOB); return CONTROLLER_OK; } /*—————————————————————- */ /* Configures specified pin as a digital input and */ /* enables this pin as interrupt source */ int Din_PIOB_Enable(unsigned int pin) { // Disable output on specified PIO pin AT91C_BASE_PIOB->PIO_ODR = 0x1<<pin; AT91C_BASE_PIOB->PIO_PER = 0x1<<pin; // enable interrupt on PIO Pin AT91C_BASE_PIOB->PIO_IER = 0x1<<pin; return CONTROLLER_OK; }

Interrupts and AT91

> Under FreeRTOS I’m successfully running a simple task ( blink Led) > that as the name says just blinks a led, it gives me some indication > that things a running, and I also have my non context switching ISR > that I want to run based on a digital input PIOB, that will > eventually be my wheel encoder ISR. I would suggest writing a simple program that does not use FreeRTOS to get the PIOB interrupt working as you want first, then add the known working code to your FreeRTOS project.  Something very simple, like toggle an LED from the interrupt and have main just setup the interrupt, then sit in a for(;;); loop not doing anything (assuming your PIOB interrupt occur slowly enough to see the LED toggle). > It appears my ISR is being called when I put a high on the PIOB input > port, I have my ISR turning on one of my development board Leds, this > is happening the first time, then freezes the controller So I’m > wondering. Do I have to re-enable interrupts manually after I > complete my ISR??? You have to clear the AIC as: AT91C_BASE_AIC->AIC_EOICR = 0; Other than that, you may have to clear the BIOB interrupt also, I don’t know the details of how the port interrupts work.  You don’t need to enable interrupts as such. Maybe you ISR is being continuously entered.  Run the code in the debugger, set a break point in the ISR, then step trough the code.  Do you immediately go back into the ISR when the ISR function ends?  If so then the interrupt is still being asserted. > > Another thing I thought what could be causing it could be ISR Stack > Size. Anyone know where this is set? However I don’t think it is > stack size of the ISR as I have tested it by cutting the ISR back to > just about nothing, and it still froze. The stack size is set in the startup file – the asm file that calls main.  You will probably find a definition in there for the stack size of each processor mode. > > Anyway my Interrupt setup code so far if anyone can see any serious > holes that they could drive a truck though that a beginner like me > might be missing. Do not call ENTER_EXIT critical from the ISR – this is a definite no no.  Also don’t call a function to toggle an LED that uses enter/exit critical. The enter/exit switching isr macros need only be used if the isr causes a context switch, and should only be used if the ISR is declared as naked. I don’t know what the debug() function does – but I suspect it will be something that you don’t want to happen from within an ISR! Hope this provides some pointers.

Interrupts and AT91

Thanks for that. I’m already clearing the AIC at the end of my ISR, and by reading the PIOB Interrupt Register it should be clearing it (as I interpret the datasheet anyway) I only had the entry/exit ISR macros in to test as a "naked" ISR to see if it made any difference. I will remove everything else and test tonight without FreeRTOS when I get home as you suggest.  this was the next thing I was going to do. Thanks, Stephen…