[gnu arm] interrupts don't work :/

Started by Pawel Sikora August 29, 2004
Hi,

I have the LPC2104 kit.
I've used the IAR-System for developing so far
but I would like to try the GNU ARM.
I've rebuilt several existing applications
that use interrupts but they don't work with GNU ARM.

How can I use interrupts with GNU ARM?
Attached I send an example of a code that works
with IAR and doesn't work with GNU ARM.

Is the crt0.s or led.c a problem?

Help is appreciated.

__________________________________




An Engineer's Guide to the LPC2100 Series

The attachment:
http://149.156.124.14/~pluto/tmp/led.zip

__________________________________



interrupt keyword does not work in GCC 3.3.1
http://gcc.gnu.org/bugzilla/show_bug.cgi?id637

try a new version or refer to

http://groups.yahoo.com/group/lpc2000/message/223

--- In , Pawel Sikora <rzulfik@y...> wrote:
> Hi,
>
> I have the LPC2104 kit.
> I've used the IAR-System for developing so far
> but I would like to try the GNU ARM.
> I've rebuilt several existing applications
> that use interrupts but they don't work with GNU ARM.
>
> How can I use interrupts with GNU ARM?
> Attached I send an example of a code that works
> with IAR and doesn't work with GNU ARM.
>
> Is the crt0.s or led.c a problem?
>
> Help is appreciated.






--- lpc2100 <> wrote:

> interrupt keyword does not work in GCC 3.3.1
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id637
>
> try a new version or refer to

I am using a GNUARM-3.4.1.

[fragment of app.s]

irq_handler:
@ Interrupt Service Routine.
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 1, uses_anonymous_args = 0
str ip, [sp, #-4]!
mov ip, sp
stmfd sp!, {r0, r1, r2, r3, r4, fp, ip, lr, pc}
sub fp, ip, #4
mvn r4, #4032
sub r4, r4, #15
ldr r3, [r4, #0]
mov lr, pc
mov pc, r3
mov r3, #0
str r3, [r4, #0]
ldmfd sp, {r0, r1, r2, r3, r4, fp, sp, lr}
ldmfd sp!, {ip}
subs pc, lr, #4

Everything (except VIC) works fine.
I don't known what is wrong :(

[app.c]

#include "iolpc210x_gcc.h"
#define bit(n) (1U << (n))

static void delay(int d)
{
while (d > 0)
d--;
}

typedef enum { YELLOW, GREEN, RED } LEDS;

static void ledOn(LEDS led)
{
switch (led)
{
case YELLOW: IOCLR.bit.P0_12 = 1; break;
case GREEN: IOCLR.bit.P0_25 = 1; break;
case RED: IOCLR.bit.P0_26 = 1; break;
}
}

static void ledOff(LEDS led)
{
switch (led)
{
case YELLOW: IOSET.bit.P0_12 = 1; break;
case GREEN: IOSET.bit.P0_25 = 1; break;
case RED: IOSET.bit.P0_26 = 1; break;
}
}

static volatile int ledStatus = 0;

void timer0_isr()
{
ledStatus = !ledStatus;
if (ledStatus)
ledOff(RED);
else
ledOn(RED);
T0IR.reg = 0xFF;
}

void init_timer()
{
VICIntSelect.reg &= ~bit(VIC_TIMER0);
VICVectAddr2 = (unsigned)&timer0_isr;
VICVectCntl2.reg = 0x20 | VIC_TIMER0;
VICIntEnable.reg = bit(VIC_TIMER0);

T0TCR.bit.CE = 0;
T0TCR.bit.CR = 1;
T0MR0 = (14745600/4)/2; // 2Hz
T0PC = 0;
T0MCR.bit.MR0INT = 1;
T0MCR.bit.MR0RES = 1;
T0CCR.reg = 0;
T0EMR.reg = 0;
T0TCR.bit.CE = 1;
}

void __irq irq_handler()
{
((void (*)())VICVectAddr)();
VICVectAddr = 0;
}

int main()
{
PINSEL0.bit.P0_12 = 0;
PINSEL1.bit.P0_25 = 0;
PINSEL1.bit.P0_26 = 0;
IODIR.bit.P0_12 = 1;
IODIR.bit.P0_25 = 1;
IODIR.bit.P0_26 = 1;
ledOff(RED);
ledOff(YELLOW);
ledOff(GREEN);
init_timer();
while (1)
{
ledOn(YELLOW); delay(50000);
ledOff(YELLOW); delay(50000);
}
}

[startup.s]

.set SYSTEM_MODE, 0x1F
.set UNDEFINED_MODE, 0x1B
.set ABORT_MODE, 0x17
.set SUPERVISOR_MODE, 0x13
.set IRQ_MODE, 0x12
.set FIQ_MODE, 0x11
.set USER_MODE, 0x10

.text
.arm
.align 0

# exception vectors
ldr pc, reset_handler_addr
ldr pc, undefined_instruction_handler_addr
ldr pc, software_interrupt_handler_addr
ldr pc, prefetch_abort_handler_addr
ldr pc, data_abort_handler_addr
ldr pc, endless_loop
ldr pc, irq_handler_addr
ldr pc, fiq_handler_addr

reset_handler_addr: .long reset_handler
undefined_instruction_handler_addr: .long
undefined_instruction_handler
software_interrupt_handler_addr: .long
software_interrupt_handler
prefetch_abort_handler_addr: .long
prefetch_abort_handler
data_abort_handler_addr: .long data_abort_handler
.long 0 /* ARM-reserved vector */
irq_handler_addr: .long irq_handler
fiq_handler_addr: .long fiq_handler

.global reset_handler
reset_handler:
msr cpsr_c, #UNDEFINED_MODE
ldr sp, =__UNDEFINED_SP__
msr cpsr_c, #ABORT_MODE
ldr sp, =__ABORT_SP__
msr cpsr_c, #SUPERVISOR_MODE
ldr sp, =__SUPERVISOR_SP__
msr cpsr_c, #IRQ_MODE
ldr sp, =__IRQ_SP__
msr cpsr_c, #FIQ_MODE
ldr sp, =__FIQ_SP__
msr cpsr_c, #USER_MODE
ldr sp, =__USER_SP__
# setup a default stack limit (when compiled with
"-mapcs-stack-check").
sub sl, sp, #__USER_STACK_SIZE__
# relocate .data(rw) section (copy from FLASH to RAM).
ldr r1, =__text_end__
ldr r2, =__data_start__
ldr r3, =__data_end__
reset_handler_L01:
cmp r2, r3
ldrlo r0, [r1], #4
strlo r0, [r2], #4
blo reset_handler_L01
# clear .bss(rw) section.
mov r0, #0
ldr r1, =__bss_start__
ldr r2, =__bss_end__
reset_handler_L02:
cmp r1, r2
strlo r0, [r1], #4
blo reset_handler_L02
# set up arguments to main and call.
mov r0, #0
mov r1, #0
bl main

.global endless_loop
endless_loop:
b endless_loop

.end

[lpc2104.ld]

MEMORY
{
FLASH(rx) : ORIGIN = 0x00000000, LENGTH = 128K
RAM(rw) : ORIGIN = 0x40000000, LENGTH = 16K
}

__STACK_START__ = 0x40000000 + 16K;

__UNDEFINED_STACK_SIZE__ = 0x0004;
__ABORT_STACK_SIZE__ = 0x0004;
__SUPERVISOR_STACK_SIZE__ = 0x0004;
__FIQ_STACK_SIZE__ = 0x0004;
__IRQ_STACK_SIZE__ = 0x0080;
__USER_STACK_SIZE__ = 0x0200;

__UNDEFINED_SP__ = __STACK_START__ - 4;
__ABORT_SP__ = __UNDEFINED_SP__ -
__UNDEFINED_STACK_SIZE__;
__SUPERVISOR_SP__ = __ABORT_SP__ -
__ABORT_STACK_SIZE__;
__FIQ_SP__ = __SUPERVISOR_SP__ -
__SUPERVISOR_STACK_SIZE__;
__IRQ_SP__ = __FIQ_SP__ - __FIQ_STACK_SIZE__;
__USER_SP__ = __IRQ_SP__ - __IRQ_STACK_SIZE__;

SECTIONS
{
. = 0;
.text :
{
__text_start__ = .;
startup.o(.text)
*(.text)
*(.glue_7)
*(.glue_7t)
}
>FLASH =0
. = ALIGN(4);
.rodata :
{
*(.rodata)
*(.rodata*)
}
>FLASH
. = ALIGN(4);
__text_end__ = .;

.data : AT(__text_end__)
{
__data_start__ = .;
*(.data)
}
>RAM
. = ALIGN(4);
__data_end__ = .;

.bss :
{
__bss_start__ = .;
*(.bss)
*(COMMON)
}
>RAM
. = ALIGN(4);
__bss_end__ = .;
}

PROVIDE(undefined_instruction_handler = endless_loop);
PROVIDE(software_interrupt_handler = endless_loop);
PROVIDE(prefetch_abort_handler = endless_loop);
PROVIDE(data_abort_handler = endless_loop);
PROVIDE(irq_handler = endless_loop);
PROVIDE(fiq_handler = endless_loop); __________________________________________________





You are running in user mode...try system mode.
(see startup.s)

--- In , Pawel Sikora <rzulfik@y...> wrote:
>
> --- lpc2100 <lpc2100@y...> wrote:
>
> > interrupt keyword does not work in GCC 3.3.1
> > http://gcc.gnu.org/bugzilla/show_bug.cgi?id637
> >
> > try a new version or refer to
>
> I am using a GNUARM-3.4.1.
>
> [fragment of app.s]
>
> irq_handler:
> @ Interrupt Service Routine.
> @ args = 0, pretend = 0, frame = 0
> @ frame_needed = 1, uses_anonymous_args = 0
> str ip, [sp, #-4]!
> mov ip, sp
> stmfd sp!, {r0, r1, r2, r3, r4, fp, ip, lr, pc}
> sub fp, ip, #4
> mvn r4, #4032
> sub r4, r4, #15
> ldr r3, [r4, #0]
> mov lr, pc
> mov pc, r3
> mov r3, #0
> str r3, [r4, #0]
> ldmfd sp, {r0, r1, r2, r3, r4, fp, sp, lr}
> ldmfd sp!, {ip}
> subs pc, lr, #4
>
> Everything (except VIC) works fine.
> I don't known what is wrong :(
>
> [app.c]
>
> #include "iolpc210x_gcc.h"
> #define bit(n) (1U << (n))
>
> static void delay(int d)
> {
> while (d > 0)
> d--;
> }
>
> typedef enum { YELLOW, GREEN, RED } LEDS;
>
> static void ledOn(LEDS led)
> {
> switch (led)
> {
> case YELLOW: IOCLR.bit.P0_12 = 1; break;
> case GREEN: IOCLR.bit.P0_25 = 1; break;
> case RED: IOCLR.bit.P0_26 = 1; break;
> }
> }
>
> static void ledOff(LEDS led)
> {
> switch (led)
> {
> case YELLOW: IOSET.bit.P0_12 = 1; break;
> case GREEN: IOSET.bit.P0_25 = 1; break;
> case RED: IOSET.bit.P0_26 = 1; break;
> }
> }
>
> static volatile int ledStatus = 0;
>
> void timer0_isr()
> {
> ledStatus = !ledStatus;
> if (ledStatus)
> ledOff(RED);
> else
> ledOn(RED);
> T0IR.reg = 0xFF;
> }
>
> void init_timer()
> {
> VICIntSelect.reg &= ~bit(VIC_TIMER0);
> VICVectAddr2 = (unsigned)&timer0_isr;
> VICVectCntl2.reg = 0x20 | VIC_TIMER0;
> VICIntEnable.reg = bit(VIC_TIMER0);
>
> T0TCR.bit.CE = 0;
> T0TCR.bit.CR = 1;
> T0MR0 = (14745600/4)/2; // 2Hz
> T0PC = 0;
> T0MCR.bit.MR0INT = 1;
> T0MCR.bit.MR0RES = 1;
> T0CCR.reg = 0;
> T0EMR.reg = 0;
> T0TCR.bit.CE = 1;
> }
>
> void __irq irq_handler()
> {
> ((void (*)())VICVectAddr)();
> VICVectAddr = 0;
> }
>
> int main()
> {
> PINSEL0.bit.P0_12 = 0;
> PINSEL1.bit.P0_25 = 0;
> PINSEL1.bit.P0_26 = 0;
> IODIR.bit.P0_12 = 1;
> IODIR.bit.P0_25 = 1;
> IODIR.bit.P0_26 = 1;
> ledOff(RED);
> ledOff(YELLOW);
> ledOff(GREEN);
> init_timer();
> while (1)
> {
> ledOn(YELLOW); delay(50000);
> ledOff(YELLOW); delay(50000);
> }
> }
>
> [startup.s]
>
> .set SYSTEM_MODE, 0x1F
> .set UNDEFINED_MODE, 0x1B
> .set ABORT_MODE, 0x17
> .set SUPERVISOR_MODE, 0x13
> .set IRQ_MODE, 0x12
> .set FIQ_MODE, 0x11
> .set USER_MODE, 0x10
>
> .text
> .arm
> .align 0
>
> # exception vectors
> ldr pc, reset_handler_addr
> ldr pc, undefined_instruction_handler_addr
> ldr pc, software_interrupt_handler_addr
> ldr pc, prefetch_abort_handler_addr
> ldr pc, data_abort_handler_addr
> ldr pc, endless_loop
> ldr pc, irq_handler_addr
> ldr pc, fiq_handler_addr
>
> reset_handler_addr: .long reset_handler
> undefined_instruction_handler_addr: .long
> undefined_instruction_handler
> software_interrupt_handler_addr: .long
> software_interrupt_handler
> prefetch_abort_handler_addr: .long
> prefetch_abort_handler
> data_abort_handler_addr: .long data_abort_handler
> .long 0 /* ARM-reserved vector */
> irq_handler_addr: .long irq_handler
> fiq_handler_addr: .long fiq_handler
>
> .global reset_handler
> reset_handler:
> msr cpsr_c, #UNDEFINED_MODE
> ldr sp, =__UNDEFINED_SP__
> msr cpsr_c, #ABORT_MODE
> ldr sp, =__ABORT_SP__
> msr cpsr_c, #SUPERVISOR_MODE
> ldr sp, =__SUPERVISOR_SP__
> msr cpsr_c, #IRQ_MODE
> ldr sp, =__IRQ_SP__
> msr cpsr_c, #FIQ_MODE
> ldr sp, =__FIQ_SP__
> msr cpsr_c, #USER_MODE
> ldr sp, =__USER_SP__
> # setup a default stack limit (when compiled with
> "-mapcs-stack-check").
> sub sl, sp, #__USER_STACK_SIZE__
> # relocate .data(rw) section (copy from FLASH to RAM).
> ldr r1, =__text_end__
> ldr r2, =__data_start__
> ldr r3, =__data_end__
> reset_handler_L01:
> cmp r2, r3
> ldrlo r0, [r1], #4
> strlo r0, [r2], #4
> blo reset_handler_L01
> # clear .bss(rw) section.
> mov r0, #0
> ldr r1, =__bss_start__
> ldr r2, =__bss_end__
> reset_handler_L02:
> cmp r1, r2
> strlo r0, [r1], #4
> blo reset_handler_L02
> # set up arguments to main and call.
> mov r0, #0
> mov r1, #0
> bl main
>
> .global endless_loop
> endless_loop:
> b endless_loop
>
> .end
>
> [lpc2104.ld]
>
> MEMORY
> {
> FLASH(rx) : ORIGIN = 0x00000000, LENGTH = 128K
> RAM(rw) : ORIGIN = 0x40000000, LENGTH = 16K
> }
>
> __STACK_START__ = 0x40000000 + 16K;
>
> __UNDEFINED_STACK_SIZE__ = 0x0004;
> __ABORT_STACK_SIZE__ = 0x0004;
> __SUPERVISOR_STACK_SIZE__ = 0x0004;
> __FIQ_STACK_SIZE__ = 0x0004;
> __IRQ_STACK_SIZE__ = 0x0080;
> __USER_STACK_SIZE__ = 0x0200;
>
> __UNDEFINED_SP__ = __STACK_START__ - 4;
> __ABORT_SP__ = __UNDEFINED_SP__ -
> __UNDEFINED_STACK_SIZE__;
> __SUPERVISOR_SP__ = __ABORT_SP__ -
> __ABORT_STACK_SIZE__;
> __FIQ_SP__ = __SUPERVISOR_SP__ -
> __SUPERVISOR_STACK_SIZE__;
> __IRQ_SP__ = __FIQ_SP__ - __FIQ_STACK_SIZE__;
> __USER_SP__ = __IRQ_SP__ - __IRQ_STACK_SIZE__;
>
> SECTIONS
> {
> . = 0;
> .text :
> {
> __text_start__ = .;
> startup.o(.text)
> *(.text)
> *(.glue_7)
> *(.glue_7t)
> }
> >FLASH =0
> . = ALIGN(4);
> .rodata :
> {
> *(.rodata)
> *(.rodata*)
> }
> >FLASH
> . = ALIGN(4);
> __text_end__ = .;
>
> .data : AT(__text_end__)
> {
> __data_start__ = .;
> *(.data)
> }
> >RAM
> . = ALIGN(4);
> __data_end__ = .;
>
> .bss :
> {
> __bss_start__ = .;
> *(.bss)
> *(COMMON)
> }
> >RAM
> . = ALIGN(4);
> __bss_end__ = .;
> }
>
> PROVIDE(undefined_instruction_handler = endless_loop);
> PROVIDE(software_interrupt_handler = endless_loop);
> PROVIDE(prefetch_abort_handler = endless_loop);
> PROVIDE(data_abort_handler = endless_loop);
> PROVIDE(irq_handler = endless_loop);
> PROVIDE(fiq_handler = endless_loop); > __________________________________________________
>




As far as I know, attribute interrupt in GCC works incorrect.
It's better to use an assembler container, for example:
.extern My_C_ISR_Func
.global ISR_Func

.text
.code 32

ISR_Func:
stmfd sp!, {r0-r12, lr}
bl My_C_ISR_Func
ldmfd sp!, {r0-r12, lr}
subs pc, lr, #4
.ltorg

--

aka cd_racer



On 24 Sep 2004 at 19:49, Konstantin V. Novick wrote:

>
> As far as I know, attribute interrupt in GCC works incorrect.
[Stuff snipped]

I believe this has been fixed in the newer versions of GCC.

Regards
Anton Erasmus

>
>
> ------------------------ Yahoo! Groups Sponsor
> --------------------~--> $9.95 domain names from Yahoo!. Register
> anything. http://us.click.yahoo.com/J8kdrA/y20IAA/yQLSAA/dN_tlB/TM
> --------------------------------~-
> > Yahoo! Groups Links >
>

--
A J Erasmus


You can do the following:

MEMMAP = MEMMAP_USERRAMMODE;
*(volatile INT32U *)(0x00000018L) = 0xE51FFFF0L;

(MEMMAP - see page 33 of UM_LPC2106_2105_2104 - user manual,
also you see page 70 of UM_LPC2106_2105_2104).

I haven't use GCC's interrupt attribute because of the old GCC version
(3.2.0). But from this thread I think that GCC use a single
entry-point for IRQ and at this point you are to do a proper jump
(using VICVectAddr register, for example). Thus you can use different
ARM-based microcontrollers in single way (in fact, the addresses of
interrupt registers are different on Atmel's AT91RM9200 and Philips
LPC2106). But in this case you are to write your IRQ entry-point
function in a proper way.

But another way is to place at IRQ vector exception's address
(0x00000018) an instruction, that loads an address from VICVectAddr
register to PC-register. Thus, there's no need to think about
entry-point function. But in this case you are to proper init the
exception vector (according to microcontroller's user manual) and
write a proper container for your's IRQ function.



GCC doesn't use the single entry-point for interrupts, but the led
example does.

--

aka cd_racer