Forums » Software Development »
Bare-metal interrupt handling working only in debugger
Added by Alexandre Lopes over 9 years ago
Hello,
I am using the MitySOM Dev Kit and I want to use interrupts in a bare-metal
application. To that effect I wrote a 'small' program where I enable the private
timer (and the interrupt bit as well) and wrote an IRQ handler.
The interrupt vector table is at offset 0x0 (the default) using the Mentor Sourcery
linker scripts (which use __cs3_interrupt_vector).
I then configure the GIC appropriately and set the VBAR register in the coprocessor
to point to the location of the interrupt vector table (in my case, 0x30000000),
just like Altera's Hardware Library (in fact, I'm using portions of the code).
The interrupt handler simply sets a flag which main() checks in order to print
a message via UART (the function to print to UART does work outside of the debugger):
int main(void) { char msg[80]; sprintf(msg, "Interrupt!\r\n"); PRIVATE_TIMER_HANDLE_t handle; /* enable interrupts */ socfpga_int_start(); /* initialize timer */ private_timer_init(&handle, ALT_INT_INTERRUPT_PPI_TIMER_PRIVATE, CPU_TARGET); while(1) { /* main loop */ /* if there's an interrupt, the handler sets the flag variable */ if (flag) { /* write to UART */ uart_write(msg); /* unset variable */ flag = 0; } } return 0; }
Whenever I run this program using the debugger using the following DS script (
which first loads U-Boot in order to do rempping, etc.)
# # Reset and stop the system. # reset system wait 30s stop wait 30s # # Disable semihosting. # set semihosting enabled false # # Load the SPL preloader into memory. # loadfile "$sdir/u-boot-spl.axf" 0x0 # # Enable semihosting. # set semihosting enabled true # # Delete any existing breakpoints. # delete # # Set a breakpoint in the SPL function spl_boot_device(). This function is # called right before the SPL tries to load the next stage in the preloader. # tbreak spl_boot_device # # Set the PC to the entry point and go. # run # # Wait for the breakpoint. # wait # # Load the demo program. # loadfile "$sdir/main.axf" 0x0 # # Run the target and break at main(). # start
everything runs flawlessly. The ARM jumps to the right address and
the interrupts are properly handled. However, whenever I load the code
from U-Boot either using the binary and doing
ext2load mmc 0:2 0x30000000 main.bin go 0x30000000
or by writting a SCREC file via the terminal interface, it simple doesn't print
anything (again, it's not the uart_write function since that works outside of
the debugger).
Any idea where the problem might be? I'm assuming someone out there has gotten
this to work... (by the way, the fact that an ELF file is loaded in the first
case, should not be the issue since all code/data is contiguous and loaded
at 0x30000000)
Thanks!
Replies (5)
RE: Bare-metal interrupt handling working only in debugger - Added by Michael Williamson over 9 years ago
I personally haven't tried to do this before, but isn't address 0x30000000 the base of your interrupt vector table? Is that the actual runtime entry point (a jump instruction to the CRT) or is that an address for a reset interrupt? Can you provide the linker map of the main.bin? Is that main.bin an ELF file?
Sorry for the 20 questions, but would like to get a handle on the format of the blob you are stuffing into memory.
-Mike
RE: Bare-metal interrupt handling working only in debugger - Added by Alexandre Lopes over 9 years ago
Hi Mike,
That address is indeed the base of the interrupt table. I have been using it without any problem with other programs, which run just fine and which were compiled using the same linker script (which always inserts a vector table at offset 0x0). They simply have no IRQ handler, the GIC was not configured, the VBAR not set, etc...
In any case, from that adddress it should branch to a reset handler which simply jumps to the actual _start. The entrypoint is at offset 0x40. I have tried to load the program from this address, also to no avail.
The file main.bin is not an ELF file but a raw binary file produced using
objcopy.
Here's the beginning of the ELF file (main.axf)
main.axf: file format elf32-littlearm Disassembly of section .text: 30000000 <__cs3_interrupt_vector>: 30000000: 18 f0 9f e5 18 f0 9f e5 18 f0 9f e5 18 f0 9f e5 ................ 30000010: 18 f0 9f e5 18 f0 9f e5 18 f0 9f e5 18 f0 9f e5 ................ 30000020: 40 00 00 30 54 cb 00 30 58 cb 00 30 5c cb 00 30 @..0T..0X..0\..0 30000030: 60 cb 00 30 50 cb 00 30 dc 1e 00 30 64 cb 00 30 `..0P..0...0d..0 30000040 <__cs3_reset>: 30000040: ea000024 b 300000d8 <_start>
and the output of readelf
ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: ARM Version: 0x1 Entry point address: 0x30000040 Start of program headers: 52 (bytes into file) Start of section headers: 115120 (bytes into file) Flags: 0x5000202, has entry point, Version5 EABI, soft-float ABI Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 2 Size of section headers: 40 (bytes) Number of section headers: 18 Section header string table index: 15
The linker script is the default
cycloneV-dk-ram-hosted.ldwith this small modification
ram (rwx) : ORIGIN = 0x30000000, LENGTH = 256M
(since I need to leave the lower addresses free).
Thanks,
Alex
RE: Bare-metal interrupt handling working only in debugger - Added by Alexandre Lopes over 9 years ago
I am now thinking that I might have to use the unhosted version of the linker script (even though it worked just fine for compiling programs without interrupt handlers).
Might be that the Sourcery compiler does something 'weird' with the hosted linker script + interrupt handlers.
At the moment I don't have the board here but tomorrow morning I'll try it.
RE: Bare-metal interrupt handling working only in debugger - Added by Alexandre Lopes over 9 years ago
No, that was obviously not the reason. The unhosted and hosted linker scripts do link against different libraries but that only seems matters for stdio. I was able to solve the problem by rewritting everything from scratch. The way I was doing it was the way Altera implemented on their Hardware Library, which messes with the entire GIC. Now I only write to very specific addresses of the GIC (the ones pertaining to the interrupts I am interrested in) and it works flawlessly with U-Boot and with a Linux/Baremetal AMP system.
Alex
RE: Bare-metal interrupt handling working only in debugger - Added by Michael Williamson over 9 years ago
Hi Alex,
Glad you solved your issue, sorry we didn't provide much help. We don't have a lot of folks trying to do Bare-Metal (and we don't do it often either).
-Mike