EmbDev.net

Forum: ARM programming with GCC/GNU tools AT91SAM7S256: Problem with interrupt setup


von Chris B. (chris301)


Rate this post
useful
not useful
Hello all,

I’m currently setting up my AT91SAM7S256 (Olimex EvalBoard, Yagarto
Toolchain) and try to implement interrupts in RAM-code, however I don’t
succeed. I have checked all available sample code (from various forums,
from Martin Thomas, etc.) and – at least to me – the code looks OK, but
still no satisfying result..

My project is based on Jim Lynch’s tutorial, I use (without
modification) blinker.c, crt.s, isrsupport.c, lowlevelinit.c,
script.ocd, makefile, demo_at91sam7_blink_ram.cmd, and all h- and
a-files.
Main.c looks like this:

//  *******************************************************
#include "AT91SAM7S256.h"
#include "board.h"
#include "math.h"
#include "stdlib.h"
#include "string.h"

//                External References
extern  void LowLevelInit(void);
//extern  unsigned enableIRQ(void);  //xxx
//extern  unsigned enableFIQ(void);  //xxx
AT91PS_PIO p_PIO;
AT91PS_PMC p_PMC;
AT91PS_AIC p_AIC;

unsigned int  FiqCount = 0;    // global uninitialized variable

//interrupt handler: switch off LED1
void interrupt_handler_button (void)
{
  p_PIO->PIO_SODR = LED1;    //switch off LED1
}

int  main (void) {

  unsigned int test;
  unsigned long k;

  p_PIO = AT91C_BASE_PIOA;
  p_PMC = AT91C_BASE_PMC;
  p_AIC = AT91C_BASE_AIC;

  LowLevelInit();

  p_PMC->PMC_PCER = (1 << AT91C_ID_PIOA);
//  p_PMC->PMC_PCER = (1<<AT91C_ID_IRQ0);             //yyy
//  p_PMC->PMC_PCER = (1<<AT91C_ID_IRQ1);             //yyy
  test=p_PMC->PMC_PCSR;

  p_PIO->PIO_PER = LED_MASK;  //activate I/O for LEDs
  p_PIO->PIO_OER = LED_MASK;  //configure LEDs as ouput
  p_PIO->PIO_CODR = LED1 | LED2;  //define initial status of output pins
  p_PIO->PIO_SODR = LED3;    //define initial status of output pins
  p_PIO->PIO_PER = SW_MASK;  //activate I/O for buttons
  p_PIO->PIO_ODR = SW_MASK;  //configure buttons #1, #2 as input
  p_PIO->PIO_IFER = SW_MASK;  //activate glitch filtering
  p_PIO->PIO_MDDR = SW_MASK;  //deactivate multi drive control
  p_PIO->PIO_PPUER = SW_MASK;  //activate pull-ups for buttons

  p_AIC->AIC_IDCR = 0x1<<AT91C_ID_PIOA;  //firstly, deactivate interrupt
  p_AIC->AIC_SVR[AT91C_ID_PIOA] = (unsigned int)
interrupt_handler_button;  //specify interrupt handler function
  p_AIC->AIC_SMR[AT91C_ID_PIOA] =
(AT91C_AIC_SRCTYPE_POSITIVE_EDGE|AT91C_AIC_PRIOR_HIGHEST);  //interrupt
typ+priority
  p_AIC->AIC_ICCR = 0x1<<AT91C_ID_PIOA;  //read (and clear) interrupts
  p_PIO->PIO_IER = SW_MASK; //activate input change interrupt of buttons
  p_AIC->AIC_IECR = AT91C_ID_PIOA;  //enable interrupts

  //enable interrupts
//  enableIRQ();                //xxx
//  enableFIQ();                //xxx

  while (1) {
    //blink LED1
    if  ((p_PIO->PIO_ODSR & LED2) == LED2)
      p_PIO->PIO_CODR = LED2;    // LED1 (DS1) on
    else
      p_PIO->PIO_SODR = LED2;    // LED1 (DS1) off

    for (k = 1000000; k != 0; k-- );  // wait 1 second

  }
}


My most urgent question is, why does the interrupt not work? I would
expect that the function interrupt_handler_button is entered when I
press one of the push-buttons, but nothing happens!

Other open questions are:
- when I un-comment the code lines marked with yyy, I would expect to
read in the variable “test” the result of having activated AT91C_ID_IRQ0
and AT91C_ID_IRQ1. But that’s not the case, PMC_PCSR’s bit 30 and 31 can
never be set to 1. Why?
- Do I need Jim’s code lines marked with xxx (enableIRQ and enableFIQ)
or can I drop them if I write my own interrupt handlers (e.g. functions
like interrupt_handler_button)? I have a feeling that I should always
use at least enableIRQ to be able to use nested interrupt handlers, but
I’d like to confirm this assumption.

Thanks a lot for any answer,

christian

von Proc Proc (Guest)


Rate this post
useful
not useful
Hello Christian, do you have any solution (sample code for ext int) yet?
I still have problems with ext int too as you can read at
Beitrag "Externer Interrupt auf AT91SAM7X-EK mit Eclipse"

von Kees S. (kees)


Rate this post
useful
not useful
Chris Breitenbach wrote:
> Hello all,
>
> I’m currently setting up my AT91SAM7S256 (Olimex EvalBoard, Yagarto
> Toolchain) and try to implement interrupts in RAM-code, however I don’t
> succeed. I have checked all available sample code (from various forums,
> from Martin Thomas, etc.) and – at least to me – the code looks OK, but
> still no satisfying result..
>
> My project is based on Jim Lynch’s tutorial, I use (without
> modification) blinker.c, crt.s, isrsupport.c, lowlevelinit.c,
> script.ocd, makefile, demo_at91sam7_blink_ram.cmd, and all h- and
> a-files.
> Main.c looks like this:
>
> //  *******************************************************
> #include "AT91SAM7S256.h"
> #include "board.h"
> #include "math.h"
> #include "stdlib.h"
> #include "string.h"
>
> //                External References
> extern  void LowLevelInit(void);
> //extern  unsigned enableIRQ(void);  //xxx
> //extern  unsigned enableFIQ(void);  //xxx
> AT91PS_PIO p_PIO;
> AT91PS_PMC p_PMC;
> AT91PS_AIC p_AIC;
>
> unsigned int  FiqCount = 0;    // global uninitialized variable
>
> //interrupt handler: switch off LED1
> void interrupt_handler_button (void)
> {
>   p_PIO->PIO_SODR = LED1;    //switch off LED1
> }
>
> int  main (void) {
>
>   unsigned int test;
>   unsigned long k;
>
>   p_PIO = AT91C_BASE_PIOA;
>   p_PMC = AT91C_BASE_PMC;
>   p_AIC = AT91C_BASE_AIC;
>
>   LowLevelInit();
>
>   p_PMC->PMC_PCER = (1 << AT91C_ID_PIOA);
> //  p_PMC->PMC_PCER = (1<<AT91C_ID_IRQ0);             //yyy
> //  p_PMC->PMC_PCER = (1<<AT91C_ID_IRQ1);             //yyy
>   test=p_PMC->PMC_PCSR;
>
>   p_PIO->PIO_PER = LED_MASK;  //activate I/O for LEDs
>   p_PIO->PIO_OER = LED_MASK;  //configure LEDs as ouput
>   p_PIO->PIO_CODR = LED1 | LED2;  //define initial status of output pins
>   p_PIO->PIO_SODR = LED3;    //define initial status of output pins
>   p_PIO->PIO_PER = SW_MASK;  //activate I/O for buttons
>   p_PIO->PIO_ODR = SW_MASK;  //configure buttons #1, #2 as input
>   p_PIO->PIO_IFER = SW_MASK;  //activate glitch filtering
>   p_PIO->PIO_MDDR = SW_MASK;  //deactivate multi drive control
>   p_PIO->PIO_PPUER = SW_MASK;  //activate pull-ups for buttons
>
>   p_AIC->AIC_IDCR = 0x1<<AT91C_ID_PIOA;  //firstly, deactivate interrupt
>   p_AIC->AIC_SVR[AT91C_ID_PIOA] = (unsigned int)
> interrupt_handler_button;  //specify interrupt handler function
>   p_AIC->AIC_SMR[AT91C_ID_PIOA] =
> (AT91C_AIC_SRCTYPE_POSITIVE_EDGE|AT91C_AIC_PRIOR_HIGHEST);  //interrupt
> typ+priority
>   p_AIC->AIC_ICCR = 0x1<<AT91C_ID_PIOA;  //read (and clear) interrupts
>   p_PIO->PIO_IER = SW_MASK; //activate input change interrupt of buttons
>   p_AIC->AIC_IECR = AT91C_ID_PIOA;  //enable interrupts
>
>   //enable interrupts
> //  enableIRQ();                //xxx
> //  enableFIQ();                //xxx
>
>   while (1) {
>     //blink LED1
>     if  ((p_PIO->PIO_ODSR & LED2) == LED2)
>       p_PIO->PIO_CODR = LED2;    // LED1 (DS1) on
>     else
>       p_PIO->PIO_SODR = LED2;    // LED1 (DS1) off
>
>     for (k = 1000000; k != 0; k-- );  // wait 1 second
>
>   }
> }
>
>
> My most urgent question is, why does the interrupt not work? I would
> expect that the function interrupt_handler_button is entered when I
> press one of the push-buttons, but nothing happens!
>
> Other open questions are:
> - when I un-comment the code lines marked with yyy, I would expect to
> read in the variable “test” the result of having activated AT91C_ID_IRQ0
> and AT91C_ID_IRQ1. But that’s not the case, PMC_PCSR’s bit 30 and 31 can
> never be set to 1. Why?
> - Do I need Jim’s code lines marked with xxx (enableIRQ and enableFIQ)
> or can I drop them if I write my own interrupt handlers (e.g. functions
> like interrupt_handler_button)? I have a feeling that I should always
> use at least enableIRQ to be able to use nested interrupt handlers, but
> I’d like to confirm this assumption.
>
> Thanks a lot for any answer,
>
> christian

Hi Christian,

The type of interrupt that you want is definitely an IRQ interrupt, so
you probably want call the enableIRQ in your program. The reason that
your interrupts are not working might have something to do with your
startup code. It is not shown here, so I am just guessing, but....

I would first check in what processor mode your code runs. The startup
code initializes the various stacks and specifies whether or not the
IRQ's and FIQ's are enabled for all processor modes. Suppose that the
startup code switches to USR mode and disables the IRQ's (Sets the
I-bit), then it is not so easy to enable it in your C-program. Since the
ARM processor does not allow you do clear the IRQ flag while in USR
mode, the enableIRQ function does not work. Switching to another mode
while in USR mode is not easy either.

So, either you have to change your startup code and keep running in SYS
mode, or you have to write a SWI handler and write some SWI code that
does enable the interrupts. When the swi instruction is executed, the
processor mode switches to SVC mode, and then you can clear the IRQ flag
for USR mode.

But then again, I am just guessing since I do not know what your startup
code does.

Kees.

von Rick Hamilton (Guest)


Rate this post
useful
not useful
This is probably old, but.... Just in case anyone wants to know the 
solution to the problem

  p_AIC->AIC_IECR = AT91C_ID_PIOA;  //enable interrupts

Should be

  p_AIC->AIC_IECR = 1 << AT91C_ID_PIOA;  //enable interrupts

(very easy to miss)

Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
No account? Register here.