EmbDev.net

Forum: ARM programming with GCC/GNU tools STR9 - wierd interrupt behavior


von Dan M. (gorlash)


Rate this post
useful
not useful
We have a STR9 project that we're porting from IAR to Yagarto.  We have
interrupts on UART0, RTC, ADC (all via the standard VIC interface).  The
RTC is driven by a 32Khz external clock.  The ADC interrupt is started
off in main(), then restarts itself in the ADC IRQ.  These interrupts
have all been running fine in the IAR implementation.

When the gcc build starts up, the RTC starts up, and ticks along
merrily.  Then, after a couple of seconds, we initiate the first ADC
conversion, and the ADC interrupt triggers... once...
After that ADC interrupt, no interrupts ever occur again in the system.
The RTC, ADC, and UART interrupts all simply fail to occur any further.
Main loop is running along happily.  The cpsr shows IRQ interrupt is
enabled (cpsr = 0x2000001F).  I don't understand what could be causing
the ADC interrupt to disable all interrupts (without disabling
interrupts)... ??

I'm using the same ISR to handle all the VIC interrupts (via IRQ
interrupt), so if I'm exiting from the RTC interrupt successfully, the
ADC should be fine also.

Does anyone have any insights on this odd issue?

#*************************************************************
My IRQ ISR code:

#  STR9 firmware method from ST (Ride code)
.macro Savecontext $r0,$r4
    STMFD  sp!,{r0-r4,lr}     /* Save The workspace plus the current
return*/
                                  /* address lr_ mode into the stack.*/
  .endm

#  STR9 firmware method from ST (Ride code)
.macro RestoreContext $r0,$r4

   LDMFD   sp!,{r0-r4,pc}^  /* Return to the instruction following...*/
                            /*...the exception interrupt.*/
  .endm

#*************************************************************
My IRQ setup code (from main())

  // Initialize the real time clock(RTC) for the timer that works on the
external 32.8K crystal
  RTC_DeInit();  // RTC default configuration : Reset configuration

  //  Configure the VIC
  VIC_Config(RTC_ITLine, VIC_IRQ, 8);  // set up the RTC interrupt
priority to 8
  VIC_ITCmd(RTC_ITLine, ENABLE);  //  Enable the VIC

  // Configure the RTC to generate an interrupt 16Hz
  RTC_PeriodicIntConfig(RTC_Per_16Hz);
  RTC_ITConfig(RTC_IT_Per, ENABLE);  // Enable the RTC Periodic
interrupt

  //SCU_APBPeriphClockConfig(__ADC, ENABLE);    // Enable the clock for
the ADC
  // Configure the GPIO4 as analog input 8 pins
  GPIO_ANAPinConfig(GPIO_ANAChannelALL, ENABLE);

  //  ADC setup omitted...

  // Enable the ADC
  ADC_Cmd(ENABLE);

  // Configure the ADC
  ADC_Init(&ADC_InitStructure);

  // VIC configuration
  VIC_Config(ADC_ITLine, VIC_IRQ, 15);
  VIC_ITCmd(ADC_ITLine, ENABLE);

  // ADC interrupt config
  ADC_ITConfig(ADC_IT_ECV, ENABLE);

von Dan M. (gorlash)


Rate this post
useful
not useful
Dan Miller wrote:
> We have a STR9 project that we're porting from IAR to Yagarto.  We have
> interrupts on UART0, RTC, ADC (all via the standard VIC interface).  The
> RTC is driven by a 32Khz external clock.  The ADC interrupt is started
> off in main(), then restarts itself in the ADC IRQ.  These interrupts
> have all been running fine in the IAR implementation.
>
> When the gcc build starts up, the RTC starts up, and ticks along
> merrily.  Then, after a couple of seconds, we initiate the first ADC
> conversion, and the ADC interrupt triggers... once...
> After that ADC interrupt, no interrupts ever occur again in the system.
> The RTC, ADC, and UART interrupts all simply fail to occur any further.
> Main loop is running along happily.  The cpsr shows IRQ interrupt is
> enabled (cpsr = 0x2000001F).  I don't understand what could be causing
> the ADC interrupt to disable all interrupts (without disabling
> interrupts)... ??
>
> I'm using the same ISR to handle all the VIC interrupts (via IRQ
> interrupt), so if I'm exiting from the RTC interrupt successfully, the
> ADC should be fine also.
>
> Does anyone have any insights on this odd issue?
>
> #*************************************************************
> My IRQ ISR code:
>
> #  STR9 firmware method from ST (Ride code)
> .macro Savecontext $r0,$r4
>     STMFD  sp!,{r0-r4,lr}     /* Save The workspace plus the current
> return*/
>                                   /* address lr_ mode into the stack.*/
>   .endm
>
> #  STR9 firmware method from ST (Ride code)
> .macro RestoreContext $r0,$r4
>
>    LDMFD   sp!,{r0-r4,pc}^  /* Return to the instruction following...*/
>                             /*...the exception interrupt.*/
>   .endm

#  oops, left out the actual interrupt handler:
/*********************************************************************** 
*********
* Function Name  : IRQHandler
* Description    : This function is called when IRQ exception is
entered.
* Input          : none
* Output         : none
************************************************************************ 
********/

IRQHandler:
       SUB    lr,lr ,#4
       SaveContext r0,r4
       LDR    r0, = VectorAddress
       LDR    r0, [r0]  /* Read the routine address from VIC0 Vector
Address register  */

       BLX    r0        /* Branch with link to the IRQ handler. */
       RestoreContext r0,r4

>
> #*************************************************************
> My IRQ setup code (from main())
>
>   // Initialize the real time clock(RTC) for the timer that works on the
> external 32.8K crystal
>   RTC_DeInit();  // RTC default configuration : Reset configuration
>
>   //  Configure the VIC
>   VIC_Config(RTC_ITLine, VIC_IRQ, 8);  // set up the RTC interrupt
> priority to 8
>   VIC_ITCmd(RTC_ITLine, ENABLE);  //  Enable the VIC
>
>   // Configure the RTC to generate an interrupt 16Hz
>   RTC_PeriodicIntConfig(RTC_Per_16Hz);
>   RTC_ITConfig(RTC_IT_Per, ENABLE);  // Enable the RTC Periodic
> interrupt
>
>   //SCU_APBPeriphClockConfig(__ADC, ENABLE);    // Enable the clock for
> the ADC
>   // Configure the GPIO4 as analog input 8 pins
>   GPIO_ANAPinConfig(GPIO_ANAChannelALL, ENABLE);
>
>   //  ADC setup omitted...
>
>   // Enable the ADC
>   ADC_Cmd(ENABLE);
>
>   // Configure the ADC
>   ADC_Init(&ADC_InitStructure);
>
>   // VIC configuration
>   VIC_Config(ADC_ITLine, VIC_IRQ, 15);
>   VIC_ITCmd(ADC_ITLine, ENABLE);
>
>   // ADC interrupt config
>   ADC_ITConfig(ADC_IT_ECV, ENABLE);

von Clifford S. (clifford)


Rate this post
useful
not useful
What you have not posted is the code to the specific device handlers. I
would suggest that sight of all the code that executes when the ADC
interrupt occurs might be useful.

Interrupt share a separate stack from the normal running code. Is it
possible that your ADC interrupt has caused a stack overflow? How much
have you allocated? It needs to be sufficient to handle worst-case
interrupt nesting.

Clifford

von Spencer O. (ntfreak)


Attached files:

Rate this post
useful
not useful
Dan Miller wrote:
> Dan Miller wrote:
>> We have a STR9 project that we're porting from IAR to Yagarto.  We have
>> interrupts on UART0, RTC, ADC (all via the standard VIC interface).  The
>> RTC is driven by a 32Khz external clock.  The ADC interrupt is started
>> off in main(), then restarts itself in the ADC IRQ.  These interrupts
>> have all been running fine in the IAR implementation.
>>
>> When the gcc build starts up, the RTC starts up, and ticks along
>> merrily.  Then, after a couple of seconds, we initiate the first ADC
>> conversion, and the ADC interrupt triggers... once...
>> After that ADC interrupt, no interrupts ever occur again in the system.
>> The RTC, ADC, and UART interrupts all simply fail to occur any further.
>> Main loop is running along happily.  The cpsr shows IRQ interrupt is
>> enabled (cpsr = 0x2000001F).  I don't understand what could be causing
>> the ADC interrupt to disable all interrupts (without disabling
>> interrupts)... ??
>>
>> I'm using the same ISR to handle all the VIC interrupts (via IRQ
>> interrupt), so if I'm exiting from the RTC interrupt successfully, the
>> ADC should be fine also.
>>
>> Does anyone have any insights on this odd issue?
>>
>> #*************************************************************

All your interrupt code looks wrong, it has code missing to correctly
restore interrupts etc.

You either have a copy paste issue or have a very old and incorrect
version of ride.

Attached is my own code that may help.

Cheers
Spen

von Dan M. (gorlash)


Rate this post
useful
not useful
Thanks for your comments, Spen!!

As it turns out, after I posted the above data, I went back and compared
the IAR startup code (which our IAR project used) with the RideV7 code
that I was using for reference, and I saw that I was missing alot of
code.  Just to figure out what was going on, I just went to the ST
website this morning, and downloaded um0233.zip, which is the firmware
library that ST distributes on their support website.  Both the Ride and
EWARM/IAR code reflect the code which I posted on friday, which is
clearly incomplete.  I guess the moral is, when using ST's chips,
*don't* use ST's code to make them work.

Anyway, the updated Savecontext, Restorecontext, and IRQ_Handler code
that I'm using now agrees almost exactly with what you posted.  The only
difference is that ours uses:
       BX     r0                /* Branch to the IRQ handler. */

while yours uses:
       MOV  pc, r0    /* Branch to the IRQ handler. */

Is there any practical difference between the two??

Otherwise, interrupts now appear to be working reliably, now that I'm
finally using complete IRQ code.

//*******************************************************
Also, regarding your question about the ADC interrupt handler, I
actually put a return statement at the first instruction in
ADC_IRQHandler, to make sure it didn't have too much overhead; this made
no difference in the symptoms that we saw...

von Spencer O. (ntfreak)


Rate this post
useful
not useful
Dan,

> Anyway, the updated Savecontext, Restorecontext, and IRQ_Handler code
> that I'm using now agrees almost exactly with what you posted.  The only
> difference is that ours uses:
>        BX     r0                /* Branch to the IRQ handler. */
>
> while yours uses:
>        MOV  pc, r0    /* Branch to the IRQ handler. */
>
> Is there any practical difference between the two??
>

a bx is a v5 instruction that is equiv to the following v4 instuctions
LDR    lr, =ReturnAddress    /* Read the return address. */
MOV    pc, r0        /* Branch to the IRQ handler. */

It also can switch between arm/thumb mode, so is a better instruction to
use.

Cheers
Spen

von Dan M. (gorlash)


Rate this post
useful
not useful
Spencer Oliver wrote:
> Dan,
>
> a bx is a v5 instruction that is equiv to the following v4 instuctions
> LDR    lr, =ReturnAddress    /* Read the return address. */
> MOV    pc, r0        /* Branch to the IRQ handler. */
>
> It also can switch between arm/thumb mode, so is a better instruction to
> use.
>
Whoa!!!  Thanks for that clarification, very valuable!!
Soo... The fact that we have:

       LDR    lr, =IRQ_ReturnAddress /* ; Read the return address. */
       BX     r0                      /* ; Branch to the IRQ handler. */

is redundant??  8-{P

von Spencer O. (ntfreak)


Rate this post
useful
not useful
Actually i am getting my instructions mixed up - i was thinking of BLX
you will still need the following with a BX

LDR    lr, =IRQ_ReturnAddress /* ; Read the return address. */
BX     r0                     /* ; Branch to the IRQ handler. */

with a blx you would just require
BLX    r0                     /* ; Branch to the IRQ handler. */

On the original instruction
MOV    pc, r0        /* Branch to the IRQ handler. */
the compiler will add the switch to thumb if required, so you may save a
instruction by using the bx, you will have to check the asm to verify
this.

I have not tested the above, so double check before using.

The only limiting factor with the B* instructions is they can only
handle a +-32MB jump - whereas the LDR can jump anywhere in the arm
address space.

Cheers
Spen

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.