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.

RM48L950: Changing sys_intvecs.asm for Ethernet bootloader

Part Number: RM48L950
Other Parts Discussed in Thread: HALCOGEN

Hello,

I've developed a functioning Ethernet bootloader, and have had some success loading small, basic applications into memory. 

My next goal is to load an application that uses interrupts (specifically a simple UDP app using lwip to blink an LED, which has been tested an runs successfully as a standalone application w/o a bootloader).

After reading through some forums and this CAN bootloader manual I've noticed that if I plan on using interrupts in my application that will be loaded into memory by the bootloader, then I have to change the exception vector table.

My bootloader is run out of Bank1 at 0x180000, with the vector table being at it's default 0x0 position 

My UDP application starts at 0x160000 in Bank0, so the bootloader's sys_intvecs.asm is as follows: 

    .sect ".intvecs"
    .arm

;-------------------------------------------------------------------------------
; import reference for interrupt routines

    .ref _c_int00
    .ref _dabort
    ;.ref phantomInterrupt
    .def resetEntry

;-------------------------------------------------------------------------------
; interrupt vectors

resetEntry
        b   _c_int00  ; 0x00  Bootloader
        b   #0x15FFF8 ; 0x04
        b   #0x15FFF8 ; 0x08, SW interrupt
        b   #0x15FFF8 ; 0x0C, Abort (prefetch)
        b   #0x15FFF8 ; 0x10, Abort (data)

reservedEntry
        b   reservedEntry
        ldr pc,[pc,#-0x1b0]
        ldr pc,[pc,#-0x1b0]

I believe the addresses are setup correctly, as the PC points two address ahead, so APP_START_ADDR - 0x8 = 0x15FFF8

After doing so, my bootloader does not work, and seems to receive a ESM error upon start up. 

HOWEVER, when I leave the exception vector table in it's default state, the bootloader does boot up successfully, and I can load and run the UDP app over Ethernet successfully.  This result is what is strange to me: I receive network packets in my newly loaded app, even though I didn't change the exception vector table in the bootloader, and I disable interrupts before I run my UDP app (which tells me the UDP app is successfully enabling interrupts).

Here is the bootloader sys_intvecs.asm file that allows me to run everything successfully: 

    .sect ".intvecs"
    .arm

;-------------------------------------------------------------------------------
; import reference for interrupt routines

    .ref _c_int00
    .ref _dabort
    ;.ref phantomInterrupt
    .def resetEntry

;-------------------------------------------------------------------------------
; interrupt vectors

resetEntry
        b   _c_int00
undefEntry
        b   undefEntry
svcEntry
        b   svcEntry
prefetchEntry
        b   prefetchEntry
        b   _dabort
reservedEntry
        b   reservedEntry
        ldr pc,[pc,#-0x1b0]
        ldr pc,[pc,#-0x1b0]

My questions:

1. Am I doing something incorrectly with respect to the exception vector table for the bootloader?   

2. More importantly: Why does my loaded UDP app work when the bootloader's 'sys_intvecs.asm' file is left alone?  If both apps are using the same interrupts for EMAC, is that why I'm able to receive packets in my UDP even though I didn't setup the sys_intvecs.asm file to jump to my new address? 

Any advice or tips are appreciated!

Also, let me know if you need more info

Thank you,

-Nate J

  • Hello Nathan,

    1. Does your bootloader use SW interrupt? If any interrupt occurs in bootloader, it will jump the address defined in the exception vector table (0x15FFF8), and you will get ESM error before the UDP application is loaded to 0x160000. Which bit of ESM status registers is set?

    2. After the IRQ or FIQ is received by the CPU, the CPU branches to 0x18 (IRQ) or 0x1C (FIQ). The pending ISR address is written into the corresponding vector register (IRQVECREG for IRQ, FIQVECREG for FIQ). The instruction LDR PC, [PC,#-0x1B0] reads the content of the register and branches to the ISR. If the interrupt occurs in bootloader, the ISR address is defined in bootloader's VIM table. If the interrupt occurs in your application, the CPU uses the ISR address defined in your application VIM table.

  • Thank you for your response QJ, 

    1. The bootloader only uses IRQ for EMAC handling. But would calling '_enable_IRQ()' be considered a SW interrupt? I was getting ESM group 3 errors on startup. Code would loop forever at this point:

        if ((esmREG->SR1[2]) != 0U)
        {
    /* USER CODE BEGIN (24) */
    /* USER CODE END */
        /*SAFETYMCUSW 5 C MR:NA <APPROVED> "for(;;) can be removed by adding "# if 0" and "# endif" in the user codes above and below" */
        /*SAFETYMCUSW 26 S MR:NA <APPROVED> "for(;;) can be removed by adding "# if 0" and "# endif" in the user codes above and below" */
        /*SAFETYMCUSW 28 D MR:NA <APPROVED> "for(;;) can be removed by adding "# if 0" and "# endif" in the user codes above and below" */
            for(;;)
            { 
            }/* Wait */                 
    /* USER CODE BEGIN (25) */
    /* USER CODE END */
        }

    2. So, if I'm understanding this correctly, I don't have to change the exception vector table if I'm only using IRQ/FIQs in either my bootloader / application?

  • 1. Which bit of ESM status registers is set?

    2. You need to handle the exceptions generated by the code in Bootloader AND the code in your application.

    you can define a function in bootloader to dispatch the exceptions. for example

    Bootloader exception table:

    resetEntry
            b   _c_int00
              ...
            b   dabort_handler
    dabort_handler()
    {
        if the exception is caused by bootloader
             then call _dabort()
       else
             branch to application: 0x160000+0x10
    }
  • hello QJ Wang,

    I am also currently experiencing problems in my application where I cannot properly enter the exception interrupt handler.It's useful to see your answer, but how do you tell if an exception is coming from a bootloader or an application?

  • One method is to write a flag to EEPROM.

    You can define one block (for example block x) to store this flag. Both bootloader and Application write their flag to the same block.The dabort_handler() reads the flag from the EEPROM.  

    For example:

    In bootloader:

    1. TI_Fee_WriteAsync(block x, &BL_Flag[0]);

    in Bootloader's dabort_handler():

    2. TI_Fee_Read(block x, 0, Read_Ptr, Length);

    In application:

    3. TI_Fee_WriteAsync(block x, &APP_Flag[0]);

    Please take a look at the EEPROM example code in HALCoGen.

  • 1. Bit position 3 of ESM Status Register 3; that register is showing 0x00000008

    2. This is good information, but I'm still confused as to why my bootloader doesn't work when I enter those custom address. If I was running into a data abort exception, wouldn't it crash regardless of what address I jump to once that exception is hit?

    In other words, even if I put in that handler that you posted into my code, there would still be some underlying problem causing a data abort, correct?    

    Thanks,

    -Nate J

  • Hi,

    I checked my example code of ethernet bootloader. The branch addresses (UNDEF, DABT, PABT) in sys_intvec.asm are the locations in the application:

  • Yes, I understand that portion, but why would putting the addresses of my application into the bootloaders' sys_intvecs.asm cause the bootloader to crash? 

    If it is because of a data abort, then why is there a data abort when I change my code to what you have above (with the correct addresses for my application)? 

    Yet, it works perfectly fine if I don't touch the sys_intvecs.asm 

    Thanks,

    -Nate J

  • Hi Nate,

    I tried couple time with different branch addresses in sys_intvecs.asm, there is no problem. Can you please step through your code to check which instruction in startup.c causes the issue?

  • Hi Nate,

    When your bootloader checks if any valid application has been programmed by reading the flag words, it will generate ECC error if the application and flag have not been programmed. To avoid this issue, please program the ECC for the whole flash using linker cmd file.

    Please learn how to generate ECC using Linker CMD file:

  • This is an example:

    /* */
    /*----------------------------------------------------------------------------*/
    /* USER CODE BEGIN (0) */
    /* USER CODE END */


    /*----------------------------------------------------------------------------*/
    /* Linker Settings */

    --retain="*(.intvecs)"

    /* USER CODE BEGIN (1) */
    /* USER CODE END */

    /*----------------------------------------------------------------------------*/
    /* Memory Map */

    MEMORY
    {
    VECTORS (X) : origin=0x00000000 length=0x00000020 vfill = 0xffffffff
    FLASH0 (RX) : origin=0x00000020 length=0x0017FFE0 vfill = 0xffffffff
    FLASH1 (RX) : origin=0x00180000 length=0x00180000 vfill = 0xffffffff
    SRAM (RW) : origin=0x08002000 length=0x0002D000
    STACK (RW) : origin=0x08000000 length=0x00002000

    /* USER CODE BEGIN (2) */
    #if 1
    ECC_VEC (R) : origin=(0xf0400000 + (start(VECTORS) >> 3))
    length=(size(VECTORS) >> 3)
    ECC={algorithm=algoL2R5F021, input_range=VECTORS}

    ECC_FLA0 (R) : origin=(0xf0400000 + (start(FLASH0) >> 3))
    length=(size(FLASH0) >> 3)
    ECC={algorithm=algoL2R5F021, input_range=FLASH0 }

    ECC_FLA1 (R) : origin=(0xf0400000 + (start(FLASH1) >> 3))
    length=(size(FLASH1) >> 3)
    ECC={algorithm=algoL2R5F021, input_range=FLASH1 }
    #endif
    /* USER CODE END */

    }

    /* USER CODE BEGIN (3) */
    ECC
    {
    algoL2R5F021 : address_mask = 0xfffffff8 /* Address Bits 31:3 */
    hamming_mask = R4 /* Use R4/R5 build in Mask */
    parity_mask = 0x0c /* Set which ECC bits are Even and Odd parity */
    mirroring = F021 /* RM57Lx and TMS570LCx are build in F021 */
    }
    /* USER CODE END */


    /*----------------------------------------------------------------------------*/
    /* Section Configuration */

    SECTIONS
    {
    .intvecs : {} > VECTORS

    flashAPI:
    {
    .\source\Fapi_UserDefinedFunctions.obj (.text)
    .\source\bl_flash.obj (.text)
    --library= "c:\ti\Hercules\F021 Flash API\02.01.01\F021_API_CortexR4_LE.lib" (.text)
    } palign=8 load = FLASH0, run = SRAM, LOAD_START(apiLoadStart), RUN_START(apiRunStart), SIZE(apiLoadSize)

    .text : {} > FLASH0 /*Initialized executable code and constants*/
    .const : {} palign=8 load=FLASH0, run = SRAM, LOAD_START(constLoadStart), RUN_START(constRunStart), SIZE(constLoadSize)

    .cinit : {} > FLASH0 /*Initialized global and static variables*/
    .pinit : {} > FLASH0
    .data : {} > SRAM
    .bss : {} > SRAM /*Uninitialized Global and static variables */
    .sysmem : {} > SRAM

    /* USER CODE BEGIN (4) */
    /* USER CODE END */
    }

    /* USER CODE BEGIN (5) */
    /* USER CODE END */

  • Thank you QJ, I will definitely be giving this a shot

    Updates to follow!

    -Nate J