Yahoo Groups archive

Lpc2000

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

Message

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;
}

Attachments

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.