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.

TMS570LS1224: F021 Flash API causes Prefetch Entry when erasing or reprogramming Flash Sector.

Part Number: TMS570LS1224

Hello,

I am trying to implement a bootloader application.

In order to start understanding how bootloading can be done, a use case is devised. After successfully having completed this simple use case, the basic functionality can be augmented and scaled for external memory or for the emulated EEPROM. The possibilities are there.

The use case:

  1. Load the F021 Flash API into RAM to gain erase/reprogram access to Flash Bank 0 (main flash).
  2. Erase a sector in the flash bank 0 in order to verify that the F021 is loaded in RAM.
  3. Use the F021 to reprogram the sector with data from another sector in the same flash bank.

I am using the bootloader example provided from TI.

 

The steps I have taken so far:

  • In the linker file (sys_link.cmd)
      • I have used SPNU515C for the memory layout. The origin of each memory section is aligned with the beginning addresss of a Flash sector, as specified in SPNU515C (page 113), and noted as important by Joe Josn in .
      • The F021 Flash API resides in its own memory section (FLASH_API).
      • The memory section which I want to erase and program is called FLASH_COPY. 
MEMORY
{   
        /* Sector 0 */
    VECTORS     (X)     : o=0x00000000 l=0x00001000
    BOOT_LOAD   (RX)    : o=0x00001000 l=0x00001000 /* Bootloader resides here */
    FLASH_API   (RX)    : o=0x00002000 l=0x00002000 /* F021 API resides here */
        /* Sectors 1..14 */
    FLASH0      (RX)    : o=0x00004000 l=0x0011BFFF 
        /* Sector 15 */ 
    FLASH_COPY  (RX)    : o=0x00120000 l=0x0001FFFF f=0x5A5A5A
    
    STACKS      (RW)    : o=0x08000000 l=0x00010500
    RAM         (RW)    : o=0x08010500 l=0x0001fb00

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

 

      • I include the whole F021 library in the FLASH_API section now, which solves an issue discussed in other threads on the e2e forum( URL:  ). The library fits in the section.
SECTIONS
{
    .intvecs    : {} > VECTORS 
    .text       : {} > FLASH0
    .const      : {} > FLASH0 
    .cinit      : {} > FLASH0
    .pinit      : {} > FLASH0 
    .bss        : {} > RAM
    .data       : {} > RAM
    .sysmem     : {} > RAM


/* USER CODE BEGIN (4) */

    boot_ldr    : {sys_core_afw.obj     (.text)} > BOOT_LOAD
    eabi_start  : {sys_startup_afw.obj  (.text)} > BOOT_LOAD
    
    flash_api   :
    {
        fapi_usr_func.obj   (.text)
        bl_flash.obj        (.text)

        -l F021_API_CortexR4_BE_V3D16.lib (.text)
    } 
    load = FLASH_API,
    run = RAM,
    LOAD_START(api_load),
    RUN_START(api_run),
    LOAD_SIZE(api_size)

/* USER CODE END */

}
  • In the startup sequence (sys_startup.c & sys_core.asm)
      • The CPU is switched back to Supervisor Mode at the end of the _coreInitRegisters_ function.
       ....
        ; Switch to Undefined Instruction Mode (M = 11011)
        cps #27
        mov lr, r0
        mrs r1,cpsr
        msr spsr_cxsf, r1
        ; Switch to System Mode ( Shares User Mode registers ) (M = 11111)
        cps #31
        mov lr, r0
        mrs r1,cpsr
        msr spsr_cxsf, r1
        ; Switch back to Supervisor Mode (M = 10011) - Bootloader
        cps #19
        mov lr, r0
        mrs r1,cpsr
        msr spsr_cxsf, r1

        ; ARM Modes - cortex r4 manual ARM DDI 0363G p.56
      •  
      • Afterwards, I give full read/write data permission using the MPU access control registers, as mentioned in the Cortex-R4F techincal reference manual on page 126 (ARM DDI 0363G, ID041111; p.126/436)
        ; MPU cortex r4 ARM DDI 0363G p.184
        mrc   p15,     #0x00,      r2,       c1, c0, #0x02
        orr   r2,      r2,         #0xF00000
        mcr   p15,     #0x00,      r2,       c1, c0, #0x02
        mov   r2,      #0x40000000
        fmxr  fpexc,   r2

        ; Read/Write full access ARM DDI 0363G p.126
        mrc   p15,     #0x00,      r2,       c6, c1, #0x04
        mov   r2,      #0x03
        mcr   p15,     #0x00,      r2,       c6, c1, #0x04
        mov   r2,      #0x40000000
        fmxr  fpexc,   r2

      • The Flash is initialized in Pipeline mode to enable read/write at 160MHz (SPNU515C; p.288).
/** - Setup flash read mode, address wait states and data wait states */
    flashWREG->FRDCNTL =  0x00000000U
                       | (uint32)((uint32)3U << 8U)
                       | (uint32)((uint32)1U << 4U)
                       |  1U;

      • ECC is enabled in sys_startup.c for RAM ( _coreEnableRamEcc_(); function)
      • The Auto-ECC option is checked in CCS as suggested by Charles Tsai in  .
      • The Watchdog is not enabled.
  • The "Bootloader"
      • To copy the flash API in RAM, I opted for a C function instead of assembly. The CI Pipeline in our company can analyze C code but not Assembly code. The code I found on another E2E Thread, which I have not noted down!
      • I use the linker symbols following SPNU118W, Section 8.6.1 Using Linker Symbols in C/C++ Applications
      • I flush the Pipeline after every function call even though it is not necessary.
      •  

extern uint8_t api_load;
extern uint8_t api_run;
extern uint8_t api_size;

/* Size of F021 API in u32 words */
#define API_U32_WORD_COUNT  (uint32_t)((uint32_t)(&api_size) / sizeof(uint32_t) )

/* The Flash address to write to */
#define ADDR_FLASH_COPY     0x00120000
#define ADDR_FLASH_API      0x00002000

/* Flash - Bank 0, EEPROM - Bank 7 */
#define BANK_0              0U
#define BANK_7              7U

#define BANK_0_SECTOR_15    0x8000U

void fn_copy_api_to_ram(uint8_t *p_load, uint8_t *p_start, uint32_t u32_size)
{

    do
    {
        *p_start = *p_load;
        p_start++;
        p_load++;
    } while (--u32_size);

    return;
}

void fn_updater_util(void)
{
    /* First copy the FLASH API to RAM
    ** in order to write to FLASH Bank 0 */
    fn_copy_api_to_ram( (uint8_t*)&api_load, (uint8_t*)&api_run, (uint32_t)&api_size);

    uint32_t u32_fapi_res = (uint32_t)0U;

    u32_fapi_res = Fapi_initializeFlashBanks(SYS_CLK_FREQ);

    u32_fapi_res = Fapi_setActiveFlashBank(BANK_0);

    u32_fapi_res = Fapi_enableMainBankSectors(BANK_0_SECTOR_15);

    while( FAPI_CHECK_FSM_READY_BUSY != Fapi_Status_FsmReady );
    while( FAPI_GET_FSM_STATUS != Fapi_Status_Success );

    u32_fapi_res =  Fapi_issueAsyncCommandWithAddress(Fapi_EraseSector, (uint32_t*)ADDR_FLASH_COPY);
    Fapi_flushPipeline();

    while( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmBusy );
    while( FAPI_GET_FSM_STATUS != Fapi_Status_Success );

    u32_fapi_res = FAPI_GET_FSM_STATUS;

    u32_fapi_res = Fapi_initializeFlashBanks(SYS_CLK_FREQ);
    u32_fapi_res = Fapi_setActiveFlashBank(BANK_0);
    u32_fapi_res = Fapi_enableMainBankSectors(BANK_0_SECTOR_15);
    while( FAPI_CHECK_FSM_READY_BUSY != Fapi_Status_FsmReady );
    while( FAPI_GET_FSM_STATUS != Fapi_Status_Success );

    uint8_t u8_dummy_buff[4] = { 0xBA, 0xD0, 0xBA, 0xD0 };

    u32_fapi_res = Fapi_issueProgrammingCommand((uint32_t *)ADDR_FLASH_COPY,
                                                &u8_dummy_buff[0],
                                                4,
                                                0U,
                                                0U,
                                                Fapi_AutoEccGeneration);


    while( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmBusy );

    u32_fapi_res = FAPI_GET_FSM_STATUS;


    return;
}

The problem I am facing: 

1. When using the debugger, if I step over the Fapi_issueAsyncCommandWithAddress() function, It works without any problems, and I can see the erased Flash in the Memory browser. If I set a breakpoint after the function and press Resume Execution at program begin, it causes a prefetchEntry.

2. When I step into the assembly code of Fapi_issueProgrammingCommand(), it works without any problems and reprograms the newly erased Flash! When I try to step over the function, it causes a prefetchEntry.

 

I do not know how to proceed further and this is proving to be a blocker. Thank you in advance!

 

Kind Regards,

Mihail

  • To clarify further, the SYS_CLK_FREQ is set to 160

    //*****************************************************************************
    //
    // The frequency (MHz) of the crystal used to clock the microcontroller.
    //
    // This defines the crystal frequency used by the microcontroller running the
    // boot loader.
    //
    // Depends on: None
    // Exclusive of: None
    // Requires: None
    //
    //*****************************************************************************
    #define CRYSTAL_FREQ            16             //MHz
    
    #define SYS_CLK_FREQ            160           //MHz

  • Hello,

    fn_updater_util() should be executed from SRAM too,

  • Hello and thank you for the response. I believe that the function is run from RAM too!

    An excerpt from sys_startup.c:

        /* Configure system response to error conditions signaled to the ESM group1 */
        /* This function can be configured from the ESM tab of HALCoGen */
        esmInit();
        /* initialize copy table */
        __TI_auto_init();
    
    /* USER CODE BEGIN (75) */
    /* USER CODE END */
        
        /* call the application */
    /*SAFETYMCUSW 296 S MR:8.6 <APPROVED> "Startup code(library functions at block scope)" */
    /*SAFETYMCUSW 326 S MR:8.2 <APPROVED> "Startup code(Declaration for main in library)" */
    /*SAFETYMCUSW 60 D MR:8.8 <APPROVED> "Startup code(Declaration for main in library;Only doing an extern for the same)" */
        fn_updater_util();
    
    /* USER CODE BEGIN (76) */
    /* USER CODE END */
    /*SAFETYMCUSW 122 S MR:20.11 <APPROVED> "Startup code(exit and abort need to be present)" */
        exit(0);
    
    /* USER CODE BEGIN (77) */
    /* USER CODE END */
    }

  • Hello,

    Is fn_updater_util() fapi_usr_func()? I don't find fn_updater_util() in your linker command file.

  • Hello once more!

    I have modified the Linker file to include the file in which the fn_updater_util() function resides. It is the bl_main.obj :

     boot_ldr    : {sys_core_afw.obj     (.text)} > BOOT_LOAD
        eabi_start  : {sys_startup_afw.obj  (.text)} > BOOT_LOAD
        
        /* The linker allocates the sections to a single memory range for running,
        ** but different memory ranges for loading.
        */
        flash_api   :
        {
            fapi_usr_func.obj   (.text)
            bl_flash.obj        (.text)
            bl_main.obj         (.text)
    
            -l F021_API_CortexR4_BE_V3D16.lib (.text)
        } 
        load = FLASH_API,     /* Where to load the section */
        run = RAM,            /* Where to run the section */
        LOAD_START(api_load), /* api_load holds the load addr of the flashAPI section */
        RUN_START(api_run),   /* api_run holds the run addr of the flashAPI section */
        LOAD_SIZE(api_size)        /* api_size holds the size of the flashAPI section */
        /* api_load, api_run, api_size can be referenced from the copy table. */

    Now I am calling the function fn_copy_api_to_ram() directly in sys_startup.c, as in the TI Bootloader example. Excerpt from sys_startup.c:

    /* USER CODE BEGIN (74) */
    /* USER CODE END */
    
        /* Configure system response to error conditions signaled to the ESM group1 */
        /* This function can be configured from the ESM tab of HALCoGen */
        esmInit();
        /* initialize copy table */
        __TI_auto_init();
    
    /* USER CODE BEGIN (75) */
    /* USER CODE END */
        
        /* call the application */
    /*SAFETYMCUSW 296 S MR:8.6 <APPROVED> "Startup code(library functions at block scope)" */
    /*SAFETYMCUSW 326 S MR:8.2 <APPROVED> "Startup code(Declaration for main in library)" */
    /*SAFETYMCUSW 60 D MR:8.8 <APPROVED> "Startup code(Declaration for main in library;Only doing an extern for the same)" */
        fn_copy_api_to_ram( (uint8_t*)&api_load, (uint8_t*)&api_run, (uint32_t)&api_size);
    
        fn_updater_util();
    
    /* USER CODE BEGIN (76) */
    /* USER CODE END */
    /*SAFETYMCUSW 122 S MR:20.11 <APPROVED> "Startup code(exit and abort need to be present)" */
        exit(0);
    
    /* USER CODE BEGIN (77) */
    /* USER CODE END */
    }

    Now I am able to step over both functions ( Fapi_issueAsyncCommandWithAddress() and Fapi_issueProgrammingCommand() ) and they do not generate a prefetchEntry.

    If I set a breakpoint at the end of the fn_updater_util() function and press Resume after a System reset, it goes into prefetchEntry!

  • I seem to have stumbled upon the exact problem discussed in this topic:


    Interrupts are not enabled for our Microcontroller, as it is not foreseen to be so by our architecture!

     

    Kind Regards,

    Mihail

  • A very helpful answer that might be pointing in the correct direction is the one by in this thread: .

     

    Could you please explain the reason why in the provided bootloader example, in the sys_intvecs.asm, the Interrupts branch to the application image? Excerpt from sys_intvecs.asm from the TI Bootloader example:

    ;-------------------------------------------------------------------------------
    ; interrupt vectors
    ; Please change the #0x???? for your specified image location defined in bl_config.h
    
            b   _c_int00               ;0x00
            b   #0x1FFF8               ;0x04
            b   #0x1FFF8               ;0x08, Software interrupt
            b   #0x1FFF8               ;0x0C, Abort (prefetch)
            b   #0x1FFF8               ;0x10, Abort (data)
    reservedEntry
            b   reservedEntry          ;0x14
            ldr pc,[pc, #-0x1b0]       ;0x18
            ldr pc,[pc, #-0x1b0]       ;0x1C

    I believe the solution is around the corner, but assistance from the TI team would be greatly appreciated!

     

     

  • I will use this platform to record my findings so that anybody who is facing a similar issue can refer to the steps I have taken to try to resolve this issue.

    After looking at the forum thread posted which I referenced in the comment above (), I set a breakpoint at the prefetchEntry in the interrupt vectors table (sys_intvecs.asm) and Resumed the application so that it causes the abort.

    The breakpoint was reached and I could observe the Registers of the MCU using the Register view in CCS. Of interest are the CP15_INSTRUCTION_FAULT_STATUS in this case. The comment by pointed this out (link: Jun 1, 2015 10:41 PM)

    Using the CortexR4F Technical Reference Manual (ARM DDI 0363G ID041111) on Page 4-47, in Table 4-27, the value of bits [10, 3-0] of the CP15_INSTRUCTION_FAULT_STATUS suggest a "Synchronous Parity/ECC Error"

    Disabling the RAM ECC using _coreDisableRamEcc_(); and disabling Parity using disableParity(); also did not solve the issue.

    Setting the interrupt vectors to be identical to the ones in the bootloader example is not optimal, since the function that checks the TCRAMM ECC generates a data abort (DABT), which causes a jump into the interrupt vectors.


     

  • I cloned the Hercules examples git repository () locally and checked out the branch named "qjwang_hercules_examples" (commit hash: 2ec9e6f9f8a09932f1d6455ab3c101c6efa27711).

    In this repository, I found the sys_link.cmd linker file which is very different than the provided Bootloader examples on the TI webpage. I modified my linker file accordingly. ECC generation is invoked now for every flash area from the Linker file.

    In the readme.txt from the bootloader examples I found the following (under the "New features" topic): "Generates flash ECC using Linker CMD file to avoid speculative fetch ECC error."

    This is further discussed in the "Linker CMD file to generate Flash ECC" topic of the readme.txt. I followed all the steps pointed out:

    (excerpt from readme.txt)
    Do following changes under Flash Settings. CCS Project properties --> Debug -->Flash Settings:
    1. Check "System Reset on Connect"
    2. Uncheck "Auto ECC Generation"
    3. Check "Align program segments to 64-bit memory regions"
    4. Select "None" for "Flash Verification Settings"
    5. Uncheck "Perform Blank Check before Program Load"
    6. Press "APPLY" to save your changes!

     

    With all of this done too, I am still getting the prefetchEntry abort!

  • I am really struggling with this, so any help would be appreciated!

  • Mihail

    Did you resolve this issue ?

    I am experiencing a smiliar issue.

    Rob

  • Hi Mihail,

    Can you please post your project, so I can check on my board?

  • Hello Rob, I have not been able to resolve the issue yet!
  • Hello,

    Have you solved this issue?

  • QJ,

    I haven’t resolved all of my Flash issues, although I have now sorted this specific issue.

    A trap for new users is the speculative branching. 

    I had a section of Test Code in one of the sectors that I was erasing and was relying on that during firmware updates I would not be accessing the test code. 

    As it turns out this is not the case and the CPU must have been accessing the erased section for speculative branching from time to time, giving me inconsistent results. 

    I have now moved the test code out of this area for now which creates another issue with running out of code space.

    So I think I am now on top of that issue.

    I now have one more problem to resolve but I think it would be best to start a new thread as it is related to writing to FLASH fail. I am in the middle of another debug session and will create a new thread if I can’t resolve before too long.

    Thank you for your help.

    Regards

    Robert

  • Hello!

    Sorry for my delayed reply, I was out of office and with limited access to source code!

    Here is the source code. It is a minimum working example exhibiting the issues I am still facing!

     

    Thank you in advance!

     

    5127.tms570ls_bootloader.zip

     

     

  • Hello!

    Could you please post a reference link to your new thread please!

    Kind regards

  • Hello Mihail,

    Fapi_flushPipeline() is used to flushes the FMC pipeline buffers. Please call this function after the status checking. But you call it before the status checking.

    void fn_updater_util(void)
    {
    uint32_t u32_fapi_res = (uint32_t)0U;

    u32_fapi_res = Fapi_initializeFlashBanks(SYS_CLK_FREQ);
    Fapi_flushPipeline();

    if( (Fapi_initializeFlashBanks((uint32_t)SYS_CLK_FREQ)) == Fapi_Status_Success)
    {
    (void)Fapi_setActiveFlashBank((Fapi_FlashBankType)BANK_0);
    (void)Fapi_enableMainBankSectors(0xFFFF);
    }
    else
    {
    return ;
    }

    while( FAPI_CHECK_FSM_READY_BUSY != Fapi_Status_FsmReady );
    while( FAPI_GET_FSM_STATUS != Fapi_Status_Success );

    u32_fapi_res = Fapi_issueAsyncCommandWithAddress(Fapi_EraseSector, (uint32_t*)ADDR_FLASH_COPY);
    // Fapi_flushPipeline();

    while( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmBusy );
    while( FAPI_GET_FSM_STATUS != Fapi_Status_Success );

    Fapi_flushPipeline();

    u32_fapi_res = FAPI_GET_FSM_STATUS;

    while( FAPI_CHECK_FSM_READY_BUSY != Fapi_Status_FsmReady );
    while( FAPI_GET_FSM_STATUS != Fapi_Status_Success );

    uint8_t u8_dummy_buff[4] = { 0xBA, 0xD0, 0xBA, 0xD0 };

    u32_fapi_res = Fapi_issueProgrammingCommand((uint32_t *)ADDR_FLASH_COPY,
    &u8_dummy_buff[0],
    4,
    0U,
    0U,
    Fapi_AutoEccGeneration);

    //Fapi_flushPipeline();

    while( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmBusy );

    Fapi_flushPipeline();

    u32_fapi_res = FAPI_GET_FSM_STATUS;

    return;
    }

  • another suggestion,

    Please use vfill instead of fill in linker cmd file.

    refer to http://www.ti.com/lit/ug/spnu118y/spnu118y.pdf

  • Thank you very much,

    This resolved the issue completely!

    The application software does not jump into the interrupt vectors anymore!

    Kind regards,

    Mihail