Yahoo Groups archive

Lpc2000

Index last updated: 2026-04-28 23:31 UTC

Thread

how to tell IRQ stack size

how to tell IRQ stack size

2005-06-29 by elef_papa

Hi,

After many hours trying to figure out why the cpu kept freezing, i
fixed it by changing the following in my startup file:

was:         .equ    IRQ_Stack_Size, 0x00000080
changed to:  .equ    IRQ_Stack_Size, 0x00001000

obviously the original value was not enough for the IRQ function and
it was probably overwriting the stack from the USR mode (im
guessing?!? correct me if im wrong)

Anyways, im using winarm (GNU GCC 4.0.0) and want to know how can i
tell how much ram a function/IRQ needs, so i can set the .equ   
IRQ_Stack_Size without having to guess?

Thanks
Eleftherios

Re: [lpc2000] how to tell IRQ stack size

2005-06-29 by Jim Parziale

Here's something I had done a long time ago:
- Set your stack size large (maybe the 0x1000 you have is way too big?)
- When you set up the stack in your boot.s or startup.s, fill it with a 
known pattern (like 0xBEEF)
- Run your code for a while (definition of "while" is up to you... :-)
- Stop the processor and look at your stack in memory. Whatever is still 
your known pattern is what wasn't used.

You can roughly estimate stack usage by looking at the calls you're making 
from your ISR. You shouldn't be making too many nested routine calls inside 
an ISR, and especially not with lots of parameters.
Local variables also factor in heavily. Trade-off is between how much stack 
you want to take up and how many global variables you really need.

Jim

On 6/29/05, elef_papa <elef_papa@...> wrote:
> 
> Hi,
> 
> After many hours trying to figure out why the cpu kept freezing, i
> fixed it by changing the following in my startup file:
> 
> was: .equ IRQ_Stack_Size, 0x00000080
> changed to: .equ IRQ_Stack_Size, 0x00001000
> 
> obviously the original value was not enough for the IRQ function and
> it was probably overwriting the stack from the USR mode (im
> guessing?!? correct me if im wrong)
> 
> Anyways, im using winarm (GNU GCC 4.0.0) and want to know how can i
> tell how much ram a function/IRQ needs, so i can set the .equ
> IRQ_Stack_Size without having to guess?
> 
> Thanks
> Eleftherios
>


[Non-text portions of this message have been removed]

Re: how to tell IRQ stack size

2005-06-30 by Dave

--- In lpc2000@yahoogroups.com, "elef_papa" <elef_papa@y...> wrote:
> Hi,
> 
> After many hours trying to figure out why the cpu kept freezing, i
> fixed it by changing the following in my startup file:
> 
> was:         .equ    IRQ_Stack_Size, 0x00000080
> changed to:  .equ    IRQ_Stack_Size, 0x00001000
> 
> obviously the original value was not enough for the IRQ function and
> it was probably overwriting the stack from the USR mode (im
> guessing?!? correct me if im wrong)
> 
> Anyways, im using winarm (GNU GCC 4.0.0) and want to know how can i
> tell how much ram a function/IRQ needs, so i can set the .equ   
> IRQ_Stack_Size without having to guess?
> 
> Thanks
> Eleftherios

Hello,

  My approach to this is to use the user stack, in system mode.
  This way, I only ever use 12 bytes of irq stack space.
  Here is some gnu 'C' code to demonstrate.

/*
*/

#define ARM_MODE_IRQ	0x12
#define ARM_MODE_SYS	0x1F
#define I_BIT			0x80

// SWITCH_TO_SYSTEM() - An inline assembler function to
//                      switch stacks from the IRQ stack to the USER
stack.
//                      Thus the interrupt handler operates in SYSTEM
mode.
//

extern inline void SWITCH_TO_SYSTEM(void)
{
	// Adjust and save LR_irq in IRQ stack
	__asm volatile ("	sub         lr, lr, #4" : : : "lr");
	__asm volatile ("	stmfd       sp!, {lr}" : : : "sp");

	// Save SPSR and r0 in IRQ stack
	__asm volatile ("	mrs         lr, SPSR" : : : "lr");
	__asm volatile ("	stmfd       sp!, {r0, lr}" : : : "sp");

	// Enable Interrupt and Switch in SYS Mode
	__asm volatile ("	mrs         r0, CPSR" : : : "r0");
	__asm volatile ("	bic         r0, r0, %0" : : "i" (I_BIT) : "r0");
	__asm volatile ("	orr         r0, r0, %0" : : "i" (ARM_MODE_SYS) : "r0");
	__asm volatile ("	msr         CPSR_c, r0");

	// Save scratch/used registers and LR in User Stack
	__asm volatile ("	stmfd       sp!, {r1-r3, r12, lr}" : : : "sp");
}

// RETURN_FROM_SYSTEM() - Returns a SYSTEM mode handler to the IRQ
stack, and
//                        then to the interrupted code. This is done
by an assembly
//                        language inline function that switches the
stack to the IRQ
//                        stack, and then retruns from the interrupt
after acknowledging
//                        it to the interrupt controller.

extern inline void RETURN_FROM_SYSTEM(void)
{
	// Restore scratch/used registers and LR from User Stack
	__asm volatile ("	ldmia       sp!, {r1-r3, r12, lr}" : : : "sp",
"r1", "r2", "r3", "r12", "lr");

	// Disable Interrupt and switch back in IRQ mode
	__asm volatile ("	mrs         r0, CPSR" : : : "r0");
	__asm volatile ("	bic         r0, r0, %0" : : "i" (ARM_MODE_SYS) : "r0");
	__asm volatile ("	orr         r0, r0, %0" : : "i" (I_BIT |
ARM_MODE_IRQ) : "r0");
    __asm volatile ("	msr         CPSR_c, r0");

	// Restore SPSR_irq and r0 from IRQ stack
	__asm volatile ("	ldmia       sp!, {r0, lr}" : : : "sp", "r0", "lr");
    __asm volatile ("	msr         SPSR, lr");

	// Restore adjusted  LR_irq from IRQ stack directly in the PC
	__asm volatile ("	ldmia       sp!, {pc}^" : : : "sp", "pc");
}

and an example of usage:

void timer0_irq_handler(void) __attribute__((naked))
{
	led_on(LED_TIMER_0);

	++global_timer;

	// scan the inputs
	scanInputs();

	// Clear interrupt flag
	T0IR = TIMER_IR_MR0;

	led_off(LED_TIMER_0);
}

// setup timer 0 to generate 1mS interrupts
int timer0Init(void)
{
	// power up the timer
	PCONP |= PCONP_PCTIM0;

	// initialise global millisecond counter
	global_timer = 0;

	// set count divisor
	T0MR0 = ONE_MS;

	// Interrupt and Reset on MR0
	T0MCR = TIMER_MCR_RESET_MR0 | TIMER_MCR_IRQ_MR0;

	// Timer1 Enable
	T0TCR = TIMER_CR_ENABLE;

	return setVector(TIMER0_PRIORITY, VECTOR_TIMER0, (unsigned long)
timer0_asm_irq_handler);
}



//
// Vector handling
//
int setVector(int priority, int vectorNum, unsigned long handler)
{
	// make sure priority and vectorNum are in range
	if (priority < 0 || priority > 15)
		return 0;

	if (vectorNum < 0 || vectorNum > VECTOR_MAX)
		return 0;

	// set handler
	VICVectAddrBase[priority] = handler;

	// enable it
	VICVectCntlBase[priority] = VICVECCTRL_ENABLE | vectorNum;

	// make sure that the IRQ is used, not the FIQ
	//VICIntSelect &= ~(1 << vectorNum);

	// and the interrupt
	VICIntEnable = (1 << vectorNum);

	return 1;
}

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.