Yahoo Groups archive

Lpc2000

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

Message

Re: [lpc2000] {To TomW} GCC-Bug in IRQs

2006-03-27 by David Hawkins

Hi Clemens,

> wouldn't this handler need the "naked" attribute when using the stub
> above? would you please write out the declaration in full?

With the assembler coded stub in place, the functions loaded
into the VIC are standard C functions. The code requires no
attributes anywhere. Maximum portability.

Given that the functions called by the VIC are standard,
they adhere to the ACPS, and so the assembler stub just
handles the caller save registers and expects the compiler
to do-the-right-thing for the rest.

The example code below demonstrates this ...

Cheers
Dave


/* ex10_main.c
  *
  * Software generated EINT[0:3] example (non-nested IRQs)
  */
#include "led.h"

/* ----------------------------------------------------------------
  * LPC2138 registers
  * ----------------------------------------------------------------
  */
#define VICIRQStatus    (*((volatile unsigned long *) 0xFFFFF000))
#define VICIntSelect    (*((volatile unsigned long *) 0xFFFFF00C))
#define VICIntEnable    (*((volatile unsigned long *) 0xFFFFF010))
#define VICSoftInt      (*((volatile unsigned long *) 0xFFFFF018))
#define VICSoftIntClear (*((volatile unsigned long *) 0xFFFFF01C))
#define VICVectAddr     (*((volatile unsigned long *) 0xFFFFF030))
#define VICDefVectAddr  (*((volatile unsigned long *) 0xFFFFF034))
#define VICVectAddr0    (*((volatile unsigned long *) 0xFFFFF100))
#define VICVectAddr1    (*((volatile unsigned long *) 0xFFFFF104))
#define VICVectAddr2    (*((volatile unsigned long *) 0xFFFFF108))
#define VICVectAddr3    (*((volatile unsigned long *) 0xFFFFF10C))
#define VICVectCntl0    (*((volatile unsigned long *) 0xFFFFF200))
#define VICVectCntl1    (*((volatile unsigned long *) 0xFFFFF204))
#define VICVectCntl2    (*((volatile unsigned long *) 0xFFFFF208))
#define VICVectCntl3    (*((volatile unsigned long *) 0xFFFFF20C))

/* ----------------------------------------------------------------
  * Function declarations and globals
  * ----------------------------------------------------------------
  */
void irq_init();
void fiq_handler(void);
typedef void(*irq_handler_t)(void);

void irq_handler(void);
void eint0_handler(void);
void eint1_handler(void);
void eint2_handler(void);
void eint3_handler(void);

/* IRQ register bit locations */
#define EINT0 (1 << 14)
#define EINT1 (2 << 14)
#define EINT2 (4 << 14)
#define EINT3 (8 << 14)

/* ----------------------------------------------------------------
  * Function definitions
  * ----------------------------------------------------------------
  */

/* Setup the IRQ interrupts */
void irq_init(void)
{
   /* Setup the VIC to have EINT[0:3] generate IRQs */
   VICIntSelect   = 0;                           /* Select IRQ      */
   VICVectAddr0   = (unsigned long)eint0_handler;/* Vector 0        */
   VICVectAddr1   = (unsigned long)eint1_handler;/* Vector 1        */
   VICVectAddr2   = (unsigned long)eint2_handler;/* Vector 2        */
   VICVectAddr3   = (unsigned long)eint3_handler;/* Vector 3        */
   VICVectCntl0   = 0x20 | 14;                   /* EINT0 Interrupt */
   VICVectCntl1   = 0x20 | 15;                   /* EINT1 Interrupt */
   VICVectCntl2   = 0x20 | 16;                   /* EINT2 Interrupt */
   VICVectCntl3   = 0x20 | 17;                   /* EINT3 Interrupt */
   VICIntEnable   = (0xF << 14);                 /* Enable          */

}

/* VICVectAddr dispatch loop */
void irq_handler(void)
{
	/* Process IRQ interrupts */
	irq_handler_t handler;
	while (VICIRQStatus) {
		/* Get the address of the highest priority handler */
		handler = (irq_handler_t)VICVectAddr;

		/* Execute the handler */
		(*handler)();

		/* Acknowledge the VIC */
		VICVectAddr = 0;
	}
}

void eint0_handler(void)
{
	/* Clear interrupt source */
	VICSoftIntClear = EINT0;

	/* Processing EINT0 complete */
	led_clr(1);
}

void eint1_handler(void)
{
	/* Clear interrupt source */
	VICSoftIntClear = EINT1;

	/* Process EINT1 */

	/* Trigger EINT0 */
	led_set(1);
	VICSoftInt = EINT0;

	/* Processing EINT1 complete */
	led_clr(2);
}

void eint2_handler(void)
{
	/* Clear interrupt source */
	VICSoftIntClear = EINT2;

	/* Process EINT2 */

	/* Trigger EINT1 */
	led_set(2);
	VICSoftInt = EINT1;

	/* Processing EINT2 complete */
	led_clr(4);
}

void eint3_handler(void)
{
	/* Clear interrupt source */
	VICSoftIntClear = EINT3;

	/* Process EINT3 */

	/* Trigger EINT2 */
	led_set(4);
	VICSoftInt = EINT2;

	/* Processing EINT3 complete */
	led_clr(8);
}

/* Empty handler (since the startup code references it) */
void fiq_handler(void)
{
	return;
}

/* ----------------------------------------------------------------
  * Application
  * ----------------------------------------------------------------
  */
int main (void)
{
	led_init();
	/* Start low */
	led(0);
	irq_init();
	while(1) {
		/* Trigger EINT3 */
		led_set(8);
		VICSoftInt = EINT3;
	}
	return 0;
}


/* ex10a_start.s */

     .global main
     .global _start
	
     /* Symbols defined by the linker script */
     .global _etext
     .global _data
     .global _edata
     .global _bss
     .global _ebss

     /* External functions */
     .global fiq_handler
     .global irq_handler

     .text
     .arm

/* ----------------------------------------------------------------
  * Exception vectors
  * ----------------------------------------------------------------
  */
_start:
     b reset  /* reset */
     b loop   /* undefined instruction */
     b loop   /* software interrupt */
     b loop   /* prefetch abort */
     b loop   /* data abort */
     nop      /* reserved for the bootloader checksum */
     ldr pc, irq_addr

     /* FIQ ISR */
fiq_isr:
     sub   lr, lr, #4
     stmfd sp!, {r0-r3, ip, lr}
     bl fiq_handler
     ldmfd sp!, {r0-r3, ip, pc}^

irq_addr: .word irq_isr
irq_isr:
     sub   lr, lr, #4
     stmfd sp!, {r0-r3, ip, lr}
     bl irq_handler
     ldmfd sp!, {r0-r3, ip, pc}^

/* ----------------------------------------------------------------
  * LPC21xx PLL setup
  * ----------------------------------------------------------------
  */
reset:
     /* Use r0 for indirect addressing */
     ldr	r0, PLLBASE

     /* PLLCFG = PLLCFG_VALUE */
     mov	r3, #PLLCFG_VALUE
     str r3, [r0, #PLLCFG_OFFSET]

     /* PLLCON = PLLCON_PLLE */
     mov	r3, #PLLCON_PLLE
     str r3, [r0, #PLLCON_OFFSET]

     /* PLLFEED = PLLFEED1, PLLFEED2 */
     mov	r1, #PLLFEED1
     mov	r2, #PLLFEED2
     str r1, [r0, #PLLFEED_OFFSET]
     str r2, [r0, #PLLFEED_OFFSET]

     /* 	while ((PLLSTAT & PLLSTAT_PLOCK) == 0); */
pll_loop:
     ldr r3, [r0, #PLLSTAT_OFFSET]
     tst	r3, #PLLSTAT_PLOCK
     beq	pll_loop

     /* PLLCON = PLLCON_PLLC|PLLCON_PLLE */
     mov	r3, #PLLCON_PLLC|PLLCON_PLLE
     str r3, [r0, #PLLCON_OFFSET]

     /* PLLFEED = PLLFEED1, PLLFEED2 */
     str r1, [r0, #PLLFEED_OFFSET]
     str r2, [r0, #PLLFEED_OFFSET]

/* ----------------------------------------------------------------
  * LPC21xx MAM setup
  * ----------------------------------------------------------------
  */
mam_init:
     /* Use r0 for indirect addressing */
     ldr	r0, MAMBASE

     /* MAMCR = MAMCR_VALUE */
     mov	r1, #MAMCR_VALUE
     str r1, [r0, #MAMCR_OFFSET]

     /* MAMTIM = MAMTIM_VALUE */
     mov	r1, #MAMTIM_VALUE
     str r1, [r0, #MAMTIM_OFFSET]

/* ----------------------------------------------------------------
  * LPC21xx stacks setup
  * ----------------------------------------------------------------
  */
stacks_init:
     ldr r0, STACK_START

     /* FIQ mode stack */
     msr CPSR_c, #FIQ_MODE|IRQ_DISABLE|FIQ_DISABLE
     mov sp, r0
     sub r0, r0, #FIQ_STACK_SIZE

     /* IRQ mode stack */
     msr CPSR_c, #IRQ_MODE|IRQ_DISABLE|FIQ_DISABLE
     mov sp, r0
     sub r0, r0, #IRQ_STACK_SIZE

     /* Supervisor mode stack */
     msr CPSR_c, #SVC_MODE|IRQ_DISABLE|FIQ_DISABLE
     mov sp, r0
     sub r0, r0, #SVC_STACK_SIZE

     /* Undefined mode stack */
     msr CPSR_c, #UND_MODE|IRQ_DISABLE|FIQ_DISABLE
     mov sp, r0
     sub r0, r0, #UND_STACK_SIZE

     /* Abort mode stack */
     msr CPSR_c, #ABT_MODE|IRQ_DISABLE|FIQ_DISABLE
     mov sp, r0
     sub r0, r0, #ABT_STACK_SIZE

     /* System mode stack */
/*    msr CPSR_c, #SYS_MODE|IRQ_DISABLE|FIQ_DISABLE*/
     msr CPSR_c, #SYS_MODE
     mov sp, r0

     /* Leave the processor in system mode */

/* ----------------------------------------------------------------
  * C runtime setup
  * ----------------------------------------------------------------
  */
runtime_init:
     /* Copy .data */
     ldr r0, data_source
     ldr r1, data_start
     ldr r2, data_end
copy_data:
     cmp   r1, r2
     ldrne r3, [r0], #4
     strne r3, [r1], #4
     bne   copy_data
	
     /* Clear .bss */
     ldr r0, =0
     ldr r1, bss_start
     ldr r2, bss_end
clear_bss:
     cmp   r1, r2
     strne r0, [r1], #4
     bne   clear_bss

     /* Jump to main */
     bl  main

/* Catch return from main */
loop:   b   loop

/* ----------------------------------------------------------------
  * 32-bit constants (and storage)
  * ----------------------------------------------------------------
  *
  * These 32-bit constants are used in ldr statements.
  */

/* LPC SRAM starts at 0x40000000, and there is 32Kb = 8000h */
STACK_START:	.word   0x40008000
PLLBASE:        .word   0xE01FC080
MAMBASE:        .word   0xE01FC000

/* Linker symbols */
data_source:    .word   _etext
data_start:     .word   _data
data_end:       .word   _edata
bss_start:      .word   _bss
bss_end:        .word   _ebss

/* ----------------------------------------------------------------
  * 8-bit constants
  * ----------------------------------------------------------------
  *
  * These 8-bit constants are used as immediate values and offsets.
  */

/* PLL configuration */
     .equ PLLCON_OFFSET,   0x0
     .equ PLLCFG_OFFSET,   0x4
     .equ PLLSTAT_OFFSET,  0x8
     .equ PLLFEED_OFFSET,  0xC

     .equ PLLCON_PLLE,    (1 << 0)
     .equ PLLCON_PLLC,    (1 << 1)
     .equ PLLSTAT_PLOCK,  (1 << 10)
     .equ PLLFEED1,        0xAA
     .equ PLLFEED2,        0x55

     .equ PLLCFG_VALUE,    0x24

/* MAM configuration */
     .equ MAMCR_OFFSET,   0x0
     .equ MAMTIM_OFFSET,  0x4

     .equ MAMCR_VALUE,    0x2  /* fully enabled */
     .equ MAMTIM_VALUE,   0x4  /* fetch cycles  */

/* Stack configuration */
     /* Processor modes (see pA2-11 ARM-ARM) */
     .equ FIQ_MODE,       0x11
     .equ IRQ_MODE,       0x12
     .equ SVC_MODE,       0x13  /* reset mode */
     .equ ABT_MODE,       0x17
     .equ UND_MODE,       0x1B
     .equ SYS_MODE,       0x1F

     /* Stack sizes */
     .equ FIQ_STACK_SIZE, 0x00000080    /*  32x32-bit words */
     .equ IRQ_STACK_SIZE, 0x00000080
     .equ SVC_STACK_SIZE, 0x00000080
     .equ ABT_STACK_SIZE, 0x00000010    /*   4x32-bit words */
     .equ UND_STACK_SIZE, 0x00000010
     .equ SYS_STACK_SIZE, 0x00000400    /* 256x32-bit words */

     /* CPSR interrupt disable bits */
     .equ IRQ_DISABLE,    (1 << 7)
     .equ FIQ_DISABLE,    (1 << 6)

     .end

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.