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.

AM5718: Bootloader issue with M4 core

Part Number: AM5718

I'm having troubles with starting multicore application from MicroSD card on AM571x IDK board.
I have one TI-RTOS application for A15 core, one bare-metal application for DSP core and one bare-metal application for one IPU (Cortex-M4) core (one of two).
I can run this multicore application suite through internal JTAG of IDK board. Every part of it (for each core) executes it's code correctly.
All applications use separated part of OCMC1 RAM section.
No collisions or inadequate behaviour are detected while debuggind device throug JTAG.
I also can make an 'app' file for loading from SD card using precompiled bootloader 'MLO' from Processor SDK RTOS 06.01.00.08. In this case, when booting from SD card, A15 and DSP cores run card correctly.
The problem is with IPU unit (Cortex-M4).
First of all, bootloader prints an error message 'IPU1 - Invalid Memory section'.
After recompiling IPU application with MMU turned off, this message dissapeared, but IPU core still does not show any signs of life.

I have built custom bootloader using original source code, but continue to get the same result.
I tried to modify mechanics of IPU clock management, reset and memory mapping. According to Technical Reference manual all Register data is correct, I can see through JTAG that register fields for indicating IPU module status change their values to expected ones. But my application for IPU core does not start any way.

If I can run IPU application with JTAG, does not it mean that is should also be suitable for bootloader?
Is bootloader code (IPU engage part) correct?
Can you please share an example (source and binaries) of multicore application with SD card bootloader that uses A15 core and one Cortex-M4 core in am571x chip?

Regards.

  • Hi Anton,

    >> I can run this multicore application suite through internal JTAG of IDK board. Every part of it (for each core) executes it's code correctly.

    Did you use the GEL file to set up the IPU (PLL, MMU etc.)? If yes, can you remove the GEL file from the CCXML and try it again. If the IPU cannot run  after removing the GEL file, then your issue is the IPU settings in your IPU program. The SBL will not set up IPU for you (the GEL file will do). You have to set up IPU in your application program.

    Ming

  • Hello, Ming.

    Obviously without GEL files JTAG does not run. I've already figured out that reset and MMU configuration is performed in IPUSSClkEnable() function in AM571x_multicore_reset.gel file and it's called every time from OnTargetConnect() -> AM571x_MULTICORE_EnableAllCores() -> IPU1SSClkEnable_API() -> IPUSSClkEnable(1).

    But the problem is not with that.

    I must say, that according to the source codes from last PDK version SBL actually does have a setup sequence for IPU cores.
    pdk_am57xx_1_0_16/packages/ti/boot/sbl/board/idkAM571x/sbl_main.c:101: SBL_SlaveCorePrcmEnable() -> pdk_am57xx_1_0_16/packages/ti/boot/sbl/soc/am57xx/sbl_slave_core_boot.c:200: IPU1_ClkEnable(), IPU1_SystemReset() and so on including IPU1_AMMU_Config() which setups IPU's MMU exactly like GEL files do.

    I only can't understand the meaning of pdk_am57xx_1_0_16/packages/ti/boot/sbl/soc/am57xx/sbl_slave_core_boot.c:553: HW_WR_REG32((MPU_IPU1_RAM + 0x4), EntryPoint) call.

    Why the entry adress value is written down to 0x4 offset in internal memory?

    After detailed study of IPU boot process I can see that it should work somehow, but it does not. I feel that problem is in the very beggining, because I tried to build tiny program and place it completely inside the internal IPU memory to exclude possible OCMC_RAM1 address problems, but still it does not run.

    Is IPU boot part of SBL source code incorrect?

    Can you please share an example of proper IPU intialization from scratch?

    Regards, Anton.

  • Hi Anton,

    The IPU cores, being standard Cortex-M4s, will boot from a vector table located at 0x0000_0000. This is in the usual Cortex-M format. The MPU_IPU1_RAM + 0x4 is the reset handler. In fact, after setting the reset handler to entry point. The program will bring the IPU out of the reset.

    Ming

    uint32_t vector_table[] = {
        // Stack Pointer
        (unsigned long) &_stack_top,
        // Reset handler
        (unsigned long) rst_handler,
        // Standard Cortex-M4 exception handlers
        (unsigned long) empty_def_handler,      // NMI handler.                     2
        (unsigned long) empty_def_handler,      // hard fault handler.              3
        (unsigned long) empty_def_handler,      // Memory Management Fault          4
        (unsigned long) empty_def_handler,      // Bus Fault                        5
        (unsigned long) empty_def_handler,      // Usage Fault                      6
        (unsigned long) empty_def_handler,      // Reserved                         7
        (unsigned long) empty_def_handler,      // Reserved                         8
        (unsigned long) empty_def_handler,      // Reserved                         9
        (unsigned long) empty_def_handler,      // Reserved                         10
        (unsigned long) empty_def_handler,      // SV call                          11
        (unsigned long) empty_def_handler,      // Debug monitor                    12
        (unsigned long) empty_def_handler,      // Reserved                         13
        (unsigned long) empty_def_handler,      // PendSV                           14
        (unsigned long) empty_def_handler,      // SysTick                          15
        // Now 64 CPU specific interrupt handlers
        (unsigned long) empty_def_handler,      // ISR 0x00
        ...
    }



  • Hi Anton,

    >> Can you please share an example of proper IPU intialization from scratch?

    in pdk_am57xx_1_0_16/packages folder

    make -C ti/boot/sbl example_clean BOARD=idkAM571x SOC=AM571x

    make -C ti/boot/sbl example BOARD=idkAM571x SOC=AM571x

    will build the SBL example for A15, DSP and IPU images for you.

    They will be in pdk_am57xx_1_0_16\packages\ti\boot\sbl\binary\idkAM571x\example.

    Ming

  • Hi Anton,

    To make the "app" for multicore for idkAM571, you will need to do the following after the sbl example build:

    cd .\ti\boot\sbl
    export BIN_PATH=./binary
    export APP_MPU_CPU0=./binary/idkAM571x/example/a15/mpuc0/bin/sbl_app.out
    export APP_MPU_CPU1=""
    export APP_DSP1=./binary/idkAM571x/example/c66/dsp1/bin/sbl_app.xe66
    export APP_DSP2=""
    export APP_IPU1_CPU0=./binary/idkAM571x/example/m4/ipu1/bin/sbl_app.xem4
    export APP_IPU1_CPU1=""
    .\tools\scripts\AM57xImageGen.bat

    The generated "app" will be at .\binary\app

    Copy the MLO and the app to a FAT32 formatted SD card, you will be ready to boot for idkAM571x.

    See 4.6.3.2.6.3. Windows Environment of Processor SDK RTOS Software Developer's Guide for details.

    Ming  

  • Hello, Ming.

    Eventually I made IPU1-0 core run as conceived. The problem was in AMMU configuration. Somehow default AMMU register values in sbl sources cause conflict with GMPC controller, which I configure in my custom bootloader from A15 core a bit earlier than it starts IPU. I rewrote IPU1_AMMU_Config() function using macroses from cslr_unicache_mmu.h file and now firmware for IPU1-0 is loaded and running from OCMC-RAM1.

    I leave source here in case it comes in handy.

    void IPU1_AMMU_Config(void)
    {
        CSL_UnicacheMmuRegs *ammuReg = (CSL_UnicacheMmuRegs *)CSL_IPU_UNICACHE_MMU_REGS;
    
        // Large Page Translations
        // Logical Address
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_LARGE_ADDR(0), 0x40000000);
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_LARGE_ADDR(1), 0x80000000);
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_LARGE_ADDR(2), 0xA0000000);
    
        // Physical Address
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_LARGE_XLTE(0), 0x40000000);  // All peripherals
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_LARGE_XLTE(1), 0x80000000);  // DDR0
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_LARGE_XLTE(2), 0xA0000000);  // DDR0
    
        // Policy Register
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_LARGE_POLICY(0),
                    CSL_FMKT(UNICACHEMMU_LARGE_POLICY_ENABLE, ENABLE) |
                    CSL_FMKT(UNICACHEMMU_LARGE_POLICY_SIZE, 512MB) |
                    CSL_FMKT(UNICACHEMMU_LARGE_POLICY_L1_CACHEABLE, DISABLE) |
                    CSL_FMKT(UNICACHEMMU_LARGE_POLICY_L1_POSTED, NON_POSTED) |
                    CSL_FMKT(UNICACHEMMU_LARGE_POLICY_L1_WR_POLICY, WT));
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_LARGE_POLICY(1),
                    CSL_FMKT(UNICACHEMMU_LARGE_POLICY_ENABLE, ENABLE) |
                    CSL_FMKT(UNICACHEMMU_LARGE_POLICY_SIZE, 512MB) |
                    CSL_FMKT(UNICACHEMMU_LARGE_POLICY_L1_CACHEABLE, ENABLE) |
                    CSL_FMKT(UNICACHEMMU_LARGE_POLICY_L1_POSTED, POSTED) |
                    CSL_FMKT(UNICACHEMMU_LARGE_POLICY_L1_WR_POLICY, WB));
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_LARGE_POLICY(2),
                    CSL_FMKT(UNICACHEMMU_LARGE_POLICY_ENABLE, ENABLE) |
                    CSL_FMKT(UNICACHEMMU_LARGE_POLICY_SIZE, 512MB) |
                    CSL_FMKT(UNICACHEMMU_LARGE_POLICY_L1_CACHEABLE, ENABLE) |
                    CSL_FMKT(UNICACHEMMU_LARGE_POLICY_L1_POSTED, POSTED) |
                    CSL_FMKT(UNICACHEMMU_LARGE_POLICY_L1_WR_POLICY, WB));
    
        // Medium Page
        // Logical Address
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_MED_ADDR(0), 0x00300000);
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_MED_ADDR(1), 0x00340000);
    
        // Physical Address
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_MED_XLTE(0), 0x40300000);  // OCMC SRAM1
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_MED_XLTE(1), 0x40340000);  // OCMC SRAM1
    
        // Policy Register
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_MED_POLICY(0),
                    CSL_FMKT(UNICACHEMMU_MED_POLICY_ENABLE, ENABLE) |
                    CSL_FMKT(UNICACHEMMU_MED_POLICY_SIZE, 256KB) |
                    CSL_FMKT(UNICACHEMMU_MED_POLICY_L1_CACHEABLE, ENABLE) |
                    CSL_FMKT(UNICACHEMMU_MED_POLICY_L1_POSTED, POSTED) |
                    CSL_FMKT(UNICACHEMMU_MED_POLICY_L1_WR_POLICY, WB));
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_MED_POLICY(1),
                    CSL_FMKT(UNICACHEMMU_MED_POLICY_ENABLE, ENABLE) |
                    CSL_FMKT(UNICACHEMMU_MED_POLICY_SIZE, 256KB) |
                    CSL_FMKT(UNICACHEMMU_MED_POLICY_L1_CACHEABLE, ENABLE) |
                    CSL_FMKT(UNICACHEMMU_MED_POLICY_L1_POSTED, POSTED) |
                    CSL_FMKT(UNICACHEMMU_MED_POLICY_L1_WR_POLICY, WB));
    
        // Small Page
        // Enable cache for first 16kB of SRAM
        CSL_FINST(ammuReg->SMALL_POLICY0, UNICACHEMMU_SMALL_POLICY0_L1_CACHEABLE, ENABLE);
        // Expand region to 16kB for L2MMU/WUGEN access
        CSL_FINST(ammuReg->SMALL_POLICY1, UNICACHEMMU_SMALL_POLICY1_SIZE, MAX);
    
        // Logical Address
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_SMALL_ADDR(0), 0x00004000);
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_SMALL_ADDR(1), 0x00008000);
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_SMALL_ADDR(2), 0x0000C000);
    
        // Physical Address
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_SMALL_XLTE(0), 0x55024000);  // SRAM
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_SMALL_XLTE(1), 0x55028000);  // SRAM
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_SMALL_XLTE(2), 0x5502C000);  // SRAM
    
        // Policy Register
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_SMALL_POLICY(0),
                    CSL_FMKT(UNICACHEMMU_SMALL_POLICY_ENABLE, ENABLE) |
                    CSL_FMKT(UNICACHEMMU_SMALL_POLICY_SIZE, 16KB) |
                    CSL_FMKT(UNICACHEMMU_SMALL_POLICY_L1_CACHEABLE, ENABLE) |
                    CSL_FMKT(UNICACHEMMU_SMALL_POLICY_L1_POSTED, NON_POSTED) |
                    CSL_FMKT(UNICACHEMMU_SMALL_POLICY_L1_WR_POLICY, WT));
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_SMALL_POLICY(1),
                    CSL_FMKT(UNICACHEMMU_SMALL_POLICY_ENABLE, ENABLE) |
                    CSL_FMKT(UNICACHEMMU_SMALL_POLICY_SIZE, 16KB) |
                    CSL_FMKT(UNICACHEMMU_SMALL_POLICY_L1_CACHEABLE, ENABLE) |
                    CSL_FMKT(UNICACHEMMU_SMALL_POLICY_L1_POSTED, NON_POSTED) |
                    CSL_FMKT(UNICACHEMMU_SMALL_POLICY_L1_WR_POLICY, WT));
        HW_WR_REG32(CSL_IPU_UNICACHE_MMU_REGS + CSL_UNICACHEMMU_SMALL_POLICY(2),
                    CSL_FMKT(UNICACHEMMU_SMALL_POLICY_ENABLE, ENABLE) |
                    CSL_FMKT(UNICACHEMMU_SMALL_POLICY_SIZE, 16KB) |
                    CSL_FMKT(UNICACHEMMU_SMALL_POLICY_L1_CACHEABLE, ENABLE) |
                    CSL_FMKT(UNICACHEMMU_SMALL_POLICY_L1_POSTED, NON_POSTED) |
                    CSL_FMKT(UNICACHEMMU_SMALL_POLICY_L1_WR_POLICY, WT));
    }

    And linker file part for M4 core.

    #ifdef MMU  /* Memory map with MMU turned on */
    
    MEMORY
    {
        IRAM:      o = 0x00000000 l = 0x00010000   /* 64kB internal SRAM */
        //OCMC_RAM1: o = 0x00300000 l = 0x00080000   /* 512kB L3 OCMC SRAM1 Total */
        //OCMC_RAM1: o = 0x00300000 l = 0x00010000   /* 64kB L3 OCMC SRAM1 Used by firmware */
        OCMC_RAM1: o = 0x00310000 l = 0x00020000   /* 128kB L3 OCMC SRAM1 Used by firmware_ipu1_0 */
        //OCMC_RAM1: o = 0x00330000 l = 0x00050000   /* 320kB L3 OCMC SRAM1 Used by bootloader */
        DDR0:      o = 0x80000000 l = 0x40000000   /* 1GB external DDR Bank 0 */
    }
    
    #else  /* Memory map with MMU turned off */
    
    MEMORY
    {
        IRAM:      o = 0x00000000 l = 0x00010000   /* 64kB internal SRAM */
        //OCMC_RAM1: o = 0x40300000 l = 0x00080000   /* 512kB L3 OCMC SRAM1 Total */
        //OCMC_RAM1: o = 0x40300000 l = 0x00010000   /* 64kB L3 OCMC SRAM1 Used by firmware */
        OCMC_RAM1: o = 0x40310000 l = 0x00020000   /* 128kB L3 OCMC SRAM1 Used by firmware_ipu1_0 */
        //OCMC_RAM1: o = 0x40330000 l = 0x00050000   /* 320kB L3 OCMC SRAM1 Used by bootloader */
        DDR0:      o = 0x80000000 l = 0x40000000   /* 1GB external DDR Bank 0 */
    }
    
    #endif
    
    SECTIONS
    {
        .intvecs:    > 0x00000000
        .intc_text:  > IRAM
        .text:       > OCMC_RAM1
        .const:      > OCMC_RAM1
        .cinit:      > OCMC_RAM1
        .init_array: > IRAM
        .data:       > OCMC_RAM1
        .bss:        > OCMC_RAM1
        .stack:      > OCMC_RAM1
        .sysmem:     > OCMC_RAM1
        .TI.noinit:  > OCMC_RAM1
    }

    I also had to add possibility lo load IPU firmware parts from SD card to sections with addresses >= 0x300000 for MMU usage option.

    Anyway one problem still has left.

    During my experiments I didn't find a way to run IPU1-0 code from DDR0 memory address starting from 0xA0000000 and higher. Any lower address of DDR0 is just fine. I assume there is some deeper problem, but as long as I was initially going to use OCMC-RAM1 for IPU1-0 code, it's not a critical issue.

    But yet it would be nice to figure it out.

    Regards, Anton.