This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Interrupt exception vector handling with bootlaoder

Other Parts Discussed in Thread: HALCOGEN

Hello,

In my current project i need to implement a bootloader for firmware update purpose. The bootlaoder is at the beginning of the flash and gets invoked after a power up or reset. If a update is necessary the bootloader updates the application otherwise starts the application at address 0x8000 (32kByte). So far the application is called by the bootloader as expected but behaves different than if programmed without bootloader at address 0x00.

The application has a couple of safety init features enabled like the ESRAM ECC Check (SAFETY INIT tab in HALCoGen) which provokes a data abort interrupt. This resolves to two issues, first the interrupt jumps to the execption vector located at address 0x00 instead of address 0x8000. This I can explain with 's statement in this post http://e2e.ti.com/support/microcontrollers/hercules/f/312/t/124544.aspx. I have to dispatch manually to the applications exception vector. Secondly it's not the data abort interrupt (at address 0x10) which is called but the prefetch abort (at address 0x0C).

Is there anywhere an example how to deal with this matter. Even as the bootloader example http://processors.wiki.ti.com/index.php/RM48_HDK_Kit doesn't show a solution to this an won't work for applications using exception vectors or FIQs.

Thanks in advance

Joachim

  • Joachim,

    Actually, I had many discussion about this interesting topic recently.  The following discussion is based on the assumptions (1) bootloader and application are independent entities such that changes in application will not affect bootloader and vice versa, and (2) bootloader only needs to handle reset and IRQ/FIQ.

    There are two types of interrupts on TMS570. The first types are exceptions such as reset, SWI, data and prefetch abort, etc. The second type is IRQs and FIQs.

    For IRQs  and FIQs, CPU directly fetches the ISR address from VIM module. If the hardware vector mode is enabled, CPU will not even jump to the exception vector at 0x00000018 or 0x0000001c. You can configure VIM module and RAM independently for the bootloader and application. The hardware vector mode can be enabled by the discussion in the following thread.

    http://e2e.ti.com/support/microcontrollers/hercules/f/312/t/183311.aspx

    Since the exception vector table is not relocatable, Every time a reset or an abort happens, CPU will jump to the vectors starting at address 0x0. Assume that your bootloader occupies addresses from 0x0 to 0x7fff, and application starts at 0x8000. you can set up the bootloader vector table at 0x0 as follows,

        b _c_int00 ; entry point to bootloader

        b 0x8004   ; jump to application vector for processing

        b 0x8008   ; jump to application vector for processing

        b 0x800c   ; jump to application vector for processing

        b 0x8010  ; jump to application vector for processing

        b 0x8014  ; jump to application vector for processing

    In your application project, you need to put the vector table at address 0x8000. In this set up, when an exception occurs, CPU will first jump to the bootlaoder exception vector starting at address 0x0 and then jump to the application exception vector starting at address 0x8000. After a reset, CPU will always enter boot loader first. In the bootloader, you need to use intruction "b 0x8000" to jump to application. If you want to debug your application without bootloader, you can change the vector address in the application link command file from 0x8000 to 0x0.Or you cna change the first instruction in the bootloader vector from "b _cint00' to "b 0x8000".

    The limitation of this idea is that you cannot enable ECC for the bootloader because abort handling is not allowed for bootloader.

    Please let me know if this idea works for you. Please notify us if you can think of something better out of this discussion. 

    Thanks and regards,

    Zhaohong

  • Zhaohong,

    Thanks for your informative answer. Unfortunately it doesn't solve the problem.

    The hardware vector mode is enabled already by HALCoGen with the tick "Enable IRQ Handling via VIC Controller" which produces exactly the assembler code you provided.

    The ESRAM ECC Check should trigger a data abort exception. What it does actually is generating a prefetch abort exception. Thats all I see with the debugger. After the instruction "ramread = tcramA2bit;" generated by HALCoGen (sys_selftest.c, in function checkB0RAMECC()) the PC jumps to 0x0C (prefetch abort) and sticks to there. Not even the jump to 0x800C is executed.

    Any idea why the appliaction triggers a different exception interrupt and why the PC sticks to that address?

    Thanks and regards,

    Joachim

  • Joachim,

    I forgot one thing in my earlier email. Although you do not enable Flash ECC for the bootloader, you need to calculate and ECC for the boot loader S/W. When you purposely generate a data abort in your application by a data read, CPU will generate a data abort and jump to address 0x10. If the ECC is not programmed for address 0x10, a prefetch abort will occur and CPU jumps to address 0xC. If ECC for address 0x C is not programmed, CPU will be locked into prefetch abort and you will see CPU locks to address 0xC. You can put breakpoints at address 0xC and 0x10. You should see CPU first stop at 0x10 and then locks to 0xC.

    Thanks and regards,

    Zhaohong

  • Zhaohong,

    Thank you, this helped quite a lot to the situation. I won't get any prefetch aborts anymore.

    But first, somehow the assembler instruction for the  jump from exception vector of the bootloader to the one of the app is weird. For the data abort I have to write

    b    #0x7FF8

    instead of the expected

    b    #0x8010

    Do you have any idea why?

    Second, now I get  a step further in the app but get a undefined exception somewhere later. In the application code i just changed the command file telling the linker to start placing the code from address 0x8000. Do I have to make other modifications, or should this be enough?

    Thanks a lot and have a nice weekend

    Joachim

  • Joachim,

    "b #0x77f8" is branch to an offset of 0x8000 from the current location. Branching back to current location is " b #-8". For branching to address 0x8000, you should use "b 0x8000".

    CPU always starts at 0x0. If you want to focusing on debugging the application, I would suggest you reserving the space from 0x800 to 0x820 and put the exception vector to 0x0. You can put it back to 0x8000 after everything in the application is working and start integrating with bootloader.

    Thanks and regards,

    Zhaohong

  • Zhaohong,

    "b 0x8000" doesn't work with the assembler: [E0004]  Illegal operand

    Everything (Application and Bootloader) works fine with the app's exception vector at 0x00 (what you proposed to do). Something with the jump from 0x00 to 0x8000 seems to crash the system. Any idea?

    Best regards,

    Joachim

  • Joachim,

    Branches in ARM-v7R are relative.

    You can find this information in the ARM Assembler Reference: http://infocenter.arm.com/help/topic/com.arm.doc.dui0489e/Cihfddaf.html#id4685232


    What you also need to know for using the Branch instruction is the following:

    In ARM state, the value of the PC is the address of the current instruction plus 8 bytes.

    This can be found in the ARM Using the Assembler document: http://infocenter.arm.com/help/topic/com.arm.doc.dui0473e/Cacdbfji.html

    Which means if you want to do a branch from address 0x0 to 0x8000 you need an branch instruction with the offset 0x7FF8 (0x8000 - 0x0 - 0x8 ; Destination - Source (PC) - 0x8)

    One more thing I forget to add: In the TI assembler each immediate value has to start with #

    Best Regards,

    Christian

  • Joachim,

    Do you use "b #0x7ff8" at address 0x0 to jump to address 0x8000? Can you put "b #-8" at address 0x8000 to check if branch occurs correctly? After a power-on-reset, CPU will starts at address 0x0. When you connect debugger to CPU, you should see PC at 0x8000. To branch to 0x8000 from the bootloader, you can call an assembly function from c-code. The assembly function can be constructed as follows assuming that you use eabi compiling option.

        .global branch2address
    .text
    branch2address:    
       b r0     ;no need to to save any register because CPU branches to a new application
       bx lr
    .end

    Calling in C:

    extern void branch2address(unsigned int address);

    branch2address(0x8000);

    Thanks and regards,

    Zhaohong

  • Zhaohong,

    Ok, I found the solution. My exception table in the bootloader looks now like this:

        b   _c_int00    ;0x00
        b     #0x7FF8     ;0x04, undefined instruction
        b    #0x7FF8     ;0x08, Software interrupt
        b    #0x7FF8     ;0x0C, Abort (prefetch)
        b    #0x7FF8     ;0x10, Abort (data)
        b   #0x7FF8     ;0x14
        ldr pc,[pc,#-0x1b0]    ;0x18 IRQ
        ldr pc,[pc,#-0x1b0] ;0x1C FIQ

    The last two entries were missing (IRQ and FIQ). The ADC interrupts are configured in FIQ mode and if triggered jump to 0x1C. So long so good, but why is this? You said that the IRQs and FIQs are reallocated to VIM by hardware, this seems not to be the case for FIQ. Furthemore what does instruction "ldr pc,[pc,#-0x1b0]" and why is a simple "b   #0x7FF8" not working here?

    Hopefully you can bring some light into the dark.

    Thanks and regards,

    Joachim

  • Joachim,

    we have three different possibilities to react on interrupts:

    1. Legacy ARM7 Mode: In this mode the software designer has to write a software dispatcher for the FIQ and IRQ.
    2. Vectored interrupt: In this mode the VIM module dose the dispatching for IRQ and FIQ and has an register which shows the address of the pending interrupts routine. The CPU has to load the vector address to the PC via a LDR instruction.
    3. Hardware Vectored Interrupt: This mode is only available for IRQ. In this mode the VIM dose the dispatching and supplies the vector address to the Cortex-R4F CPU via the VIC Port. This mode is similar to #2 but it saves the load instruction on address 0x18 and thus a few cycles.

    The default setup in HALCoGen is to use #3 for IRQ and #2 for FIQ.

    The "LDR PC, [PC, #-0x1B0]" instruction is necessary for #2. In this mode the CPU has to load the vector address from the VIM register IRQVECREG for IRQ's and FIQVECREG for FIQ's.

    IRQVECREG is at 0xFFFF_FE70

    FIQVECREG is at 0xFFFF_FE74

    The coding for the LDR instruction is similar as for the branches I described in my post before.

    "LDR PC, [PC, #-0x1B0]" at address 0x18 resolves to a load from address 0xFFFF_FE70. (-0x1B0 == 0xFFFF_FE50 --> 0xFFFF_FE50 + 0x18 + 0x8 = 0xFFFF_FE70)

    So you do not need to forward IRQ and FIQ exception vectors to 0x8018 and 0x801C, as you don't need to write a software dispatcher for these if you use #2 or #3.

    Best Regards,

    Christian

  • Christian,

    Thanks for the satisfying explanation, it helps a lot.

    There is no possibility to use #3 for FIQ, is that right?

    Regards,

    Joachim

  • Joachim,

    Yes, this VIC Port is only available for IRQ and not for FIQ.
    The following is from the ARM Cortex-R4 TRM:


    Best Regards,
    Christian