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.

MSP432E411Y: Failed BSL Scripter Update over Ethernet Causes Bricked MSP432 Application

Part Number: MSP432E411Y
Other Parts Discussed in Thread: UNIFLASH

Hi TI Experts,

I am using the MSP432E411Y MCU for an Ethernet-based application running on TI-RTOS. There is no physical access to the board except the power and ethernet connection, so the flash ethernet bootloader provided by TI will be used to update the software on the MSP432E411Y.

From the example provided for the MSP432E401Y Launchpad, my understanding is that the Ethernet bootloader in ROM is active when the main flash of the MSP432 is erased. We can use this to load the flash bootloader onto the MSP432 using BOOTP requests. When the device is reset, the flash bootloader sends BOOTP requests, which we can use to load the example application code.

The only difference between the example above and my project, is that my application is a ti-rtos project. It has the same magic packet listener routine and SoftwareUpdateBegin() function that the example uses, and it works to update the Application code over ethernet.

My understanding is that the application code, coupled with the ti-rtos build project it uses, changes the reset vectors of the device to make it start at the application code (0x4000?) after a reset. This application code is able to detect a "magic packet" sent by the TI BSL_Scripter application over ethernet and jump to executing the function stored in the SVCall register of the MSP432 (the bootloader has an assembly file in its project that sets a function called UpdateHandler to the SVCall register, if I am not mistaken). The function in the SVCall register sits in the bootloader and starts sending BOOTP requests for a software update. Once the software is received, it triggers a device resets which causes the MSP432 to start back at the new application code.

Please correct me if I am wrong about any of the steps in this process ^, I am trying to have a better understanding of what system registers change and how the 3 projects (bootloader, application, and ti-rtos build) link to each other.

The main issue I am having is that BSL_Scripter sometimes (about 10% of the time) fails with "[ACK_ERROR_MESSAGE] Unknown Error!", which corrupts my application software. If the board is reset, it tries to run the corrupt application again, which essentially results in a bricked MSP432, which can only be recovered with JTAG (not possible when you only have ethernet access to it).

Can you please help me figure out the following:

  • Where does the reset vector sit in memory and how is it changed when we upload the application code?
  • Is there a way to configure the reset vector in software, so we can modify it start running the application/bootloader as necessary?
  • Do you have a solution for the MSP432 device being bricked when a BSL_Scripter ethernet software update fails?

Thanks.

  • Hi,

    • Where does the reset vector sit in memory and how is it changed when we upload the application code?
    • Is there a way to configure the reset vector in software, so we can modify it start running the application/bootloader as necessary?
    • Do you have a solution for the MSP432 device being bricked when a BSL_Scripter ethernet software update fails?

      Did you set the reset vector address to 0x4000 for TI-RTOS? If you application is going to start 0x4000, you would do as follows in the .cfg file. 

    m3Hwi.resetVectorAddress = 0x4000;

      Please refer to this post where Chester attached an TI-RTOS based application example called TM4C1294XL_TI_tcpEcho_non_zero_reset_vector.zip.

    https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1024278/tm4c1294ncpdt-rtos-bios-not-working/3786291?tisearch=e2e-sitesearch&keymatch=vtable%20relocate#3786291

  • Hi Charles,

    Thanks for your response and for pointing me to the example in the post.

    The release.cfg file in my TI-RTOS build (tirtos_builds_MSP432E411Y_BGAEVM_release_ccs) used by the application has the line: m3Hwi.resetVectorAddress = 0x4000; This generates a linker.cmd file under Debug/configPkg/ with the following code at the end:

    /*
     * symbolic aliases for static instance objects
     */
    xdc_runtime_Startup__EXECFXN__C = 1;
    xdc_runtime_Startup__RESETFXN__C = 1;
    xdc_rov_runtime_Mon__checksum = 1;
    xdc_rov_runtime_Mon__write = 1;
    
    
    SECTIONS
    {
        .bootVecs:  type = DSECT
        .resetVecs: load > 0x4000
        .vecs: load > 0x20000000, type = NOLOAD
    
    
    
        xdc.meta: type = COPY
        xdc.noload: type = COPY
    }
    Does adding the m3Hwi.resetVectorAddress = 0x4000 line above change the reset vector, and make the MSP432 boot to the application at address 0x4000 at startup? Or will it still boot into the bootloader at flash address 0x0000 first?

    In the example TM4C1294XL_TI_tcpEcho_non_zero_reset_vector and TM4C1294XL_simple_bootloader, it look like the bootloader has a main function, that writes debug output to the UART, then uses some assembler code to jump to the app at #define APP_RESET_VECTOR_ADDR 0x8100. Does that mean the bootloader runs every time at startup here, and then transfers control to the app? Then what does the line m3Hwi.resetVectorAddress = 0x8100; in the .cfg file of the application do?

    I am using the boot_serial_emac_flash example for the MSP432. I was under the impression that the processor jumps straight to the 0x4000 address when the board is reset, because we use the line m3Hwi.resetVectorAddress = 0x4000 in the TI-RTOS build .cfg file, is this correct? When the board is reset, I do not see any BOOTP messages from the bootloader indicating it is looking for a software update.

    If I only load the boot_serial_emac_flash with no application code and reset the MSP432, I do see BOOTP messages on the network and I am able to send a software update.

    Does the boot_serial_emac_flash example have a main function entry point that runs and transfer control to the application? If the bootloader does run first, how does it decide to transfer to the application instead of sending BOOTP messages, which it does if there is no application loaded?

    My application linker file looks like this:

    --stack_size=1024   /* C stack is also used for ISR stack */
    #define APP_BASE 0x00004000
    
    HEAPSIZE = 0x20000;  /* Size of heap buffer used by HeapMem */
    
    MEMORY
    {
        FLASH (RX) : origin = APP_BASE,   length = 0x00100000
        SRAM (RWX) : origin = 0x20000000, length = 0x00040000
    }
    
    /* Section allocation in memory */
    
    SECTIONS
    {
        .text   :   > FLASH
        .const  :   > FLASH
        .rodata :   > FLASH
        .cinit  :   > FLASH
        .pinit  :   > FLASH
        .init_array : > FLASH
    
        .TI.ramfunc : {} load=FLASH, run=SRAM, table(BINIT)
        .data   :   > SRAM
        .bss    :   > SRAM
        .sysmem :   > SRAM
    
        /* Heap buffer used by HeapMem */
        .priheap   : {
            __primary_heap_start__ = .;
            . += HEAPSIZE;
            __primary_heap_end__ = .;
        } > SRAM align 8
    
        .stack  :   > SRAM (HIGH)
    }

    Bootloader linker file:

    --retain=Vectors
    
    /* The following command line options are set as part of the CCS project.    */
    /* If you are building using the command line, or for some reason want to    */
    /* define them here, you can uncomment and modify these lines as needed.     */
    /* If you are using CCS for building, it is probably better to make any such */
    /* modifications in your CCS project and leave this file alone.              */
    /*                                                                           */
    /* --heap_size=0                                                             */
    /* --stack_size=256                                                          */
    /* --library=rtsv7M3_T_le_eabi.lib                                           */
    
    /* System memory map */
    
    MEMORY
    {
        FLASH (RX) : origin = 0x00000000, length = 0x00010000
        SRAM (RWX) : origin = 0x20000000, length = 0x00010000
    }
    
    /* Section allocation in memory */
    
    SECTIONS
    {
        GROUP
        {
            .intvecs
            .text
            .const
            .data
        } load = FLASH, run = 0x20000000, LOAD_START(init_load), RUN_START(init_run), SIZE(init_size)
    
        GROUP
        {
            .bss
            .stack
        } run = SRAM, RUN_START(bss_run), RUN_END(bss_end), SIZE(bss_size), RUN_END(__STACK_TOP)

  • Hi,

    Does adding the m3Hwi.resetVectorAddress = 0x4000 line above change the reset vector, and make the MSP432 boot to the application at address 0x4000 at startup? Or will it still boot into the bootloader at flash address 0x0000 first?

    The flash bootloader is supposed to reside at 0x0. After reset, the processor starts from 0x0 which is where the bootloader resides. If it finds a valid application at 0x4000 then it will jump to the application.

    In the example TM4C1294XL_TI_tcpEcho_non_zero_reset_vector and TM4C1294XL_simple_bootloader, it look like the bootloader has a main function, that writes debug output to the UART, then uses some assembler code to jump to the app at #define APP_RESET_VECTOR_ADDR 0x8100. Does that mean the bootloader runs every time at startup here, and then transfers control to the app? Then what does the line m3Hwi.resetVectorAddress = 0x8100; in the .cfg file of the application do?

    As explained above, the flash bootloader is first run by the processor. If there is a valid application at 0x4000 then it will jump to 0x4000 to run the application. After the application is running, it can jump back to the bootloader based on a trigger condition to force an update on the application. That trigger condition can be detecting a pin state change or detecting a magic packet. it is all up to the application on how and when to jump back to the bootloader.

    If I only load the boot_serial_emac_flash with no application code and reset the MSP432, I do see BOOTP messages on the network and I am able to send a software update.

    Yes, this is expected.

    Does the boot_serial_emac_flash example have a main function entry point that runs and transfer control to the application? If the bootloader does run first, how does it decide to transfer to the application instead of sending BOOTP messages, which it does if there is no application loaded?

    Please refer to C:\ti\simplelink_msp432e4_sdk_4_20_00_12\source\ti\devices\msp432e4\boot_loader\bl_startup_ccs.s file. 

  • Hi Charles,

    Thanks for your reply. I can see that see from bl_startup_ccs.s that the ResetISR function (mapped to the reset vector in the bootloader memory) calls the CheckForceUpdate function from bl_check.c, which checks if there is something that looks like a valid stack pointer and reset vector at the base of the application memory 0x4000.

    uint32_t
    CheckForceUpdate(void)
    {
    #ifdef CHECK_CRC
        uint32_t ui32Retcode;
    #endif
    
    #ifdef BL_CHECK_UPDATE_FN_HOOK
        //
        // If the update check function is hooked, call the application to determine
        // how to proceed.
        //
        return(BL_CHECK_UPDATE_FN_HOOK());
    #else
        uint32_t *pui32App;
    
    #ifdef ENABLE_UPDATE_CHECK
        g_ui32Forced = 0;
    #endif
    
        //
        // See if the first location is 0xfffffffff or something that does not
        // look like a stack pointer, or if the second location is 0xffffffff or
        // something that does not look like a reset vector.
        //
        pui32App = (uint32_t *)APP_START_ADDRESS;
        if((pui32App[0] == 0xffffffff) ||
           ((pui32App[0] & 0xfff00000) != 0x20000000) ||
           (pui32App[1] == 0xffffffff) ||
           ((pui32App[1] & 0xfff00001) != 0x00000001))
        {
            return(1);
        }

    I think the bootloader sequentially reprograms the flash memory of the application from 0x4000 onwards when it receives a software update, is that correct? That would explain why the MSP432 is bricked if the flash process fails after making about 80% of progress, because it has already flashed what looks like a valid stack pointer and reset vector to the base of the application memory at 0x4000. The bootloader jumps straight to a corrupt application (with a valid-looking stack pointer and reset vector) when the MSP432 is reset, and there is no way of recovering the device over Ethernet as the bootloader will not broadcast BOOTP messages and wait for an update.

    I am not sure if you know of away to get the MSP432 bootloader BSL_Scripter tool to work reliably 100% of the time for flashing? Alternatively, do you know of any different tool/bootloader combination that can overcome this limitation?

    Another method to make the MSP432 recoverable after a failed flash would be to broadcast BOOTP messages and wait for an update for about 5 seconds (or some specified timeout) every time before jumping to the application if there is a valid looking vector at the app base (which may or may not be a corrupt application). I can see that the ResetISR function in bl_startup_ccs.s branches to the UpdateBOOTP function after if the CheckForceUpdate functions returns no valid table at the base of the app memory.

    ;;*****************************************************************************
    ;;
    ;; The reset handler, which gets called when the processor starts.
    ;;
    ;;*****************************************************************************
        .thumbfunc ResetISR
    ResetISR: .asmfunc
        ;;
        ;; Enable the floating-point unit.  This must be done here in case any
        ;; later C functions use floating point.  Note that some toolchains will
        ;; use the FPU registers for general workspace even if no explicit floating
        ;; point data types are in use.
        ;;
        movw    r0, #0xED88
        movt    r0, #0xE000
        ldr     r1, [r0]
        orr     r1, r1, #0x00F00000
        str     r1, [r0]
    
        ;;
        ;; Initialize the processor.
        ;;
        bl      ProcessorInit
    
        ;;
        ;; Call the user-supplied low level hardware initialization function
        ;; if provided.
        ;;
     .if $$defined(BL_HW_INIT_FN_HOOK)
        .ref    BL_HW_INIT_FN_HOOK
        bl      BL_HW_INIT_FN_HOOK
     .endif
    
        ;;
        ;; See if an update should be performed.
        ;;
        .ref    CheckForceUpdate
        bl      CheckForceUpdate
        cbz     r0, CallApplication
    
        ;;
        ;; Configure the microcontroller.
        ;;
        .thumbfunc EnterBootLoader
    EnterBootLoader:
     .if $$defined(ENET_ENABLE_UPDATE)
        .ref PinoutSet
        bl PinoutSet
        .ref    ConfigureEnet
        bl      ConfigureEnet

    The UpdateBOOTP function is located in the bl_emac.c file and this is the function that the ResetISR calls to handle the update. However, there is also a BOOTPThread(void) function int he same file bl_emac.c, which appears more in line with what the MSP432 actually does when broadcasting these BOOTP messages and initiating the TFTP file transfer. Which of these functions (UpdateBOOTP or BOOTPThread) is used in the software update, and where is the BOOTPThread function started/called? Would it be possible to implement this x second delay to broadcast BOOTP messages for a software update, before timing out and jumping to a valid-looking application?

    Thanks for your help.

  • I think the bootloader sequentially reprograms the flash memory of the application from 0x4000 onwards when it receives a software update, is that correct?

    That is correct.

    That would explain why the MSP432 is bricked if the flash process fails after making about 80% of progress, because it has already flashed what looks like a valid stack pointer and reset vector to the base of the application memory at 0x4000. The bootloader jumps straight to a corrupt application (with a valid-looking stack pointer and reset vector) when the MSP432 is reset, and there is no way of recovering the device over Ethernet as the bootloader will not broadcast BOOTP messages and wait for an update.

    I'm not clear on your statements here. What do you mean that the flash process fails after 80%? Do you mean the software update did not 100% complete and after the reset the bootloader jumps to the application at 0x4000 and unable to run the application because of an incomplete application download? if this is the case, you would need to add CRC to the bootloading process. Before the bootloader jumps to the application, it will first check if the CRC is correct for the program image. If the CRC fails, the bootloader will not jump to the application but rather goes into the bootloading mode. 

    Please refer to the bl_config.h file in the bootloader for details. 

    //*****************************************************************************
    //
    // Enables runtime and download CRC32 checking of the main firmware image.
    // If this is defined, the boot loader will scan the main firmware image for
    // an image information header (stored immediately above the vector table and
    // marked by the words 0xFF01FF02 and 0xFF03FF04). If the header is found and
    // the CRC32 value it contains matches that calculated for the image, the
    // firmware is run. If the CRC32 does not match or the image information
    // is not found, the boot loader retains control and waits for a new download.
    // To aid debugging, if this option is used without ENFORCE_CRC being set, the
    // image will also be booted if the header is present but the length field is
    // set to 0xFFFFFFFF, typically indicating that the firmware file has not been
    // run through the post-processing tool which inserts the length and CRC values.
    //
    // Note that firmware images intended for use with CRC checking must have been
    // built with an 8 word image header appended to the top of the vector table
    // and the binary must have been processed by a tool such as tools/binpack.exe
    // to ensure that the required length (3rd word) and CRC32 (4th word) fields
    // are populated in the header.
    //
    // Depends on: ENFORCE_CRC
    // Exclusive of: None
    // Requires: None
    //
    //*****************************************************************************
    //#define CHECK_CRC

    //*****************************************************************************
    //
    // This definition may be used alongside CHECK_CRC to remove the debug behavior
    // which will allow an image with an uninitialized header to be run. With
    // ENFORCE_CRC defined firmware images will only be booted if they contain a
    // valid image information header and if the embedded CRC32 in that header
    // matches the calculated value.
    //
    // Depends on: None
    // Exclusive of: None
    // Requires: CHECK_CRC

    //*****************************************************************************
    //#define ENFORCE_CRC

    //*****************************************************************************

    The MSP432E BSL user's guide has the details as well. https://www.ti.com/lit/pdf/slau746

  • Hi Charles,

    Thanks for pointing me to the config file for the bootloader. Enabling the CRC check will be able to fix the issue where the bootloader jumps into a corrupt application.

    I was able to use the thread below as a reference to create the appropriate header after the vector table of my C++ ti-rtos application

    RTOS/TM4C1294NCPDT: CRC header for TI-RTOS - Arm-based microcontrollers forum - Arm-based microcontrollers - TI E2E support forums

    My code:

    #pragma LOCATION(0x4040)
    #pragma RETAIN
    static const unsigned char myCRC[32] = {
                                   0xFF, 0x01, 0xFF, 0x02, //predefined header - first word
                                   0xFF, 0x03, 0xFF, 0x04, //predefined header - second word
                                   0xFF, 0xFF, 0xFF, 0xFF, //word to be replaced with image length by binpack
                                   0xFF, 0xFF, 0xFF, 0xFF, //word to be replaced with CRC32 by binpack
                                   0xFF, 0xFF, 0xFF, 0xFF, //reserved word
                                   0xFF, 0xFF, 0xFF, 0xFF, //reserved word
                                   0xFF, 0xFF, 0xFF, 0xFF, //reserved word
                                   0xFF, 0xFF, 0xFF, 0xFF //reserved word
    };

    The start of my .txt file:

    @4000
    00 FC 03 20 C9 0E 06 00 61 EA 06 00 61 EA 06 00 
    61 EA 06 00 61 EA 06 00 61 EA 06 00 61 EA 06 00 
    61 EA 06 00 61 EA 06 00 61 EA 06 00 61 EA 06 00 
    61 EA 06 00 61 EA 06 00 37 F0 06 00 
    @4040
    FF 01 FF 02 FF 03 FF 04 FF FF FF FF FF FF FF FF 
    FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
    2D E9 F0 4F 91 F8 3D 30 91 F8 3C 20 42 EA 03 22 
    91 F8 3E 30 42 EA 03 42 91 F8 3F 30 AD F1 74 0D 
    42 EA 03 62 08 92 91 F8 39 30 91 F8 38 20 42 EA 
    03 22 91 F8 3A 30 42 EA 03 42 91 F8 3B 30 42 EA 
    03 62 0C 92 91 F8 35 30 91 F8 34 20 42 EA 03 22 
    91 F8 36 30 42 EA 03 42 91 F8 37 30 42 EA 03 62 
    06 92 91 F8 31 30 91 F8 30 20 42 EA 03 22 91 F8 
    32 30 42 EA 03 42 91 F8 33 30 42 EA 03 62 13 92 

    I also added the post build step below to create a bin file.

    "${CCE_INSTALL_ROOT}/utils/tiobj2bin/tiobj2bin.bat" "${BuildArtifactFileName}" "${BuildArtifactFileBaseName}.bin" "${CG_TOOL_ROOT}/bin/ofd470.exe" "${CG_TOOL_ROOT}/bin/hex470.exe" "${CCE_INSTALL_ROOT}/utils/tiobj2bin/mkhex4bin.exe"

    I could not find the binpack tool it in the MSP432 SDK, can you please point me to the location? But I did find the tool in TivaWare_C_Series-2.2.0.295.

    However, I am getting the following error from binpack when I try to pass in my .bin file:
    Error: Invalid input image format.
    The input file contains no image info header at the top of the vector table!
    Please ensure this is present before running this tool.

     

    Any advice on this? Thanks.

  • Hi Parry,

      Can you refer to the user's guide (SW-TM4C-TOOLS-UG-2.2.0.295.pdf) in the TivaWare docs folder for details. I will suggest you first generate the .bin and do the binpack manually instead of embedding as part of the CCS post build process. It will be easier to isolate the problem. 

  • Hi Charles,

    I have not integrated binpack into the post-build process. I have only integrated the conversion of the .out file to a .bin file into the post-build process using the tiobj2bin tool located in the ti/ccs tool folder.

    I am currently trying to get the binpack tool to work manually using the command:

    binpack -i Program.bin -o Program_output.bin 

    But I get the error:

    Error: Invalid input image format.
    The input file contains no image info header at the top of the vector table!
    Please ensure this is present before running this tool.

    I'm not sure if there is anything wrong with the 8-word header I created using the #pramga directives above, but binpack is unable to find the correct header in the .bin image I am generating.

    I have read the section of the SW-TM4C-TOOLS-UG-2.2.0.295.pdf manual you suggested, but the -d option seems to be appending a different type of 8-byte header, which isn't related to the CRC checking of the bootloader.

    Do you know how I would need to add the header to allow binpack to substitute the length and CRC information to the correct words on the header? After successfully making this .bin file, I would need to flash it to the MSP432 and I will be able to test the CRC check on the Ethernet bootloader (do I need to convert the .bin file back into a .out file?)

    Thanks.

  • This is a screenshot of the start of my .out/.bin file (generated in txt format for the BSL Ethernet bootloader), with and without the additional header inserted using the #pragma directives.

    Do you know why binpack is not detecting the header at the top of the vector table and throwing an error?

  • Here is a screenshot of the verbose output from the tool when running the command:binpack -i Program.bin -o Program_output.bin -v

    Are these settings correct for the file with the header I have shown above?

  • Hi Parry,

      I think there may be two issues with your binary. 

      - First, your 8-word header starts at 0x4040. This means your interrupt vector table is only 64 bytes. According to the CHECK_CRC description, it needs to at the "top" of interrupt vector table. If you look at the vector table, the last entry is at 0x000041FC. This means the the header should start at 0x00004200 in my opinion, not 0x4040. 

      - Second, if your program is going to start at 0x4000 then you need to specify -a 0x4000 -d to binpack.exe which I don't see in your command line. 

  • Hi Charles,

    Thanks for pointing that out, I wasn't sure if the header was supposed to be after the last entry of the processor exception vector table or the interrupt vectors, that clears it up.

    However, when I place the custom 8 word header for my CRC and length information at LOCATION: 0x4200, the .txt file generated for my .out/.bin files looks like this:

    It looks like the header always gets placed right after the processor exception (reset vec, etc.) interrupt table and before the rest of the interrupt vectors (assuming the bytes 2D E9 onwards are the interrupts vectors).

    Is there an issue with the way I am trying to place the header from my code? I'm not sure how to get it to be placed at 0x4200 after the interrupt vectors.

    Still receiving the following error from the binpack tool after entering the command: binpack -i Program.bin -o Program_output.bin -a 0x4000 -d -v

    Application .cmd file:

    --stack_size=1024   /* C stack is also used for ISR stack */
    #define APP_BASE 0x00004000
    
    HEAPSIZE = 0x20000;  /* Size of heap buffer used by HeapMem */
    
    MEMORY
    {
        FLASH (RX) : origin = APP_BASE,   length = 0x00100000
        SRAM (RWX) : origin = 0x20000000, length = 0x00040000
    }
    
    /* Section allocation in memory */
    
    SECTIONS
    {
        .text   :   > FLASH
        .const  :   > FLASH
        .rodata :   > FLASH
        .cinit  :   > FLASH
        .pinit  :   > FLASH
        .init_array : > FLASH
    
        .TI.ramfunc : {} load=FLASH, run=SRAM, table(BINIT)
        .data   :   > SRAM
        .bss    :   > SRAM
        .sysmem :   > SRAM
    
        /* Heap buffer used by HeapMem */
        .priheap   : {
            __primary_heap_start__ = .;
            . += HEAPSIZE;
            __primary_heap_end__ = .;
        } > SRAM align 8
    
        .stack  :   > SRAM (HIGH)
    }

    TI-RTOS build  release.cfg file:

    /*
     * Copyright (c) 2015-2018, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    
    
    /* ================ Clock configuration ================ */
    var Clock = xdc.useModule('ti.sysbios.knl.Clock');
    /*
     * Default value is family dependent. For example, Linux systems often only
     * support a minimum period of 10000 us and multiples of 10000 us.
     * TI platforms have a default of 1000 us.
     */
    Clock.tickPeriod = 1000;
    
    
    
    /* ================ Defaults (module) configuration ================ */
    var Defaults = xdc.useModule('xdc.runtime.Defaults');
    /*
     * A flag to allow module names to be loaded on the target. Module name
     * strings are placed in the .const section for debugging purposes.
     *
     * Pick one:
     *  - true (default)
     *      Setting this parameter to true will include name strings in the .const
     *      section so that Errors and Asserts are easier to debug.
     *  - false
     *      Setting this parameter to false will reduce footprint in the .const
     *      section. As a result, Error and Assert messages will contain an
     *      "unknown module" prefix instead of the actual module name.
     */
    //Defaults.common$.namedModule = true;
    Defaults.common$.namedModule = false;
    
    
    
    /* ================ Error configuration ================ */
    var Error = xdc.useModule('xdc.runtime.Error');
    /*
     * This function is called to handle all raised errors, but unlike
     * Error.raiseHook, this function is responsible for completely handling the
     * error with an appropriately initialized Error_Block.
     *
     * Pick one:
     *  - Error.policyDefault (default)
     *      Calls Error.raiseHook with an initialized Error_Block structure and logs
     *      the error using the module's logger.
     *  - Error.policySpin
     *      Simple alternative that traps on a while(1) loop for minimized target
     *      footprint.
     *      Using Error.policySpin, the Error.raiseHook will NOT called.
     *  - Error.policyMin
     *      Lightweight policy function that does minimum processing and returns.
     */
    //Error.policyFxn = Error.policyDefault;
    //Error.policyFxn = Error.policySpin;
    Error.policyFxn = Error.policyMin;
    
    /*
     * If Error.policyFxn is set to Error.policyDefault, this function is called
     * whenever an error is raised by the Error module.
     *
     * Pick one:
     *  - Error.print (default)
     *      Errors are formatted and output via System_printf() for easier
     *      debugging.
     *  - null
     *      Errors are not formatted or logged. This option reduces code footprint.
     *  - non-null function
     *      Errors invoke custom user function. See the Error module documentation
     *      for more details.
     */
    //Error.raiseHook = Error.print;
    Error.raiseHook = null;
    //Error.raiseHook = "&myErrorFxn";
    
    /*
     * If Error.policyFxn is set to Error.policyDefault, this option applies to the
     * maximum number of times the Error.raiseHook function can be recursively
     * invoked. This option limits the possibility of an infinite recursion that
     * could lead to a stack overflow.
     * The default value is 16.
     */
    Error.maxDepth = 2;
    
    
    
    /* ================ Hwi configuration ================ */
    var halHwi = xdc.useModule('ti.sysbios.hal.Hwi');
    var m3Hwi = xdc.useModule('ti.sysbios.family.arm.m3.Hwi');
    /*
     * Checks for Hwi (system) stack overruns while in the Idle loop.
     *
     * Pick one:
     *  - true (default)
     *      Checks the top word for system stack overflows during the idle loop and
     *      raises an Error if one is detected.
     *  - false
     *      Disabling the runtime check improves runtime performance and yields a
     *      reduced flash footprint.
     */
    //halHwi.checkStackFlag = true;
    halHwi.checkStackFlag = false;
    
    /*
     * The following options alter the system's behavior when a hardware exception
     * is detected.
     *
     * Pick one:
     *  - Hwi.enableException = true
     *      This option causes the default m3Hwi.excHandlerFunc function to fully
     *      decode an exception and dump the registers to the system console.
     *      This option raises errors in the Error module and displays the
     *      exception in ROV.
     *  - Hwi.enableException = false
     *      This option reduces code footprint by not decoding or printing the
     *      exception to the system console.
     *      It however still raises errors in the Error module and displays the
     *      exception in ROV.
     *  - Hwi.excHandlerFunc = null
     *      This is the most aggressive option for code footprint savings; but it
     *      can difficult to debug exceptions. It reduces flash footprint by
     *      plugging in a default while(1) trap when exception occur. This option
     *      does not raise an error with the Error module.
     */
    //m3Hwi.enableException = true;
    //m3Hwi.enableException = false;
    m3Hwi.excHandlerFunc = null;
    
    /*
     * Enable hardware exception generation when dividing by zero.
     *
     * Pick one:
     *  - 0 (default)
     *      Disables hardware exceptions when dividing by zero
     *  - 1
     *      Enables hardware exceptions when dividing by zero
     */
    m3Hwi.nvicCCR.DIV_0_TRP = 0;
    //m3Hwi.nvicCCR.DIV_0_TRP = 1;
    
    
    
    /* ================ Idle configuration ================ */
    var Idle = xdc.useModule('ti.sysbios.knl.Idle');
    /*
     * The Idle module is used to specify a list of functions to be called when no
     * other tasks are running in the system.
     *
     * Functions added here will be run continuously within the idle task.
     *
     * Function signature:
     *     Void func(Void);
     */
    //Idle.addFunc("&myIdleFunc");
    
    Idle.addFunc('&Power_idleFunc');  /* add the Power module's idle function */
    
    
    
    /* ================ Kernel (SYS/BIOS) configuration ================ */
    var BIOS = xdc.useModule('ti.sysbios.BIOS');
    /*
     * Enable asserts in the BIOS library.
     *
     * Pick one:
     *  - true (default)
     *      Enables asserts for debugging purposes.
     *  - false
     *      Disables asserts for a reduced code footprint and better performance.
     */
    //BIOS.assertsEnabled = true;
    BIOS.assertsEnabled = false;
    
    /*
     * A flag to determine if xdc.runtime sources are to be included in a custom
     * built BIOS library.
     *
     * Pick one:
     *  - false (default)
     *      The pre-built xdc.runtime library is provided by the respective target
     *      used to build the application.
     *  - true
     *      xdc.runtime library sources are to be included in the custom BIOS
     *      library. This option yields the most efficient library in both code
     *      footprint and runtime performance.
     */
    //BIOS.includeXdcRuntime = false;
    BIOS.includeXdcRuntime = true;
    
    /*
     * The SYS/BIOS runtime is provided in the form of a library that is linked
     * with the application. Several forms of this library are provided with the
     * SYS/BIOS product.
     *
     * Pick one:
     *   - BIOS.LibType_Custom
     *      Custom built library that is highly optimized for code footprint and
     *      runtime performance.
     *   - BIOS.LibType_Debug
     *      Custom built library that is non-optimized that can be used to
     *      single-step through APIs with a debugger.
     *
     */
    BIOS.libType = BIOS.LibType_Custom;
    //BIOS.libType = BIOS.LibType_Debug;
    
    /*
     * Runtime instance creation enable flag.
     *
     * Pick one:
     *   - true (default)
     *      Allows Mod_create() and Mod_delete() to be called at runtime which
     *      requires a default heap for dynamic memory allocation.
     *   - false
     *      Reduces code footprint by disallowing Mod_create() and Mod_delete() to
     *      be called at runtime. Object instances are constructed via
     *      Mod_construct() and destructed via Mod_destruct().
     */
    BIOS.runtimeCreatesEnabled = true;
    //BIOS.runtimeCreatesEnabled = false;
    
    /*
     * Enable logs in the BIOS library.
     *
     * Pick one:
     *  - true (default)
     *      Enables logs for debugging purposes.
     *  - false
     *      Disables logging for reduced code footprint and improved runtime
     *      performance.
     */
    //BIOS.logsEnabled = true;
    BIOS.logsEnabled = false;
    
    
    
    /* ================ Memory configuration ================ */
    var Memory = xdc.useModule('xdc.runtime.Memory');
    /*
     * The Memory module itself simply provides a common interface for any
     * variety of system and application specific memory management policies
     * implemented by the IHeap modules(Ex. HeapMem, HeapBuf).
     */
    
    /*
     * Use HeapMem primary heap instance to use linker-defined memory region
     * Add HeapTrack on top to find over-writes, invalid frees, and
     * aid in finding the correct sizing of the heap and memory leaks.
     */
    var HeapMem = xdc.useModule('ti.sysbios.heaps.HeapMem');
    HeapMem.primaryHeapBaseAddr = "&__primary_heap_start__";
    HeapMem.primaryHeapEndAddr = "&__primary_heap_end__";
    
    var heapMemParams = new HeapMem.Params();
    heapMemParams.usePrimaryHeap = true;
    
    //var HeapTrack = xdc.useModule('ti.sysbios.heaps.HeapTrack');
    //var heapTrackParams = new HeapTrack.Params;
    //heapTrackParams.heap = HeapMem.create(heapMemParams);
    //Program.global.heap0 = HeapTrack.create(heapTrackParams);
    Program.global.heap0 = HeapMem.create(heapMemParams);
    
    Memory.defaultHeapInstance = Program.global.heap0;
    
    
    
    /* ================ Program configuration ================ */
    /*
     *  Program.stack must be set to 0 to allow the setting
     *  of the system stack size to be determined in the example's
     *  linker command file.
     */
    Program.stack = 0;
    
    
    /*
     * Uncomment to enable Semihosting for GNU targets to print to the CCS console.
     * Please read the following TIRTOS Wiki page for more information on Semihosting:
     * http://processors.wiki.ti.com/index.php/TI-RTOS_Examples_SemiHosting
     */
    
    if (Program.build.target.$name.match(/gnu/)) {
        //var SemiHost = xdc.useModule('ti.sysbios.rts.gnu.SemiHostSupport');
    }
    
    
    
    /* ================ Semaphore configuration ================ */
    var Semaphore = xdc.useModule('ti.sysbios.knl.Semaphore');
    /*
     * Enables global support for Task priority pend queuing.
     *
     * Pick one:
     *  - true (default)
     *      This allows pending tasks to be serviced based on their task priority.
     *  - false
     *      Pending tasks are services based on first in, first out basis.
     *
     *  When using BIOS in ROM:
     *      This option must be set to false.
     */
    //Semaphore.supportsPriority = true;
    Semaphore.supportsPriority = false;
    
    /*
     * Allows for the implicit posting of events through the semaphore,
     * disable for additional code saving.
     *
     * Pick one:
     *  - true
     *      This allows the Semaphore module to post semaphores and events
     *      simultaneously.
     *  - false (default)
     *      Events must be explicitly posted to unblock tasks.
     *
     */
    //Semaphore.supportsEvents = true;
    Semaphore.supportsEvents = false;
    
    
    
    /* ================ Swi configuration ================ */
    var Swi = xdc.useModule('ti.sysbios.knl.Swi');
    /*
     * A software interrupt is an object that encapsulates a function to be
     * executed and a priority. Software interrupts are prioritized, preempt tasks
     * and are preempted by hardware interrupt service routines.
     *
     * This module is included to allow Swi's in a users' application.
     */
    
    
    
    /* ================ System configuration ================ */
    var System = xdc.useModule('xdc.runtime.System');
    /*
     * The Abort handler is called when the system exits abnormally.
     *
     * Pick one:
     *  - System.abortStd (default)
     *      Call the ANSI C Standard 'abort()' to terminate the application.
     *  - System.abortSpin
     *      A lightweight abort function that loops indefinitely in a while(1) trap
     *      function.
     *  - A custom abort handler
     *      A user-defined function. See the System module documentation for
     *      details.
     */
    //System.abortFxn = System.abortStd;
    System.abortFxn = System.abortSpin;
    //System.abortFxn = "&myAbortSystem";
    
    /*
     * The Exit handler is called when the system exits normally.
     *
     * Pick one:
     *  - System.exitStd (default)
     *      Call the ANSI C Standard 'exit()' to terminate the application.
     *  - System.exitSpin
     *      A lightweight exit function that loops indefinitely in a while(1) trap
     *      function.
     *  - A custom exit function
     *      A user-defined function. See the System module documentation for
     *      details.
     */
    //System.exitFxn = System.exitStd;
    System.exitFxn = System.exitSpin;
    //System.exitFxn = "&myExitSystem";
    
    /*
     * Minimize exit handler array in the System module. The System module includes
     * an array of functions that are registered with System_atexit() which is
     * called by System_exit(). The default value is 8.
     */
    System.maxAtexitHandlers = 2;
    
    /*
     * Enable System_printf() to display floats.  Use the longer '%f%$L%$S%$F'
     * if your code has SYS/BIOS instrumentation enabled (Asserts/Error/Log),
     * as is typical with the 'debug' profile.
     */
    //System.extendedFormats = '%f%$L%$S%$F';
    System.extendedFormats = '%f%$S';
    
    /*
     * The System.SupportProxy defines a low-level implementation of System
     * functions such as System_printf(), System_flush(), etc.
     *
     * Pick one pair:
     *  - SysMin
     *      This module maintains an internal configurable circular buffer that
     *      stores the output until System_flush() is called.
     *      The size of the circular buffer is set via SysMin.bufSize.
     *  - SysCallback
     *      SysCallback allows for user-defined implementations for System APIs.
     *      The SysCallback support proxy has a smaller code footprint and can be
     *      used to supply custom System_printf services.
     *      The default SysCallback functions point to stub functions. See the
     *      SysCallback module's documentation.
     */
    //var SysMin = xdc.useModule('xdc.runtime.SysMin');
    //SysMin.bufSize = 1024;
    //System.SupportProxy = SysMin;
    var SysCallback = xdc.useModule('xdc.runtime.SysCallback');
    System.SupportProxy = SysCallback;
    //SysCallback.abortFxn = "&myUserAbort";
    //SysCallback.exitFxn  = "&myUserExit";
    //SysCallback.flushFxn = "&myUserFlush";
    //SysCallback.putchFxn = "&myUserPutch";
    //SysCallback.readyFxn = "&myUserReady";
    
    
    
    /* ================ Task configuration ================ */
    var Task = xdc.useModule('ti.sysbios.knl.Task');
    /*
     * Check task stacks for overflow conditions.
     *
     * Pick one:
     *  - true (default)
     *      Enables runtime checks for task stack overflow conditions during
     *      context switching ("from" and "to")
     *  - false
     *      Disables runtime checks for task stack overflow conditions.
     */
    //Task.checkStackFlag = true;
    Task.checkStackFlag = false;
    
    /*
     * Set the default task stack size when creating tasks.
     *
     * The default is dependent on the device being used. Reducing the default stack
     * size yields greater memory savings.
     */
    Task.defaultStackSize = 512;
    
    /*
     * Enables the idle task.
     *
     * Pick one:
     *  - true (default)
     *      Creates a task with priority of 0 which calls idle hook functions. This
     *      option must be set to true to gain power savings provided by the Power
     *      module.
     *  - false
     *      No idle task is created. This option consumes less memory as no
     *      additional default task stack is needed.
     *      To gain power savings by the Power module without having the idle task,
     *      add Idle.run as the Task.allBlockedFunc.
     */
    Task.enableIdleTask = true;
    //Task.enableIdleTask = false;
    //Task.allBlockedFunc = Idle.run;
    
    /*
     * If Task.enableIdleTask is set to true, this option sets the idle task's
     * stack size.
     *
     * Reducing the idle stack size yields greater memory savings.
     */
    Task.idleTaskStackSize = 512;
    
    /*
     * Reduce the number of task priorities.
     * The default is 16.
     * Decreasing the number of task priorities yield memory savings.
     */
    Task.numPriorities = 16;
    
    /*
     * Allows SYSBIOS to clean up terminated tasks
     * This is required if using the NDK in order to free dynamically created
     * Task threads that have terminated.
     */
    Task.deleteTerminatedTasks = true;
    
    
    /* ================ Text configuration ================ */
    var Text = xdc.useModule('xdc.runtime.Text');
    /*
     * These strings are placed in the .const section. Setting this parameter to
     * false will save space in the .const section. Error, Assert and Log messages
     * will print raw ids and args instead of a formatted message.
     *
     * Pick one:
     *  - true (default)
     *      This option loads test string into the .const for easier debugging.
     *  - false
     *      This option reduces the .const footprint.
     */
    //Text.isLoaded = true;
    Text.isLoaded = false;
    
    
    
    /* ================ Types configuration ================ */
    var Types = xdc.useModule('xdc.runtime.Types');
    /*
     * This module defines basic constants and types used throughout the
     * xdc.runtime package.
     */
    
    
    
    /* ================ Application Specific Instances ================ */
    
    /* ================ Diagnostics configuration ================ */
    //var Diags = xdc.useModule('xdc.runtime.Diags');
    /*
     * You use the Diags module to set and clear bits in a module's diagnostics
     * mask for the purpose of controlling diagnostics within that module. A
     * module diagnostics mask controls both Assert and Log statements
     * within that module, disabling these statements yields
     * code savings.
     */
    
    /* ================ Logging configuration ================ */
    //var Log = xdc.useModule('xdc.runtime.Log');
    /*
     * Modules and the application code generate Log_Event events by calling
     * the Log module's functions.
     * Disabling all Log statements here will allow the optimizer to completely
     * remove all Log code from the application.
     *
     * Note: In order to generate Log events in your application both the Diags
     *       and the Log mask must be set. See the SYS/BIOS API guide for
     *       more information.
     */
    
    /*
     * LoggingSetup configures TI-RTOS modules to capture user-specified information
     * such as CPU Load, Task Load and Task Execution so that it can be
     * displayed by System Analyzer.
     */
    //var LoggingSetup = xdc.useModule('ti.uia.sysbios.LoggingSetup');
    //LoggingSetup.loadLoggerSize = 256;
    //LoggingSetup.mainLoggerSize = 512;
    //LoggingSetup.sysbiosLoggerSize = 1024;
    
    /* ================ Main configuration ================ */
    var Main = xdc.useModule('xdc.runtime.Main');
    /* Configuration of this Main module is used for all code not in a module */
    
    /* ================ POSIX configuration ================ */
    var Settings = xdc.useModule('ti.posix.tirtos.Settings');
    
    /* ================ Event configuration ================ */
    var Event = xdc.useModule('ti.sysbios.knl.Event');
    
    /* ================ Mailbox configuration ================ */
    var Mailbox = xdc.useModule('ti.sysbios.knl.Mailbox');
    
    /*
     * ================ NDK configuration ================
     * Create a Task hook set and configure its register function in order to
     * enable Thread Local Storage (required by the NDK).
     */
    var Task = xdc.useModule('ti.sysbios.knl.Task');
    var ndkHooks = new Task.HookSet();
    ndkHooks.registerFxn = '&NDK_hookInit';
    Task.addHookSet(ndkHooks);
    m3Hwi.resetVectorAddress = 0x4000;
    

    which automatically generates the linker.cmd file:
    /*
     * Do not modify this file; it is automatically generated from the template
     * linkcmd.xdt in the ti.platforms.msp432 package and will be overwritten.
     */
    
    /*
     * put '"'s around paths because, without this, the linker
     * considers '-' as minus operator, not a file name character.
     */
    
    
    -l"C:\sandbox\emanip-arm_ctrl-main\sm_6446_001_arm_controller_ti_rtos\src\tirtos_builds_MSP432E411Y_BGAEVM_release_ccs\Debug\configPkg\package\cfg\release_pem4f.oem4f"
    -l"C:\sandbox\emanip-arm_ctrl-main\sm_6446_001_arm_controller_ti_rtos\src\tirtos_builds_MSP432E411Y_BGAEVM_release_ccs\src\sysbios\sysbios.aem4f"
    -l"C:\sandbox\emanip-arm_ctrl-config\lib\simplelink_msp432e4_sdk_4_20_00_12_SAAB_MSP432E411\kernel\tirtos\packages\ti\targets\arm\rtsarm\lib\boot.aem4f"
    -l"C:\sandbox\emanip-arm_ctrl-config\lib\simplelink_msp432e4_sdk_4_20_00_12_SAAB_MSP432E411\kernel\tirtos\packages\ti\targets\arm\rtsarm\lib\auto_init.aem4f"
    -l"C:\ti\ccs1200\xdctools_3_62_01_16_core\packages\xdc\rov\runtime\lib\xdc.rov.runtime.aem4f"
    
    --retain="*(xdc.meta)"
    
    /* C6x Elf symbols */
    --symbol_map __TI_STACK_SIZE=__STACK_SIZE
    --symbol_map __TI_STACK_BASE=__stack
    --symbol_map _stack=__stack
    
    
    --args 0x0
    -heap  0x0
    
    /*
     * Linker command file contributions from all loaded packages:
     */
    
    /* Content from xdc.services.global (null): */
    
    /* Content from xdc (null): */
    
    /* Content from xdc.corevers (null): */
    
    /* Content from xdc.rov (null): */
    
    /* Content from xdc.runtime (null): */
    
    /* Content from xdc.rov.runtime (null): */
    
    /* Content from xdc.shelf (null): */
    
    /* Content from xdc.services.spec (null): */
    
    /* Content from xdc.services.intern.xsr (null): */
    
    /* Content from xdc.services.intern.gen (null): */
    
    /* Content from xdc.services.intern.cmd (null): */
    
    /* Content from xdc.bld (null): */
    
    /* Content from ti.targets (null): */
    
    /* Content from ti.targets.arm.elf (null): */
    
    /* Content from ti.targets.arm.rtsarm (null): */
    
    /* Content from ti.sysbios.interfaces (null): */
    
    /* Content from ti.sysbios.family (null): */
    
    /* Content from ti.sysbios.family.arm (ti/sysbios/family/arm/linkcmd.xdt): */
    
    /* Content from xdc.services.getset (null): */
    
    /* Content from ti.sysbios.rts (null): */
    
    /* Content from xdc.runtime.knl (null): */
    
    /* Content from xdc.platform (null): */
    
    /* Content from ti.catalog.arm.cortexm4 (null): */
    
    /* Content from ti.catalog (null): */
    
    /* Content from ti.catalog.peripherals.hdvicp2 (null): */
    
    /* Content from ti.catalog.arm.peripherals.timers (null): */
    
    /* Content from xdc.cfg (null): */
    
    /* Content from ti.platforms.msp432 (null): */
    
    /* Content from ti.sysbios.family.arm.msp432e4.init (null): */
    
    /* Content from ti.sysbios (null): */
    
    /* Content from ti.sysbios.hal (null): */
    
    /* Content from ti.sysbios.family.arm.lm4 (null): */
    
    /* Content from ti.sysbios.family.arm.m3 (ti/sysbios/family/arm/m3/linkcmd.xdt): */
    -u _c_int00
    --retain "*(.resetVecs)"
    --retain "*(.vecs)"
    ti_sysbios_family_arm_m3_Hwi_nvic = 0xe000e000;
    
    /* Content from ti.sysbios.knl (null): */
    
    /* Content from ti.sysbios.gates (null): */
    
    /* Content from ti.sysbios.heaps (null): */
    
    /* Content from ti.sysbios.xdcruntime (null): */
    
    /* Content from ti.sysbios.rts.ti (ti/sysbios/rts/ti/linkcmd.xdt): */
    
    /* Content from ti.posix.tirtos (null): */
    
    /* Content from ti.sysbios.utils (null): */
    
    /* Content from configPkg (null): */
    
    /* Content from xdc.services.io (null): */
    
    
    
    /*
     * symbolic aliases for static instance objects
     */
    xdc_runtime_Startup__EXECFXN__C = 1;
    xdc_runtime_Startup__RESETFXN__C = 1;
    xdc_rov_runtime_Mon__checksum = 1;
    xdc_rov_runtime_Mon__write = 1;
    
    
    SECTIONS
    {
        .bootVecs:  type = DSECT
        .resetVecs: load > 0x4000
        .vecs: load > 0x20000000, type = NOLOAD
    
    
    
        xdc.meta: type = COPY
        xdc.noload: type = COPY
    }
    


    Any idea why this is happening and how I can fix the issue?

    Thanks.

  • It looks like the header always gets placed right after the processor exception (reset vec, etc.) interrupt table and before the rest of the interrupt vectors (assuming the bytes 2D E9 onwards are the interrupts vectors).

    Hi Parry,

      I think 2D E9 is your rest of the program image, not the interrupt vectors. 

    Is there an issue with the way I am trying to place the header from my code? I'm not sure how to get it to be placed at 0x4200 after the interrupt vectors.

    I'm guessing your issue may be due to endianism. In your image above, you are writing the header in byte order as in 0xFF, 0x01, 0xFF, 0x02. But when you look at this as 32-bit word, it will be 0x02FF01FF. You can look at in 32-bit in CCS memory browser. Please try to enter into your myCRC array in the little endian order which will be 0x02, 0xFF, 0x01, 0xFF and also the next 4 bytes. Try to see if this resolves the issue. 

    Application .cmd file:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    --stack_size=1024 /* C stack is also used for ISR stack */
    #define APP_BASE 0x00004000
    HEAPSIZE = 0x20000; /* Size of heap buffer used by HeapMem */
    MEMORY
    {
    FLASH (RX) : origin = APP_BASE, length = 0x00100000
    SRAM (RWX) : origin = 0x20000000, length = 0x00040000
    }
    /* Section allocation in memory */
    SECTIONS
    {
    .text : > FLASH
    .const : > FLASH
    .rodata : > FLASH
    .cinit : > FLASH
    .pinit : > FLASH
    .init_array : > FLASH

    Your application length is incorrect. If you are starting the application 0x04000 then the length should be as follows.

    FLASH (RX) : origin = APP_BASE,   length = 0x000FC000

    I will also suggest you start with a simple non TI-RTOS image like a blinky example. The non RTOS examples have the interrupt vector table fully filled. But on the TI-RTOS examples, the table is not fully filled for all default entries. I don't know if that makes a difference to the binpack.exe when it tries to find the top of the interrupt vector table. See if you can get the non TI-RTOS bin files to work first and later move on to the TI-RTOS bin files. 

  • Hi Charles,

    Thanks for your response. The endianness was definitely the issue for the binpack tool to detect the header, I changed it as you suggested and the tool was able to run on my .bin file.

    I have correct the length of my application in the linker file.

    A comparison of the two binpack commands is below (one adds an 8-byte header to the start which I'm not sure is necessary)

    binpack -i Program.bin -o Program_output.bin -v

    binpack -i Program.bin -o Program_output-w-header.bin -a 0x4000 -d -v


     

    I am able to flash this new bin file Program_output.bin (without the 8-byte header at the start) to the MSP432 using UniFlash, after I flash in the bootloader separately with ENABLE_CRC and FORCE_CRC options enabled in the bl_config.h file.

    Is there a way to allow Code Composer to convert the new Program_output.bin file to a .out file and use that as the artifact to flash into the MSP432? It will also need to generate the .txt file to send using BSL_Scripter. The .out and .txt files generated by code composer currently do not have the CRC and length information as this is done separately by binpack. I need to be able to debug this project using Code Composer to progress it.

    I manually edited the .txt file generated from Code Composer by looking at the hex from Program_output.bin above to add the CRC and length information. When I tried to send this using BSL scritper, there are no BOOTP messages and I have no idea whether the code jumped to the bootloader successfully as I am unable to debug this through Code Composer.

    Thanks for your help.

  • Thanks for your response. The endianness was definitely the issue for the binpack tool to detect the header, I changed it as you suggested and the tool was able to run on my .bin file.

    I have correct the length of my application in the linker file.

    I am able to flash this new bin file Program_output.bin (without the 8-byte header at the start) to the MSP432 using UniFlash, after I flash in the bootloader separately with ENABLE_CRC and FORCE_CRC options enabled in the bl_config.h file.

    Hi Parry,

      Glad you make progress and the problem is resolved. 

    Is there a way to allow Code Composer to convert the new Program_output.bin file to a .out file and use that as the artifact to flash into the MSP432?

    There is no converter to convert a bin file back to a .out file. A bin file will not contain debug symbols while a .out file will. This is why a .out file will be larger than .bin file. What you can is to first load your program using a .bin file. Once the firmware is programmed, you can use the 'Load Symbol' command to add just the symbols. You still provide the .out file but that it merely adds the symbols and will not reprogram the firmware using JTAG. You can do the same for both the bootloader and the application for debugging. 

  • Hi Charles,

    From your screenshot it looks like you have already started a Debug session, did you do this by loading in the .bin file first? Can you tell me the steps to load in the bin file, before I can load the symbols from the out file to debug it? I can't figure out how to start the debug session using the .bin file. I think I need to start a debug session to see those options in the Run drop-down.

    Thanks.

  • Hi Parry,

      Try this on a simple blinky non-RTOS example. First load the blinky.bin or any simple program through JTAG. You should see the LED blinking but there is no source code to view if use CCS to connect to the device. Now do "Load Symbols" and specify the blink.out, you will see the source code and debug symbols added. 

  • Hi Charles,

    Thanks for clarifying but I still do not understand the steps to upload a .bin file from Code Composer, and then add the symbols from the .out file afterwards. I do not have the same options as you under the Run tab. Could you explain the steps?

    I did however manage to get debugging with my .out file artifact from the CCS project, by commenting ENFORCE_CRC in bl_config. As the comments mention, this is for debugging, so as long as the CRC header is present, the actual CRC value and length information do not need to be present to jump to the application - for debugging.

    I have been getting inconsistent results with the bootloader after successfully enabling the CRC. I know that the check if happening now, but if the CRC is wrong / not present, the bootloader still jumps into the application, which should not be happening.

    I think I have found an issue with the CheckForceUpdate function in the bl_check,c file in the bootloader.

    We can see from the bl_startup_ccs.s file that if there is an application to jump to CheckForceUpdate function returns 0, and we jump to CallApplication. Otherwse, we should continue to EnterBootLoader and BOOTP messages should start appearing on the network.

    I know that if there is only the bootloader in the flash and no application present, we do continue to EnterBootLoader and see BOOTP messages on the network. This exit point from the CheckForceUpdate function is shown below and is the correct behaviour to expect:

    However, if there is an application but it is corrupted and the CRC is wrong, there is a different exit point from the CheckForceUpdate function shown below:


    I think if the CRC is wrong and we return (2), the cbz instruction in bl_startup_ccs.s file is not handling this correctly and we are still jumping to a corrupt application. I changed this statement to return (1), and I am now observing correct behaviour from the bootloader. If the CRC is wrong or not present, we continue to EnterBootLoader and I can now see BOOTP messages on the network.

    Why is there a return (2) statement here? Is this just a typo in the bootloader code from the MSP432 SDK, or is there a reason for it? I can also see that this is the only place in the bootloader library code from the SDK\source\ti\devices\msp432e4\boot_loader where there is a return (2) statement.

    Thanks for the help.

  • Hi Parry,

      I first use Uniflash to load a .bin file. See below. 

    Next I use CCS to connect to the target. I can view the flash content but no debug symbols and source code. 

    Next I 'Add symbols' by supplying the corresponding .out file. Bear in mind the this is only to add symbols. It will not reprogram the flash.

  • Hi Charles,

    Thanks for showing me how to do that.

    There's just a few more things I need to clear out before I have a reliable bootloader with the CRC check.

    Issue 1:

    I have narrowed it down, and it looks like a specific part of the code in the CheckForceUpdate function in bl_check.c, which checks for a valid-looking vector table at APP_START_ADDRESS, causes the CRC implementation to break.

    I have highlighted the code below (I have deactivated it here, but it is a check that always runs in this function before checking the CRC).

    This is what I am observing with the problem section activated/deactivated:

    • With Problem Section (checking reset vector and stack pointer):
      • Valid CRC -> Boot into application
      • Invalid CRC -> Does not boot into application, but NO BOOTP requests - bricked MSP432 
    • Without Problem Section (deactivated checking reset vector and stack pointer):
      • Valid CRC -> Boot into application
      • Invalid CRC -> Does not boot into application, sends BOOTP requests - allows firmware recovery of MSP432

    I have not figured out why this if statement changes the behaviour of a valid/invalid CRC yet, do you have any idea why that may be? Please correct me if I am wrong, I think there should be BOOTP requests when the CRC is invalid and we do not boot into the application (highlighted green) - this is the functionality I would expect to see.

    I could get over this by deactivating this check in the bl_check.c file that comes from the MSP432 SDK. It looks like this check of the reset vector and stack pointer is unnecessary when the CRC is enabled, because the CRC calculation includes the reset vector and stack pointer.

    Do you have any ideas as to why I am having this issue?

    Issue 2:

    The BSL_Scripter tool uses a .txt file generated by the Arm Hex Utility from CCS to send the code over Ethernet to the MSP432. My two post-build steps essentially take the .out file artifact and convert it to a .bin file, then binpack.exe adds the necessary length and CRC information to the header:
    1. "${CCE_INSTALL_ROOT}/utils/tiobj2bin/tiobj2bin.bat" "${BuildArtifactFileBaseName}.out" "${BuildArtifactFileBaseName}.bin" "${CG_TOOL_ROOT}/bin/ofd470.exe" "${CG_TOOL_ROOT}/bin/hex470.exe" "${CCE_INSTALL_ROOT}/utils/tiobj2bin/mkhex4bin.exe"
    2. "C:/ti/binpack/binpack.exe" -i "${BuildArtifactFileBaseName}.bin" -o "${BuildArtifactFileBaseName}_output.bin" -x

    Since the .txt file from the Arm Hex Utility is converted from the .out file, it does not contain the length and CRC information I require from the .bin file after binpack. Is there a tool to convert the .bin file to a .txt file that BSL scripter can use?

    Further to this, I did try to manually edit the .txt file with the length and CRC information, but there seems to be an error with the CRC calculation? The bootloader does not boot into the app after receiving the file from BSL_Scripter, but waits sending BOOTP requests (when the if statement highlighted is deactivated).

    Appreciate your help on this. Thanks.

  • This is what I am observing with the problem section activated/deactivated:

    • With Problem Section (checking reset vector and stack pointer):
      • Valid CRC -> Boot into application
      • Invalid CRC -> Does not boot into application, but NO BOOTP requests - bricked MSP432 
    • Without Problem Section (deactivated checking reset vector and stack pointer):
      • Valid CRC -> Boot into application
      • Invalid CRC -> Does not boot into application, sends BOOTP requests - allows firmware recovery of MSP432

    Hi Parry,

      The bootloader will check for a valid application vector table. A valid vector table means the stack pointer and the reset vector are not all F's. If they are F's then it means it is not a valid vector table.  

    Is there a tool to convert the .bin file to a .txt file that BSL scripter can use?

    In the BSL Scripter user's guide https://www.ti.com/lit/pdf/slau655, it talks about how to generate the .txt file. 

    I want to also give you a heads-up that I will be OOO starting tomorrow until next Tuesday. My response will be much delayed as I may not have access to the internet. 

  • Hi Charles,

    Thanks for your response.

    I understand that the code checks for a valid vector table. But this vector table check causes the CRC implementation to break. If I upload an app with an invalid CRC, I do not receive any BOOTP messages from the bootloader - making the device unrecoverable through Ethernet. Why does this happen?

    As for the .txt file generator, I understand that the Arm Hex Tool in CCS can generate a .txt or .hex file from a .out file, but the .out file is not the final artifact of build process. As I have mentioned above, my build steps create a _output.bin file which is generated by binpack with the CRC and length header information. I need to convert this .bin to a .txt or .hex file to send over Ethernet using BSL_Scripter, but it looks like the hex tool does not support .bin as an input file format..

    If I try to manually add the CRC and length information to the .txt file generated from the .out file using the Arm Hex tool, there is a CRC error and it will not boot into my application but send BOOTP requests on the network.

    Kindly look into this as I have come to a point where I can't find information on this from the above user manuals.

  • Hi Parry,

      Sorry, I'm on vacation. I'm actually traveling at the moment. I will reply you when I come back next week. In the meantime please see if you can make some progress on your own. I really apologize.