Hi all,
i ported u-boot bootloader for 5307 successfully. It is working fine, except for an interrupt issue, when i enable a timer interrupt for the clock.
Here the issue: after the interrupt (exception) happen, the "rte" generate a "bad address/fetch" ecxeption (VEC 3, FMT 4, FAULT 4), generated just after the "rte". Everything before the "rte" in the interrupt handler is executed correctly. If i left in the interrupt handler routine the "rte" only, issue is the same.
Any help is very appreciated,
Thanks
angelo
You seem to be writing the interrupt service routine in assembly. In that case it looks like there's something wrong with your stack. Is the stack pointer set up properly? Is the RAM it is using set up OK? Can you read and write that RAM OK?
If you're using a debugger, break before the RTE and see what the stack frame is like. Compare that with the manuals that say what the RTE expects.
Check this for a possible simpler way to write interrupt routines - this depends on your development environment and compiler:
https://community.freescale.com/thread/85650
Tom
Hi Tom,
many thanks for the help,
i ported the famous u-boot opensource bootloader for the M5307 since this Coldfire model, almost in last package, was not supported.
I also added the support for this little custom board i developed.
http://194.177.99.211/~angelo/amcore.jpg
U-boot, in the start-up process, start from flash, and relocate his code into ram (you can chose internal SRAM or as in my case in SDRAM). This is done to let u-boot to be able to eventually rewrite the flash memory, and the boot loader itself. The code of the bootloader is near to 40KB, after the relocation in top of SDRAM a stack is allocated just before the code (below), then the program jump to SDRAM.
First initialization routines from ram, after the new stack has been setup into ram, are executed properly, so i don't see any reason why, after an interrupt occours, rte should fail.
I reduced the interrupt handler in the asm file as:
_interrupt_handler: rte
I can loop before the rte, and still all is working.
As you said, i can have some issues on my sdram, i will check all the ram size with a proper test.
Anyway, stack seems to be set up correctly, since before the interupt occours several functions are called from ram.
I also locked the program counter just after the timer initialization with a for (;; to be sure no other things are causing the exception 3.
Is hard to debug actually, but i will try to know the stack frame values before the rte.
Thanks again
> I reduced the interrupt handler in the asm file as:
Probably not your current problem, but in these CPUs you have to write some code to make the interrupt request go away.
Different peripherals need the interrupts acknowledged in different ways. Usually you have to write a "1" to clear the Interrupt Request bit in a status register. Otherwise when the RTE returns the original interrupt request is still active and the interrupt is re-entered immediately.
A lot of people have trouble with burst reads and writes to and from the SDRAM. With the cache disabled the CPU only makes single read and write requests. When the cache is enabled the cache fills are burst reads. If there's anything wrong with the SDRAM programming or the burst-related memory connections, then that is when the problems show up.
You can run the stack in SRAM (and it makes the whole thing faster) to simplify it a bit.
Are you enabling interrupts in U-Boot or in your App (loaded from u-Boot) or are you using u-Boot "as the operating system" to run your code?
Tom
Tom
Hi TomE,
thanks for the useful help and suggestions,
i was some days off, tonight i jumped back on the board.
To answer your question, i am using u-boot as a bootloader/trampoline, just to copy linux into sdram memory and to jump on it. Anyway u-boot enable interrupts for some stuff, as to give a timestamp using a console time command.
Unfortunately, still nothing good.
I did the following tests:
1) Reenabled completely the interrupt request, as original u-boot code. I don't think u-boot have issues here, it is quite stable, anyway, i ported many cpu-related files from another coldfire model, since 5307 was not completely supported, so there can be issues.
This is the original assembly interrupt handler code part:
/* handlers */#define ipush \ move.w #0x2700,%sr; /* disable intrs */ \ subl #60,%sp; /* space for 15 regs */ \ moveml %d0-%d7/%a0-%a6,%sp@; \#define ipop \ moveml %sp@,%d0-%d7/%a0-%a6; \ addl #60,%sp; /* space for 15 regs */ \ rte .globl _exc_handler_exc_handler: ipush movel %sp,%sp@- bsr exc_handler addql #4,%sp ipop
Then int_handler is called, and there, as you suggested, the timer interrupt is cleared correctly.
Anyway, clearing it, generate quite immedately another interrupt, with continuos exceptions:
U-Boot 1.1.6 (May 27 2011 - 00:09:24)CPU: Freescale Coldfire MCF5307 at 90 MHzBoard: Sysam AMCORE BoardDRAM: 16 MBStack set to 00fa1f78Start relocate of code from ffc00400 to 00ff2000Now running in RAM - U-Boot at: 00ff2000*** Unex*** Une*** Unex*** Une
2) i tried to disable the cache, nothing change.
3) i tested completely the sdram, all 16 MB, it is working properly. This ram once setup correctly, without shorts or open pins, works always perfectly.
If you have any other suggestion, it is welcome, really.
Thanks again
angelo
ex_handler() calls int_handler().
Something in that chain is enabling the interrupts again.
Possibly the code driving the serial port.
What test is failing for it to print "*** Unex..."? I assume the code is checking to see if the interrupt it received was one it expected, or was one registered with the handler.
The handler may have interrupt numbers hard-wired to the CPU you ported FROM and the MCF5307 may have moved them.
Can you single-step the code? Do you have a debug pod? If so just single step it and see where it goes and why.
Is it getting to the timer interrupt service routine, or is it derailing before that?
Tom
Hi Tom,
thanks again,
probably i made some confusiuon and my not perfect english also helped.
This is how u-boot works:
1) a function called trap_init(0) is called to initialize all the exceptions handlers to the same assembly functions, exc_handler or int_handler. Just after, every specific interrupt handler is set through irq_install_handle() function:
/************************************************************************/ /* * Install an interrupt handler */ void irq_install_handler (int vec, interrupt_handler_t * handler, void *arg) { int vec_base = 0; if ((vec < vec_base) || (vec > vec_base + NR_IRQS)) { printf ("irq_install_handler: wrong interrupt vector %d\n", vec); return; } irq_vecs[vec - vec_base].handler = handler; irq_vecs[vec - vec_base].arg = arg; } void trap_init(ulong value) { // value is set to 0, VBR table offset unsigned long *vec = (ulong *)value; int i; for(i = 2; i < 25; i++) { vec[i] = (unsigned long)_exc_handler; } for(i = 25; i < 32; i++) { vec[i] = (unsigned long)_int_handler; } for(i = 32; i < 64; i++) { vec[i] = (unsigned long)_exc_handler; } for(i = 64; i < 256; i++) { vec[i] = (unsigned long)_int_handler; } setvbr(value); /* set vector base register to new table */}
2) assembly code of these functions is really simple, it just redirect to an higher level routine (exc_handler or int_handler (note withoout underscore), that redirect to the right real C interrupt handler.
/* handlers */#define ipush \ move.w #0x2700,%sr; /* disable intrs */ \ subl #60,%sp; /* space for 15 regs */ \ moveml %d0-%d7/%a0-%a6,%sp@; \#define ipop \ moveml %sp@,%d0-%d7/%a0-%a6; \ addl #60,%sp; /* space for 15 regs */ \ rte .globl _exc_handler_exc_handler: ipush movel %sp,%sp@- bsr exc_handler addql #4,%sp ipop .globl _int_handler_int_handler: ipush movel %sp,%sp@- bsr int_handler addql #4,%sp ipop
3) at the end, the correct C handler, if set, is called
void int_handler (struct pt_regs *fp){ volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE2); int vec, vec_base = 0; vec = (fp->vector >> 2) & 0xff; /* disable TIMER 2 interrupt and trace the stack */ timerp->timer_tmr = MCFTIMER_TMR_DISABLE; show_frame(fp); for(;;); if (irq_vecs[vec - vec_base].handler != NULL) { irq_vecs[vec - vec_base].handler (irq_vecs[vec - vec_base].arg); } else { printf ("\nBogus External Interrupt Vector %d\n", vec); }}int interrupt_init (void){ enable_interrupts (); return 0;}
As you can see, i traced stack and registers from the interrupt function:
Stack set to 00fa1f78
Start relocate of code from ffc00400 to 00ff2000
Now running in RAM - U-Boot at: 00ff2000
We are: 00fVector Number: 31 Format: 04 Fault Status: 0
PC: ffffffff SR: 00002009 SP: 00fa1d9c
D0: 00000000 D1: 0000001d D2: 00000066 D3: 00fb1f90
D4: ffffbfff D5: dfffff7e D6: eff7ffef D7: 00fb1f90
A0: 00fb1f90 A1: 00ff24c0 A2: 00fa1e3e A3: 00ffd000
A4: 7ff5fbef A5: 00ffc000 A6: 00fa1de4
The strange thing is that the PC that shoud be the address where to return is 0xffffffff, from this, probably, the exception is generated just after the "rte".
regards,
angelo
movel %sp,%sp@- bsr int_handler addql #4,%sp ipop...void int_handler (struct pt_regs *fp)
The above code is written assuming an ABI where all the function parameters are passed on the stack.
Does that match your build environment - does that match the compiler? Some have an ABI where the first few parameters are passed in registers. This caused some incompatibility between different versions of Code Warrior.
Disassemble "int_handler" and see if it is getting "fp" from the stack or from a register.
I'd also suggest single-stepping the interrupt one assembly instruction at a time, and watching all the registers and the stack contents to see what is going wrong.
Tom