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.

LAUNCHXL-CC26X2R1: System Configuration Tool Bug: External SPI Flash CS Pin

Part Number: LAUNCHXL-CC26X2R1
Other Parts Discussed in Thread: SYSCONFIG

Hi folks,

One of the features I have had the most trouble porting from SDK 3.20 to SDK 5.10 has been OAD for both Simple Peripheral Offchip and MultiRole Offchip. Initially, I thought it was user error - but I have come to the conclusion that the SysConfig program is at fault.

Reference Material from the SDK

Overview

OAD works on both MultiRole and Simple Peripheral project on SDK 3.20. Since SysConfig was not used for this project, I have been migrating to it for SDK 5.10. OAD, while seemingly configured correctly for the BIM project and MR and SP projects, always reports: "OAD failed to open" on the latest SDK.

Diagnosis

I began by configuring the SDK 5.10 SysConfig such that the ti_drivers_config.c and ti_drivers_config.h matched the SDK 3.20 board files as closely as possible.

SDK 3.20 SDK 5.10

#ifndef Board_EXCLUDE_NVS_EXTERNAL_FLASH
#define SPISECTORSIZE    0x1000
#define SPIREGIONSIZE    0x100000     /* total storage size of external flash */
#define VERIFYBUFSIZE    64

const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = {
    {
        .regionBaseOffset = 0,
        .regionSize = SPIREGIONSIZE,
        .sectorSize = SPISECTORSIZE,
        .verifyBuf = verifyBuf,
        .verifyBufSize = VERIFYBUFSIZE,
        .spiHandle = NULL,
        .spiIndex = 0,
        .spiBitRate = 4000000,
        .spiCsnGpioIndex = CC26X2R1_FLASH_SPI0_CS,
        .statusPollDelayUs = 100,
    },
};

static const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = {
    /* CONFIG_NVS_EXTERNAL */
    {
        .regionBaseOffset = 0x0,
        .regionSize = 0x100000,
        .sectorSize = 0x1000,
        .verifyBuf = verifyBuf,
        .verifyBufSize = 64,
        /* NVS opens SPI */
        .spiHandle = NULL,
        /* SPI driver index */
        .spiIndex = SPI_NVS_EXT,
        .spiBitRate = 4000000,
        /* SPI driver manages SPI flash CS */
        .spiCsnGpioIndex = NVSSPI25X_SPI_MANAGES_CS,
        .statusPollDelayUs = 100
    },
};
/* SPI */
#define FLASH_SPI0_CS                           IOID_11
#define CC26X2R1_LAUNCHXL_FLASH_CS_ON           0
#define CC26X2R1_LAUNCHXL_FLASH_CS_OFF          1

/* SPI Board */
#define FLASH_SPI0_MISO                         IOID_10
#define FLASH_SPI0_MOSI                         IOID_12
#define FLASH_SPI0_CLK                          IOID_13

const PIN_Config BoardGpioInitTable[] = {
     FLASH_SPI0_CS               | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN,
     FLASH_SPI0_MISO             | PIN_INPUT_EN | PIN_PULLDOWN,
     FLASH_SPI0_MOSI             | PIN_INPUT_EN | PIN_PULLDOWN,
     FLASH_SPI0_CLK              | PIN_INPUT_EN | PIN_PULLDOWN,
     PIN_TERMINATE
};

Pin can be included as part of the SPI object or added to PIN.
For clarity, I kept the CS pin as part of the SPI object.

const SPICC26X2DMA_HWAttrs spiCC26X2DMAHWAttrs[CC26X2R1_LAUNCHXL_SPICOUNT] = {
    {
        .baseAddr           = SSI0_BASE,
        .intNum             = INT_SSI0_COMB,
        .intPriority        = ~0,
        .swiPriority        = 0,
        .powerMngrId        = PowerCC26XX_PERIPH_SSI0,
        .defaultTxBufValue  = 0xFF,
        .rxChannelBitMask   = 1<<UDMA_CHAN_SSI0_RX,
        .txChannelBitMask   = 1<<UDMA_CHAN_SSI0_TX,
        .mosiPin            = FLASH_SPI0_MOSI,
        .misoPin            = FLASH_SPI0_MISO,
        .clkPin             = FLASH_SPI0_CLK,
        .csnPin             = FLASH_SPI0_CSN,
        .minDmaTransferSize = 10
    }
}
const SPICC26X2DMA_HWAttrs spiCC26X2DMAHWAttrs[CONFIG_SPI_COUNT] = {
    /* SPI_NVS_EXT */
    {
        .baseAddr = SSI0_BASE,
        .intNum = INT_SSI0_COMB,
        .intPriority = (~0),
        .swiPriority = 0,
        .powerMngrId = PowerCC26XX_PERIPH_SSI0,
        .defaultTxBufValue = ~0,
        .rxChannelBitMask = 1<<UDMA_CHAN_SSI0_RX,
        .txChannelBitMask = 1<<UDMA_CHAN_SSI0_TX,
        .minDmaTransferSize = 10,
        .mosiPin = IOID_21,
        .misoPin = IOID_19,
        .clkPin  = IOID_20,
        .csnPin  = PIN_UNASSIGNED
    },
};

I tired many many things until I noticed a strange behavior - or rather the lack of behavior:

SDK 5.10 - GPIO Controlled CS SDK 5.10 - SPI Controlled CS
SDK 5.10 SysConfig Generated: ti_drivers_config.c SDK 5.10 SysConfig Generated: ti_drivers_config.c

For reference, this is the modified board file for SDK 3.20: 

And this depicts the flash specific functions:

The solution for now is to constantly correct this IOID until this bug is fixed. I have been unable to make SysConfig generate a configuration with any other CS Pin IOID which is why I think there is a bug.

Let me know what you think - I have put three days into looking into this bug and only just noticed this behavior.

Best,

Ken

  • Hey Ken,

    You will find in source\ti\drivers\.meta\templates\BoardCC26XX.c.xdt that the Board_* APIs are hard-coded to use IOID_20, IOID_10, IOID_9, and IOID_10.  You can change these values, save the project, and clean/rebuild the project accordingly.  I will submit a ticket to address this issue as these functions should be dynamically changed based on SysConfig settings.

    Regards,
    Ryan

  • Hi Ryan!

    Ah! That makes me feel better. I haven't entirely frozen my SysConfig yet - so this has proven to be a bit of a nuisance to constantly correct between builds. I appreciate that you've forwarded this on - I hope this enhancement is made available soon.

    Best,

    Ken

  • HI Ryan,

    I applied the correction manually and verified it against my working SDK project

    SDK3.20 SDK5.10
    /*
     * SPI Board
     * #define CC26X2R1_LAUNCHXL_SPI0_MOSI             IOID_21
     * #define CC26X2R1_LAUNCHXL_SPI0_MISO             IOID_19
     * #define CC26X2R1_LAUNCHXL_SPI0_CLK              IOID_20
     * #define CC26X2R1_LAUNCHXL_SPI_FLASH_CS          IOID_18
     *
     */
    
    void CC26X2R1_LAUNCHXL_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte)
    {
        uint8_t i;
    
        /* SPI Flash CS */
        PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI_FLASH_CS, 0);
    
        for (i = 0; i < 8; i++) {
            PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI0_CLK, 0);  /* SPI Flash CLK */
    
            /* SPI Flash MOSI */
            PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI0_MOSI, (byte >> (7 - i)) & 0x01);
            PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI0_CLK, 1);  /* SPI Flash CLK */
    
            /*
             * Waste a few cycles to keep the CLK high for at
             * least 45% of the period.
             * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us.
             */
            CPUdelay(8);
        }
    
        PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI0_CLK, 0);  /* CLK */
        PIN_setOutputValue(pinHandle, CC26X2R1_LAUNCHXL_SPI_FLASH_CS, 1);  /* CS */
    
        /*
         * Keep CS high at least 40 us
         * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us
         */
        CPUdelay(700);
    }
    
    /*
     *  ======== CC26X2R1_LAUNCHXL_wakeUpExtFlash ========
     */
    void CC26X2R1_LAUNCHXL_wakeUpExtFlash(void)
    {
        PIN_Config extFlashPinTable[] = {
            /* SPI Flash CS */
            CC26X2R1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED,
            PIN_TERMINATE
        };
        PIN_State extFlashPinState;
        PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable);
    
        /*
         *  To wake up we need to toggle the chip select at
         *  least 20 ns and ten wait at least 35 us.
         */
    
        /* Toggle chip select for ~20ns to wake ext. flash */
        PIN_setOutputValue(extFlashPinHandle, CC26X2R1_LAUNCHXL_SPI_FLASH_CS, 0);
        /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */
        CPUdelay(1);
        PIN_setOutputValue(extFlashPinHandle, CC26X2R1_LAUNCHXL_SPI_FLASH_CS, 1);
        /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */
        CPUdelay(560);
    
        PIN_close(extFlashPinHandle);
    }
    
    /*
     *  ======== CC26X2R1_LAUNCHXL_shutDownExtFlash ========
     */
    void CC26X2R1_LAUNCHXL_shutDownExtFlash(void)
    {
        /*
         *  To be sure we are putting the flash into sleep and not waking it,
         *  we first have to make a wake up call
         */
        CC26X2R1_LAUNCHXL_wakeUpExtFlash();
    
        PIN_Config extFlashPinTable[] = {
            /* SPI Flash CS*/
            CC26X2R1_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED,
            /* SPI Flash CLK */
            CC26X2R1_LAUNCHXL_SPI0_CLK | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED,
            /* SPI Flash MOSI */
            CC26X2R1_LAUNCHXL_SPI0_MOSI | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_INPUT_DIS | PIN_DRVSTR_MED,
            /* SPI Flash MISO */
            CC26X2R1_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN,
            PIN_TERMINATE
        };
        PIN_State extFlashPinState;
        PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable);
    
        uint8_t extFlashShutdown = 0xB9;
    
        CC26X2R1_LAUNCHXL_sendExtFlashByte(extFlashPinHandle, extFlashShutdown);
    
        PIN_close(extFlashPinHandle);
    }
    /*
     *  FLASH FUNCTION CONFIGURATION NOTES:
     *  These functions do not generate with SysConfig and must be manually corrected.
     *  Simple Peripheral:
     *       mosiPin = IOID_21,
     *       misoPin = IOID_19,
     *       clkPin  = IOID_20,
     *       csnPin  = IOID_18
     */
    /*
     *  ======== Board_sendExtFlashByte ========
     */
    void Board_sendExtFlashByte(PIN_Handle pinHandle, uint8_t byte)
    {
        uint8_t i;
    
        /* SPI Flash CS */
        PIN_setOutputValue(pinHandle, IOID_18, 0);
    
        for (i = 0; i < 8; i++) {
            PIN_setOutputValue(pinHandle, IOID_20, 0);  /* SPI Flash CLK */
    
            /* SPI Flash MOSI */
            PIN_setOutputValue(pinHandle, IOID_21, (byte >> (7 - i)) & 0x01);
            PIN_setOutputValue(pinHandle, IOID_20, 1);  /* SPI Flash CLK */
    
            /*
             * Waste a few cycles to keep the CLK high for at
             * least 45% of the period.
             * 3 cycles per loop: 8 loops @ 48 Mhz = 0.5 us.
             */
            CPUdelay(8);
        }
    
        PIN_setOutputValue(pinHandle, IOID_20, 0);  /* CLK */
        PIN_setOutputValue(pinHandle, IOID_18, 1);  /* CS */
    
        /*
         * Keep CS high at least 40 us
         * 3 cycles per loop: 700 loops @ 48 Mhz ~= 44 us
         */
        CPUdelay(700);
    }
    
    /*
     *  ======== Board_wakeUpExtFlash ========
     */
    void Board_wakeUpExtFlash(void)
    {
        PIN_Config extFlashPinTable[] = {
            /* SPI Flash CS */
            IOID_18 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL |
                    PIN_INPUT_DIS | PIN_DRVSTR_MED,
            PIN_TERMINATE
        };
        PIN_State extFlashPinState;
        PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable);
    
        /*
         *  To wake up we need to toggle the chip select at
         *  least 20 ns and ten wait at least 35 us.
         */
    
        /* Toggle chip select for ~20ns to wake ext. flash */
        PIN_setOutputValue(extFlashPinHandle, IOID_18, 0);
        /* 3 cycles per loop: 1 loop @ 48 Mhz ~= 62 ns */
        CPUdelay(1);
        PIN_setOutputValue(extFlashPinHandle, IOID_18, 1);
        /* 3 cycles per loop: 560 loops @ 48 Mhz ~= 35 us */
        CPUdelay(560);
    
        PIN_close(extFlashPinHandle);
    }
    
    /*
     *  ======== Board_shutDownExtFlash ========
     */
    void Board_shutDownExtFlash(void)
    {
        /*
         *  To be sure we are putting the flash into sleep and not waking it,
         *  we first have to make a wake up call
         */
        Board_wakeUpExtFlash();
    
        PIN_Config extFlashPinTable[] = {
            /* SPI Flash CS*/
            IOID_18 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL |
                    PIN_INPUT_DIS | PIN_DRVSTR_MED,
            /* SPI Flash CLK */
            IOID_20 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL |
                    PIN_INPUT_DIS | PIN_DRVSTR_MED,
            /* SPI Flash MOSI */
            IOID_21 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL |
                    PIN_INPUT_DIS | PIN_DRVSTR_MED,
            /* SPI Flash MISO */
            IOID_19 | PIN_INPUT_EN | PIN_PULLDOWN,
            PIN_TERMINATE
        };
        PIN_State extFlashPinState;
        PIN_Handle extFlashPinHandle = PIN_open(&extFlashPinState, extFlashPinTable);
    
        uint8_t extFlashShutdown = 0xB9;
    
        Board_sendExtFlashByte(extFlashPinHandle, extFlashShutdown);
    
        PIN_close(extFlashPinHandle);
    }

    I also checked the Board/bsp.h file from the BIM project:

    SDK3.20 SDK5.10
    // Board external flash defines
    #define BSP_SPI_MOSI            IOID_21
    #define BSP_SPI_MISO            IOID_19
    #define BSP_SPI_CLK_FLASH       IOID_20
    #define BSP_IOID_FLASH_CS       IOID_18

    // Board external flash defines
    #define BSP_SPI_MOSI            IOID_21
    #define BSP_SPI_MISO            IOID_19
    #define BSP_SPI_CLK_FLASH       IOID_20
    #define BSP_IOID_FLASH_CS       IOID_18

    I still cannot get OAD to open correctly. How can I diagnose this problem?

    Best,

    Ken

  • Hey Ken,

    What information can you gather from the CCS debugger?  Have you ever monitored the SPI lines with an oscilloscope or logic analyzer?

    Regards,
    Ryan

  • Hi Ryan,

    I don’t have much besides the “OAD failed to open” warning - I might consider putting display_printf flags in the PIN functions used for the SPI flash commands. If I recall, the PIN commands return success or fail and I can use get pin config to compare before and after pin-state modifying code.

    Alas - I do not have test points on my PCB for the SPI flash.  However, I am willing to desolder an IC and buy a breakout board to sniff the SPI channel. I only have a two channel SPI decoder - three or even four would have been ideal.

    Where do you think I should start debugging OAD? The broad flash functions might tell me if the config is off. But maybe there are OAD functions I am not aware of that are more practical to study.

    Best,

    Ken

  • I am not familiar with the "OAD failed to open" warning, if you could find where this is called inside the project then you could debug to view the call stack and possibly work your way back to the source from there.  Based on your description this issue could originate from the BIM project as it is the first to access the SPI peripheral in order to verify external flash images.  I assume you've upgraded the off-chip BIM project to v5.10 as well and changed the bsp.h file to reflect your pin dependencies?

    Regards,
    Ryan

  • Hi Ryan,

    The "OAD failed to open" is the default error posted in Simple Peripheral/simple_peripheral_oad_off_chip.c:

    static void SimplePeripheral_init(void){
      ...
      // Open the OAD module and add the OAD service to the application
      if(OAD_SUCCESS != OAD_open(OAD_DEFAULT_INACTIVITY_TIME))
      {
          Display_printf(dispHost, 0, 0, "OAD failed to open");
      }
      else
      {
        Display_printf(dispHost, 0, 0, "OAD opened");
        // Register the OAD callback with the application
        OAD_register(&SimplePeripheral_oadCBs);
      }
      ...
    }

    To the best of my knowledge, I only need to modify:

    • BSP.h file in the BIM project (copied from the SDK to a project-local directory) and customized it for my PCB as described in post 1.
    • SysConfig should handle the SPI configuration for the Simple Peripheral Project via NVS/SPI also described in post 1.

    Since my last post, I have received a SPI flash breakout PCB and mounted my SOP-8 flash package to it (chip worked in SDK3.20). When stepping through bim_main() and the external flash functions I see that the SPI CS and CLK pin states are changing. I connected my SDS 1202X-E oscilloscope to the breakout to sniff the communication.

    This depicts SCK (Channel 2, Purple) and CS (Channel 1, Yellow) during the startup.

    In greater time-scale resolution:

    Since my oscilloscope is limited to 2 Channels, I attempted to observe the MOSI (Channel 2, Purple) and MISO (Channel 1, Yellow) terminals:

    Once more in greater timescale:

    I am definitely not seeing the expected SPI output, so it is likely that the OAD error is indicating that something is incorrect. To further diagnose this issue, I referred to the oad.h source file for possible return messages for oad_open(...):

    // simple_peripheral_project/OAD/oad.h
    /*!
     * @defgroup OAD_STATUS_CODES OAD return status codes
     * @{
     */
    #define OAD_SUCCESS                         0   //!< OAD succeeded
    #define OAD_CRC_ERR                         1   //!< Downloaded image CRC doesn't match
    #define OAD_FLASH_ERR                       2   //!< Flash function failure (int, ext)
    #define OAD_BUFFER_OFL                      3   //!< Block Number doesn't match requested.
    #define OAD_ALREADY_STARTED                 4   //!< OAD is already is progress
    #define OAD_NOT_STARTED                     5   //!< OAD has not yet started
    #define OAD_DL_NOT_COMPLETE                 6   //!< An OAD is ongoing
    #define OAD_NO_RESOURCES                    7   //!< If memory allocation fails
    #define OAD_IMAGE_TOO_BIG                   8   //!< Candidate image is too big
    #define OAD_INCOMPATIBLE_IMAGE              9   //!< Image signing failure, boundary mismatch
    #define OAD_INVALID_FILE                    10  //!< If Invalid image ID received
    #define OAD_INCOMPATIBLE_FILE               11  //!< BIM or FW mismatch
    #define OAD_AUTH_FAIL                       12  //!< Authorization failed
    #define OAD_EXT_NOT_SUPPORTED               13  //!< Ctrl point command not supported
    #define OAD_DL_COMPLETE                     14  //!< OAD image payload download complete
    #define OAD_CCCD_NOT_ENABLED                15  //!< CCCD is not enabled, notif can't be sent
    #define OAD_IMG_ID_TIMEOUT                  16  //!< Image identify timed out, too many failures
    
    /** @} End OAD_STATUS_CODES */

    I modified the code:

    static void SimplePeripheral_init(void){
      ...
      // Open the OAD module and add the OAD service to the application
      uint8_t OAD_Debugging;
      OAD_Debugging = OAD_open(OAD_DEFAULT_INACTIVITY_TIME);
      if(OAD_SUCCESS != OAD_Debugging)
      {
          Display_printf(dispHost, 0, 0, "OAD failed to open: Error %d",OAD_Debugging);
      }
      else
      {
        Display_printf(dispHost, 0, 0, "OAD opened");
        // Register the OAD callback with the application
        OAD_register(&SimplePeripheral_oadCBs);
      }
      ...
    }

    The error now returns:

    SBP Off-chip OAD v0201
    OAD failed to open: Error 2

    I've traced this error down to this writeFlash function wherein the flashStat variable is never updated to FLASH_SUCCESS:

    But the method that called it doesn't return FLASH_FAILURE, instead an else case from if(extFlashErase(dstAddr, imgLen)) assigns OAD_FLASH_ERROR which is returned to OAD_Open.

    /*********************************************************************
     * @fn      oadCreateFactoryImageBackup
     *
     * @brief   This function creates factory image backup of current running image
     *
     * @param   imgStartPage - image start address on onchip flash
     * @param   imgLen       - image length
     * @param   dstAddr      - start address external flash.
     *
     * @return  OAD_SUCCESS on successful erasure else
     *          OAD_FLASH_ERR
     */
    uint8_t oadCreateFactoryImageBackup(void)
    {
        uint8_t rtn = OAD_SUCCESS;
        uint8_t status = 0;
        uint32_t dstAddr = oadFindFactImgAddr();
        uint32_t dstAddrStart = dstAddr;
        uint32_t imgStart = _imgHdr.imgPayload.startAddr;
        uint32_t imgLen = _imgHdr.fixedHdr.imgEndAddr - (uint32_t)&_imgHdr;
    
        /* initialize external flash driver */
        if(flash_open() != 0)
        {
            // First erase factory image metadata page
            if(eraseFlashPg(EXT_FLASH_PAGE(EFL_ADDR_META)) != FLASH_SUCCESS)
            {
                return OAD_FLASH_ERR;
            }
    
            /* Erase - external portion to be written*/
            status = oadEraseExtFlashPages(EXT_FLASH_PAGE(dstAddr),
                    (_imgHdr.fixedHdr.imgEndAddr - _imgHdr.imgPayload.startAddr -1),
                     EFL_PAGE_SIZE);
            if(status == OAD_SUCCESS)
            {
                /* COPY - image from internal to external */
              if(writeFlash(dstAddr, (uint8_t *)(imgStart), imgLen) == FLASH_SUCCESS)
               {
                    ...
                }
           else //  if(extFlashErase(dstAddr, imgLen))
           {
               rtn = OAD_FLASH_ERR;
           } //  end of if(extFlashErase(dstAddr, imgLen))
    
            /* close driver */
            flash_close();
    
         } // end of flash_Open
    
        return(rtn);
    }

    Like you, I am very out of my debugging skill range for this particular problem. I am still convinced that this is a SysConfig problem - so I will keep consulting my working SDK 3.20 files.

    Any and all ideas for how to keep troubleshooting this are welcome!

    Ken

  • To make the previous post more clear, I retrieved some flowcharts and marked what I am investigating.

    BIM Startup Sequence


    The following flowchart from the BLE5-Stack User's Guide depicts how the BIM (No-RTOS) starts, identifies a valid boot image, then executes it. Because the BIM is only customized at the bsp.h file for PCB/Board specific flash needs, this operation marked in purple should successfully copy the flash image from External Flash to Internal Flash. I will check this later today.


    Application Startup

    The following graphic depicts the OAD operations in the Application image including startup and processing. Marked in purple is the operation that fails in the Application image during the startup procedure. The error appears to indicate that the External SPI flash is not working correctly. I have traced the assignment of the error status to the procedure described as: /* COPY - image from internal to external */ in the oadCreateFactoryImageBackup(...) function called during OAD_open().

  • Hi Ken,

    Please clarify whether any eraseFlashPg/oadEraseExtFlashPages/writeFlash functions complete successfully inside oadCreateFactoryImageBackup.  This could help determine whether this issue resides within the SPI peripheral or external flash memory setup.  Are you using a MX25R8035F as with the LaunchPads?  You may with to review the external flash and OAD file changes between v3.20 and v5.10 for any noticeable differences.  Please further debug the BIM project when you get a chance, as this will also help determine where the root issue lies.

    Regards,
    Ryan

  • I am using an MX25R8035FM1L0 so the configuration should be identical except in IO assignment. Besides the bug noted in Post 1, there are no discrepancies I can find - though a 1:1 comparison is hard because SysConfig was not used in SDK 3.20. 

    I enabled debug mode on the BIM project, concatenated it with my project image, and then watched the Launchpad LEDs. The BIM project is working in so far as it can indicate to me that no image was found in the external or internal flash. Bim_checkImages() is the second to last command in main and the debugger gets trapped in the while(1); and progresses no further. 

    #else /* ifdef DEBUG */
    
        int8_t retVal = 0;
    
        /* First try finding a valid image on off-chip flash */
        if( !(retVal = checkImagesExtFlash() ) )
        {
            /* Could not find valid image on off-chip Flash.
             * Try finding application image on on-chip flash and jump to it */
           checkImagesIntFlash(0);
        }
    
        /* BIM is not able find any valid application, either on off-chip
         * or on-chip flash. Try to revert to Factory image */
        Bim_revertFactoryImage();
    
        /* No Valid image is found on off-chip or on-chip flash */
        if( retVal == -1)
        {
            /* Light RED LED to indicate an Error */
            powerUpGpio();
            lightRedLed();
    
            /* spin in while loop so that context is preserved for debug */
            while(1);
        }
    
    #endif

    I concatenated BIM to my project image and then loaded the production binary onto the launchpad. The GPIO LEDs are not used by any Simple Peripheral processes in the project, so the registers should not change after the BIM modifies them. The project loads and I can see the Simple Peripheral project in the Texas Instruments iOS "Starter" App. Onboard LED is solid green. I connect to the project with Sensor View to access the Enhanced OAD UI which I have used previously in SDK 3.20 to load OAD firmware. The project asks me to pair my phone which I confirmand the phone and SP are paired. bonded, and connected. However, the OAD interface is greyed out.

    So, I returned to stepping through the OAD_open process:

    uint8_t oadCreateFactoryImageBackup(void)
    {
        uint8_t rtn = OAD_SUCCESS;
        uint8_t status = 0;
        uint32_t dstAddr = oadFindFactImgAddr();
        uint32_t dstAddrStart = dstAddr;
        uint32_t imgStart = _imgHdr.imgPayload.startAddr;
        uint32_t imgLen = _imgHdr.fixedHdr.imgEndAddr - (uint32_t)&_imgHdr;
    
        /* initialize external flash driver */
        // SUCCESS! No problems.
        if(flash_open() != 0)
        {
            // First erase factory image metadata page
            // SUCCESS! No problems.
            if(eraseFlashPg(EXT_FLASH_PAGE(EFL_ADDR_META)) != FLASH_SUCCESS)
            {
                return OAD_FLASH_ERR;
            }
    
            /* Erase - external portion to be written*/
            // SUCCESS! No problems.
            status = oadEraseExtFlashPages(EXT_FLASH_PAGE(dstAddr),
                    (_imgHdr.fixedHdr.imgEndAddr - _imgHdr.imgPayload.startAddr -1),
                     EFL_PAGE_SIZE);
            if(status == OAD_SUCCESS)
            {
                /* COPY - image from internal to external */
                // FAILURE Early Return resulting in OAD_FLASH_ERROR
              if(writeFlash(dstAddr, (uint8_t *)(imgStart), imgLen) == FLASH_SUCCESS)
               {
                   
                   // Excised code... to be reviewed later
    
                   /* WRITE METADATA */
                   /* Erase - external portion to be written*/
                   // UNTESTED! Never seem to run this code...
                   //if(eraseFlashPg(EXT_FLASH_PAGE(EFL_ADDR_META)) == FLASH_SUCCESS)
                   //{
                    if(writeFlash(EFL_ADDR_META, (uint8_t *)&imgHdr, OAD_IMG_HDR_LEN + 8) != FLASH_SUCCESS)
                    {
                       rtn = OAD_FLASH_ERR;
                    }
                } // end of if(writeFlash((dstAddr+4,  (uint8_t *)(imgStart +4), (imgLen -4)) == FLASH_SUCCESS)
                else
                {
                    rtn = OAD_FLASH_ERR;
                }
           }
                // if(extFlashErase(dstAddr, imgLen))
           else // UNTESTED! Never seem to run this code...
           {
               rtn = OAD_FLASH_ERR;
           } //  end of if(extFlashErase(dstAddr, imgLen))
    
            /* close driver */
            flash_close();
    
         } // end of flash_Open
    
        return(rtn);
    }
    

    TLDR:

    Called... Returned...
    eraseFlashPg FLASH_SUCCESS
    oadEraseExtFlashPages OAD_SUCCESS
    writeFlash FLASH_FAILURE

    Specific Method resulting in Error:

    if(writeFlash(dstAddr, (uint8_t *)(imgStart), imgLen) == FLASH_SUCCESS)){
        //Error Occurs
    }

    writeFlash calls NVS_write which consistently returns -1 as per TI-RTOS Drivers NVS.h.

    This error corresponds with NVS_EFAIL which has no description in the TI-RTOS Drivers.

    Stepping through the code, the error is actually when source array and the read array are compared for bad which returns true indicating a failed comparison that ultimately returns NVS_STATUS_INV_WRITE (-7) by doWriteVerify in NVSSPI25X.c

        else if (flags & NVS_WRITE_PRE_VERIFY) {
            if ((hwAttrs->verifyBuf == NULL) || (hwAttrs->verifyBufSize == 0)) {
                SemaphoreP_post(writeSem);
                return (NVS_STATUS_ERROR);
            }
    
            retval = doWriteVerify(handle, offset, buffer, bufferSize,
                         hwAttrs->verifyBuf, hwAttrs->verifyBufSize, true);
    
            if (retval != NVS_STATUS_SUCCESS) {
                SemaphoreP_post(writeSem);
                return (retval);
            }

    The doWriteVerify function is reproduced below:

    /*
     *  ======== doWriteVerify =======
     */
    static int_fast16_t doWriteVerify(NVS_Handle handle, size_t offset, void *src,
               size_t srcBufSize, void *dst, size_t dstBufSize, bool preFlag)
    {
        size_t i, j;
        uint8_t *srcBuf, *dstBuf;
        bool bad;
        int_fast16_t retval;
    
        srcBuf = src;
        dstBuf = dst;
    
        j = dstBufSize;
    
        for (i = 0; i < srcBufSize; i++, j++) {
            if (j == dstBufSize) {
                retval = doRead(handle, offset + i, dstBuf, j);
                if (retval != NVS_STATUS_SUCCESS) {
                    break;
                }
                j = 0;
            }
            if (preFlag) {
                bad = srcBuf[i] != (srcBuf[i] & dstBuf[j]);
            }
            else {
                bad = srcBuf[i] != dstBuf[j];
            }
            if (bad) return (NVS_STATUS_INV_WRITE);
        }
        return (NVS_STATUS_SUCCESS);
    }

    This could be one of two things as far as I can tell:

    1. Defective Flash ICs (Simultaneous failure of multiple boards seems unlikely).
    2. Incorrect System Configuration (more likely, but I haven't a clue what could be wrong).

    Thoughts? I have ordered new flash ICs to test (1) but I am at a loss for next steps.

  • Thank you for the detailed description Ken.  Are you able to sky-wire a MX25R8035F to your device or connect a MX25R8035FM1L0 to a LaunchPad to determine the root source of the issue?  Based on the status of function success/fail, the SPI module appears to be working properly.  But the flash memory files operation and/or setup could be at fault.  I would also expect the configuration of the two MX25R8035F devices to be the same but I do not know enough about these devices to be certain.  Perhaps the oscilloscope can help at this phase of investigation?

    Regards,
    Ryan

  • I am definitely leaning towards flash configuration errors as well.  I cannot sky-wire a MX25R8035F to the PCB due to the total absence of test points, but I do have a MX25R8035FM1L0 connected directly to a Launchpad.

    I have tried the oscilloscope before, but I wasn't really sure what I was looking for. I know that the CS and CLK pins seem to be working. Logically, I could try the SPI decoder by monitoring:

    • CLK and MOSI 
    • CLK and MISO

    I don't know what the MOSI and MISO signals/decoded data should look like to confirm operation. At most, I can confirm CC26X2R1 writing via MOSI and reading via MISO. I'll let you know what I see.

    Is there a well defined procedure for configuring SPI NVS Flash?

  • I looked at MOSI and MISO during normal boot with the Debug and Unsecured BIM with the concatenated application image. My serial decoder didn't seem to want to do anything to the data - but just looking at these waveforms tells me that the BIM is indeed configured correctly and that the Application appears to be reading from/writing to the SPI flash.

    While probing this, I realized that DIO_7 (Green LED) is Pin 12 and is assigned to UART. The fact that the LED is lit in my previous post is totally irrelevant.

    SPI MOSI (Ch2, Purple) SPI SCK (Ch1, Yellow)

    Overview of the Waveform at Boot with Points of Interest

    Point of Interest #1 Enlarged 

    Point of Interest #2 Enlarged 

    Point of Interest #3 Enlarged 

    Point of Interest #4 Enlarged 

    Point of Interest #5 Enlarged 

    Point of Interest #6 Enlarged 

    SPI MISO (Ch2, Purple) SPI SCK (Ch1, Yellow)

    The waveform is very dense. The MISO channel has continuous activity until reset.

    Based on the arguments of the method that calls the verification function, I suspect that these values are defined incorrectly.

    uint8_t oadCreateFactoryImageBackup(void)
    {
        ...
        uint32_t dstAddr = oadFindFactImgAddr();
        uint32_t dstAddrStart = dstAddr;
        uint32_t imgStart = _imgHdr.imgPayload.startAddr;
        uint32_t imgLen = _imgHdr.fixedHdr.imgEndAddr - (uint32_t)&_imgHdr;
        ...
    }


    I believe these values are defined in oad_image_header_app.c. Here is the working SDK 3.20 and non-working SDK 5.10. 
    There are no significant differences - additions were made to provide better support for clang and IAR.

    SDK 3.20
    oad_image_header_app.c/_imgHdr

    SDK 5.10
    oad_image_header_app.c/_imgHdr

    /******************************************************************************
    
     @file  oad_image_header_app.c
    
     @brief OAD image header definition file.
    
     Group: WCS, BTS
     Target Device: cc13x2_26x2
    
     ******************************************************************************
     
     Copyright (c) 2014-2019, 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.
    
     ******************************************************************************
     
     
     *****************************************************************************/
    
    /*******************************************************************************
     * INCLUDES
     */
    
    #include <stddef.h>
    #include <common/cc26xx/oad/oad_image_header.h>
    
    /*******************************************************************************
     * EXTERNS
     */
    
    /*******************************************************************************
     * PROTOTYPES
     */
    
    /*******************************************************************************
     * MACROS
     */
    
    /*******************************************************************************
     * CONSTANTS
     */
    
    #define VECTOR_TB_SIZE       0x40 //!< Interrupt vector table entry size */
    #ifndef STACK_LIBRARY
      #define BOUNDARY_SEG_LEN   0x18 //!< Length of the boundary segment */
    #endif
    
    #define SOFTWARE_VER            {'0', '0', '0', '1'}
    
    /*******************************************************************************
     * TYPEDEFS
     */
    
    /*******************************************************************************
     * LOCAL VARIABLES
     */
    /*
     * NV Page Setting:
     * This define is used ensure the stack is built with a compatible NV setting
     * Note: this restriction does not apply to the stack library configuration
     * for off-chip OAD
     */
    
    extern const uint32_t  RAM_END;
    
    #if defined HAL_IMAGE_A
    extern const uint8_t  ENTRY_END;
    extern const uint8_t  ENTRY_START;
    #endif
    
    #ifdef __IAR_SYSTEMS_ICC__
    #pragma section = "ROSTK"
    #pragma section = "RWDATA"
    #pragma section = "ENTRY_FLASH"
    #pragma section = ".intvec"
    #endif
    
    #ifdef __TI_COMPILER_VERSION__
    /* This symbol is create by the linker file */
    extern uint8_t ramStartHere;
    extern uint8_t prgEntryAddr;
    extern uint8_t ramStartHere;
    extern uint8_t flashEndAddr;
    extern uint32_t heapEnd;
    extern uint32_t FLASH_END;
    #endif /* __TI_COMPILER_VERSION__ */
    
    #ifdef __TI_COMPILER_VERSION__
    #pragma DATA_SECTION(_imgHdr, ".image_header")
    #pragma RETAIN(_imgHdr)
    const imgHdr_t _imgHdr =
    {
      {
        .imgID = OAD_IMG_ID_VAL,
        .crc32 = DEFAULT_CRC,
        .bimVer = BIM_VER,
        .metaVer = META_VER,                   //!< Metadata version */
        .techType = OAD_WIRELESS_TECH_BLE,     //!< Wireless protocol type BLE/TI-MAC/ZIGBEE etc. */
        .imgCpStat = DEFAULT_STATE,            //!< Image copy status bytes */
        .crcStat = DEFAULT_STATE,              //!< CRC status */
        .imgNo = 0x1,                          //!< Image number of 'image type' */
        .imgVld = 0xFFFFFFFF,                  //!< In indicates if the current image in valid 0xff - valid, 0x00 invalid image */
        .len = INVALID_LEN,                     //!< Image length in bytes. */
        .softVer = SOFTWARE_VER,               //!< Software version of the image */
        .hdrLen = offsetof(imgHdr_t, fixedHdr.rfu) + sizeof(((imgHdr_t){0}).fixedHdr.rfu),   //!< Total length of the image header */
        .rfu = 0xFFFF,                         //!< reserved bytes */
        .prgEntry = (uint32_t)&prgEntryAddr,
        .imgEndAddr = (uint32_t)&flashEndAddr,
    #if (!defined(STACK_LIBRARY) && (defined(SPLIT_APP_STACK_IMAGE)))
        .imgType = OAD_IMG_TYPE_APP,
    #else
      #if defined HAL_IMAGE_A
        .imgType =  OAD_IMG_TYPE_PERSISTENT_APP,
      #else  
        .imgType = OAD_IMG_TYPE_APPSTACKLIB,
      #endif   
    #endif
      },
    
    #if (defined(SECURITY))
      {
        .segTypeSecure = IMG_SECURITY_SEG_ID,
        .wirelessTech = OAD_WIRELESS_TECH_BLE,
        .verifStat = DEFAULT_STATE,
        .secSegLen = 0x55,
        .secVer = SECURITY_VER,                     //!< Image payload and length */
        .secTimestamp = 0x0,                         //!< Security timestamp */
        .secSignerInfo = 0x0,
      },
    #endif
    
    #if (!defined(STACK_LIBRARY) && (defined(SPLIT_APP_STACK_IMAGE)))
      .segTypeBd = IMG_BOUNDARY_SEG_ID,
      .wirelessTech1 = OAD_WIRELESS_TECH_BLE,
      .rfu = DEFAULT_STATE,
      .boundarySegLen = BOUNDARY_SEG_LEN,
      .ram0StartAddr = (uint32_t)&ramStartHere,  //!< RAM entry start address */
    
      #if defined HAL_IMAGE_A                    //! Persistent image */
        .imgType =  OAD_IMG_TYPE_PERSISTENT_APP, //!< Persistent image Type */
        .stackStartAddr = INVALID_ADDR,          //!< Stack start address */
        .stackEntryAddr = INVALID_ADDR,
      #else /* User application image */
        .imgType =  OAD_IMG_TYPE_APP,            //!< Application image Type */
        .stackEntryAddr = ICALL_STACK0_ADDR,
        .stackStartAddr = ICALL_STACK0_START,
      #endif /* defined HAL_IMAGE_A */
        .imgType = OAD_IMG_TYPE_APP,
    #endif /* STACK_LIBRARY */
    
      // Image payload segment initialization
       {
         .segTypeImg = IMG_PAYLOAD_SEG_ID,
         .wirelessTech = OAD_WIRELESS_TECH_BLE,
         .rfu = DEFAULT_STATE,
         .startAddr = (uint32_t)&(_imgHdr.fixedHdr.imgID),
       }
     };
    #elif  defined(__IAR_SYSTEMS_ICC__)
    #pragma location=".img_hdr"
    const imgHdr_t _imgHdr @ ".img_hdr" =
    {
      {
        .imgID = OAD_IMG_ID_VAL,
        .crc32 = DEFAULT_CRC,
        .bimVer = BIM_VER,
        .metaVer = META_VER,                   //!< Metadata version */
        .techType = OAD_WIRELESS_TECH_BLE,     //!< Wireless protocol type BLE/TI-MAC/ZIGBEE etc. */
        .imgCpStat = DEFAULT_STATE,            //!< Image copy status bytes */
        .crcStat = DEFAULT_STATE,              //!< CRC status */
        .imgNo = 0x1,                          //!< Image number of 'image type' */
        .imgVld = 0xFFFFFFFF,                  //!< In indicates if the current image in valid 0xff - valid, 0x00 invalid image */
        .len = INVALID_LEN,                    //!< Image length in bytes. */
        .softVer = SOFTWARE_VER,               //!< Software version of the image */
        .hdrLen = offsetof(imgHdr_t, fixedHdr.rfu) + sizeof(((imgHdr_t){0}).fixedHdr.rfu),   //!< Total length of the image header */
        .rfu = 0xFFFF,                         //!< reserved bytes */
        .prgEntry = (uint32_t)(__section_begin(".intvec")), //!< Program entry address */
        .imgEndAddr = (uint32_t)(__section_end("ROSTK")),
    #if (!defined(STACK_LIBRARY) && (defined(SPLIT_APP_STACK_IMAGE)))
        .imgType = OAD_IMG_TYPE_APP,
    #else
      #if defined HAL_IMAGE_A
        .imgType =  OAD_IMG_TYPE_PERSISTENT_APP,
      #else  
        .imgType = OAD_IMG_TYPE_APPSTACKLIB,
      #endif   
    #endif
      },
    
    #if defined(SECURITY)
      {
        .segTypeSecure = IMG_SECURITY_SEG_ID,
        .wirelessTech = OAD_WIRELESS_TECH_BLE,
        .verifStat = DEFAULT_STATE,
        .secSegLen = 0x55,
        .secVer = SECURITY_VER,                                       //!< Image payload and length */
        .secTimestamp = 0x0,                              //!< Security timestamp */
        .secSignerInfo = 0x0,
      },
    #endif /* if defined(SECURITY) */
    
    #if (!defined(STACK_LIBRARY) && (defined(SPLIT_APP_STACK_IMAGE)))
      {
        .segTypeBd = IMG_BOUNDARY_SEG_ID,
        .wirelessTech = OAD_WIRELESS_TECH_BLE,
        .rfu = DEFAULT_STATE,
        .boundarySegLen = BOUNDARY_SEG_LEN,
      #if defined HAL_IMAGE_A                      //!< Persistent image */
        .imgType =  OAD_IMG_TYPE_PERSISTENT_APP,   //!< Persistent image Type */
        .stackStartAddr = INVALID_ADDR,            //!< Stack start adddress */
        .stackEntryAddr = INVALID_ADDR,
        .prgEntry = (uint32_t)&ENTRY_START,
      #else /* User application image */
        .imgType =  OAD_IMG_TYPE_APP,              //!< Application image Type */
        .stackEntryAddr = ICALL_STACK0_ADDR,
        .stackStartAddr = ICALL_STACK0_START,
      #endif /* defined HAL_IMAGE_A */
    
      .ram0StartAddr = (uint32)(__section_begin("RWDATA")),  //!< RAM entry start address */
      .imgType = OAD_IMG_TYPE_APP,
      },
    
    #endif /* (!defined(STACK_LIBRARY) && (defined(SPLIT_APP_STACK_IMAGE))) */
      // Image payload segment initialization
      {
        .segTypeImg = IMG_PAYLOAD_SEG_ID,
        .wirelessTech = OAD_WIRELESS_TECH_BLE,
        .rfu = DEFAULT_STATE,                                         //!< Image payload and length */
        .startAddr = (uint32_t)&(_imgHdr.fixedHdr.imgID),
      }
     };
    #endif /*  defined(__IAR_SYSTEMS_ICC__) */
    
    /******************************************************************************
    
     @file  oad_image_header_app.c
    
     @brief OAD image header definition file.
    
     Group: WCS, BTS
     Target Device: cc13x2_26x2
    
     ******************************************************************************
     
     Copyright (c) 2014-2021, 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.
    
     ******************************************************************************
     
     
     *****************************************************************************/
    
    /*******************************************************************************
     * INCLUDES
     */
    
    #include <stddef.h>
    #include <common/cc26xx/oad/oad_image_header.h>
    
    /*******************************************************************************
     * EXTERNS
     */
    
    /*******************************************************************************
     * PROTOTYPES
     */
    
    /*******************************************************************************
     * MACROS
     */
    
    /*******************************************************************************
     * CONSTANTS
     */
    
    #define VECTOR_TB_SIZE       0x40 //!< Interrupt vector table entry size */
    #ifndef STACK_LIBRARY
      #define BOUNDARY_SEG_LEN   0x18 //!< Length of the boundary segment */
    #endif
    
    #define SOFTWARE_VER            {'0', '0', '0', '1'}
    
    /*******************************************************************************
     * TYPEDEFS
     */
    
    /*******************************************************************************
     * LOCAL VARIABLES
     */
    /*
     * NV Page Setting:
     * This define is used ensure the stack is built with a compatible NV setting
     * Note: this restriction does not apply to the stack library configuration
     * for off-chip OAD
     */
    
    extern const uint32_t  RAM_END;
    
    #if defined HAL_IMAGE_A
    extern const uint8_t  ENTRY_END;
    extern const uint8_t  ENTRY_START;
    #endif
    
    #ifdef __IAR_SYSTEMS_ICC__
    #pragma section = "ROSTK"
    #pragma section = "RWDATA"
    #pragma section = "ENTRY_FLASH"
    #pragma section = ".intvec"
    #endif
    
    #ifndef __IAR_SYSTEMS_ICC__
    /* This symbol is create by the linker file */
    extern uint8_t ramStartHere;
    extern uint8_t prgEntryAddr;
    extern uint8_t ramStartHere;
    extern uint8_t flashEndAddr;
    extern uint32_t heapEnd;
    extern uint32_t FLASH_END;
    #endif /* ! __IAR_SYSTEMS_ICC__ */
    
    #ifdef __TI_COMPILER_VERSION__
    #pragma DATA_SECTION(_imgHdr, ".image_header")
    #pragma RETAIN(_imgHdr)
    const imgHdr_t _imgHdr =
    {
      {
        .imgID = OAD_IMG_ID_VAL,
        .crc32 = DEFAULT_CRC,
        .bimVer = BIM_VER,
        .metaVer = META_VER,                   //!< Metadata version */
        .techType = OAD_WIRELESS_TECH_BLE,     //!< Wireless protocol type BLE/TI-MAC/ZIGBEE etc. */
        .imgCpStat = DEFAULT_STATE,            //!< Image copy status bytes */
        .crcStat = DEFAULT_STATE,              //!< CRC status */
        .imgNo = 0x1,                          //!< Image number of 'image type' */
        .imgVld = 0xFFFFFFFF,                  //!< In indicates if the current image in valid 0xff - valid, 0x00 invalid image */
        .len = INVALID_LEN,                     //!< Image length in bytes. */
        .softVer = SOFTWARE_VER,               //!< Software version of the image */
        .hdrLen = offsetof(imgHdr_t, fixedHdr.rfu) + sizeof(((imgHdr_t){0}).fixedHdr.rfu),   //!< Total length of the image header */
        .rfu = 0xFFFF,                         //!< reserved bytes */
        .prgEntry = (uint32_t)&prgEntryAddr,
        .imgEndAddr = (uint32_t)&flashEndAddr,
    #if (!defined(STACK_LIBRARY) && (defined(SPLIT_APP_STACK_IMAGE)))
        .imgType = OAD_IMG_TYPE_APP,
    #else
      #if defined HAL_IMAGE_A
        .imgType =  OAD_IMG_TYPE_PERSISTENT_APP,
      #else  
        .imgType = OAD_IMG_TYPE_APPSTACKLIB,
      #endif   
    #endif
      },
    
    #if (defined(SECURITY))
      {
        .segTypeSecure = IMG_SECURITY_SEG_ID,
        .wirelessTech = OAD_WIRELESS_TECH_BLE,
        .verifStat = DEFAULT_STATE,
        .secSegLen = 0x55,
        .secVer = SECURITY_VER,                     //!< Image payload and length */
        .secTimestamp = 0x0,                         //!< Security timestamp */
        .secSignerInfo = 0x0,
      },
    #endif
    
    #if (!defined(STACK_LIBRARY) && (defined(SPLIT_APP_STACK_IMAGE)))
      .segTypeBd = IMG_BOUNDARY_SEG_ID,
      .wirelessTech1 = OAD_WIRELESS_TECH_BLE,
      .rfu = DEFAULT_STATE,
      .boundarySegLen = BOUNDARY_SEG_LEN,
      .ram0StartAddr = (uint32_t)&ramStartHere,  //!< RAM entry start address */
    
      #if defined HAL_IMAGE_A                    //! Persistent image */
        .imgType =  OAD_IMG_TYPE_PERSISTENT_APP, //!< Persistent image Type */
        .stackStartAddr = INVALID_ADDR,          //!< Stack start address */
        .stackEntryAddr = INVALID_ADDR,
      #else /* User application image */
        .imgType =  OAD_IMG_TYPE_APP,            //!< Application image Type */
        .stackEntryAddr = ICALL_STACK0_ADDR,
        .stackStartAddr = ICALL_STACK0_START,
      #endif /* defined HAL_IMAGE_A */
        .imgType = OAD_IMG_TYPE_APP,
    #endif /* STACK_LIBRARY */
    
      // Image payload segment initialization
       {
         .segTypeImg = IMG_PAYLOAD_SEG_ID,
         .wirelessTech = OAD_WIRELESS_TECH_BLE,
         .rfu = DEFAULT_STATE,
         .startAddr = (uint32_t)&(_imgHdr.fixedHdr.imgID),
       }
     };
    #elif  defined(__IAR_SYSTEMS_ICC__)
    #pragma location=".img_hdr"
    const imgHdr_t _imgHdr @ ".img_hdr" =
    {
      {
        .imgID = OAD_IMG_ID_VAL,
        .crc32 = DEFAULT_CRC,
        .bimVer = BIM_VER,
        .metaVer = META_VER,                   //!< Metadata version */
        .techType = OAD_WIRELESS_TECH_BLE,     //!< Wireless protocol type BLE/TI-MAC/ZIGBEE etc. */
        .imgCpStat = DEFAULT_STATE,            //!< Image copy status bytes */
        .crcStat = DEFAULT_STATE,              //!< CRC status */
        .imgNo = 0x1,                          //!< Image number of 'image type' */
        .imgVld = 0xFFFFFFFF,                  //!< In indicates if the current image in valid 0xff - valid, 0x00 invalid image */
        .len = INVALID_LEN,                    //!< Image length in bytes. */
        .softVer = SOFTWARE_VER,               //!< Software version of the image */
        .hdrLen = offsetof(imgHdr_t, fixedHdr.rfu) + sizeof(((imgHdr_t){0}).fixedHdr.rfu),   //!< Total length of the image header */
        .rfu = 0xFFFF,                         //!< reserved bytes */
        .prgEntry = (uint32_t)(__section_begin(".intvec")), //!< Program entry address */
        .imgEndAddr = (uint32_t)(__section_end("ROSTK")),
    #if (!defined(STACK_LIBRARY) && (defined(SPLIT_APP_STACK_IMAGE)))
        .imgType = OAD_IMG_TYPE_APP,
    #else
      #if defined HAL_IMAGE_A
        .imgType =  OAD_IMG_TYPE_PERSISTENT_APP,
      #else
        .imgType = OAD_IMG_TYPE_APPSTACKLIB,
      #endif
    #endif
      },
    
    #if defined(SECURITY)
      {
        .segTypeSecure = IMG_SECURITY_SEG_ID,
        .wirelessTech = OAD_WIRELESS_TECH_BLE,
        .verifStat = DEFAULT_STATE,
        .secSegLen = 0x55,
        .secVer = SECURITY_VER,                                       //!< Image payload and length */
        .secTimestamp = 0x0,                              //!< Security timestamp */
        .secSignerInfo = 0x0,
      },
    #endif /* if defined(SECURITY) */
    
    #if (!defined(STACK_LIBRARY) && (defined(SPLIT_APP_STACK_IMAGE)))
      {
        .segTypeBd = IMG_BOUNDARY_SEG_ID,
        .wirelessTech = OAD_WIRELESS_TECH_BLE,
        .rfu = DEFAULT_STATE,
        .boundarySegLen = BOUNDARY_SEG_LEN,
      #if defined HAL_IMAGE_A                      //!< Persistent image */
        .imgType =  OAD_IMG_TYPE_PERSISTENT_APP,   //!< Persistent image Type */
        .stackStartAddr = INVALID_ADDR,            //!< Stack start adddress */
        .stackEntryAddr = INVALID_ADDR,
        .prgEntry = (uint32_t)&ENTRY_START,
      #else /* User application image */
        .imgType =  OAD_IMG_TYPE_APP,              //!< Application image Type */
        .stackEntryAddr = ICALL_STACK0_ADDR,
        .stackStartAddr = ICALL_STACK0_START,
      #endif /* defined HAL_IMAGE_A */
    
      .ram0StartAddr = (uint32)(__section_begin("RWDATA")),  //!< RAM entry start address */
      .imgType = OAD_IMG_TYPE_APP,
      },
    
    #endif /* (!defined(STACK_LIBRARY) && (defined(SPLIT_APP_STACK_IMAGE))) */
      // Image payload segment initialization
      {
        .segTypeImg = IMG_PAYLOAD_SEG_ID,
        .wirelessTech = OAD_WIRELESS_TECH_BLE,
        .rfu = DEFAULT_STATE,                                         //!< Image payload and length */
        .startAddr = (uint32_t)&(_imgHdr.fixedHdr.imgID),
      }
     };
    #elif defined(__clang__)
    const imgHdr_t _imgHdr __attribute__((section( ".image_header"))) __attribute__((used)) =
    {
      {
        .imgID = OAD_IMG_ID_VAL,
        .crc32 = DEFAULT_CRC,
        .bimVer = BIM_VER,
        .metaVer = META_VER,                   //!< Metadata version */
        .techType = OAD_WIRELESS_TECH_BLE,     //!< Wireless protocol type BLE/TI-MAC/ZIGBEE etc. */
        .imgCpStat = DEFAULT_STATE,            //!< Image copy status bytes */
        .crcStat = DEFAULT_STATE,              //!< CRC status */
        .imgNo = 0x1,                          //!< Image number of 'image type' */
        .imgVld = 0xFFFFFFFF,                  //!< In indicates if the current image in valid 0xff - valid, 0x00 invalid image */
        .len = INVALID_LEN,                     //!< Image length in bytes. */
        .softVer = SOFTWARE_VER,               //!< Software version of the image */
        .hdrLen = offsetof(imgHdr_t, fixedHdr.rfu) + sizeof(((imgHdr_t){0}).fixedHdr.rfu),   //!< Total length of the image header */
        .rfu = 0xFFFF,                         //!< reserved bytes */
        .prgEntry = (uint32_t)&prgEntryAddr,
        .imgEndAddr = (uint32_t)&flashEndAddr,
    #if (!defined(STACK_LIBRARY) && (defined(SPLIT_APP_STACK_IMAGE)))
        .imgType = OAD_IMG_TYPE_APP,
    #else
      #if defined HAL_IMAGE_A
        .imgType =  OAD_IMG_TYPE_PERSISTENT_APP,
      #else
        .imgType = OAD_IMG_TYPE_APPSTACKLIB,
      #endif
    #endif
      },
    
    #if (defined(SECURITY))
      {
        .segTypeSecure = IMG_SECURITY_SEG_ID,
        .wirelessTech = OAD_WIRELESS_TECH_BLE,
        .verifStat = DEFAULT_STATE,
        .secSegLen = 0x55,
        .secVer = SECURITY_VER,                     //!< Image payload and length */
        .secTimestamp = 0x0,                         //!< Security timestamp */
        .secSignerInfo = {0x0},
      },
    #endif
    
    #if (!defined(STACK_LIBRARY) && (defined(SPLIT_APP_STACK_IMAGE)))
      .segTypeBd = IMG_BOUNDARY_SEG_ID,
      .wirelessTech1 = OAD_WIRELESS_TECH_BLE,
      .rfu = DEFAULT_STATE,
      .boundarySegLen = BOUNDARY_SEG_LEN,
      .ram0StartAddr = (uint32_t)&ramStartHere,  //!< RAM entry start address */
    
      #if defined HAL_IMAGE_A                    //! Persistent image */
        .imgType =  OAD_IMG_TYPE_PERSISTENT_APP, //!< Persistent image Type */
        .stackStartAddr = INVALID_ADDR,          //!< Stack start address */
        .stackEntryAddr = INVALID_ADDR,
      #else /* User application image */
        .imgType =  OAD_IMG_TYPE_APP,            //!< Application image Type */
        .stackEntryAddr = ICALL_STACK0_ADDR,
        .stackStartAddr = ICALL_STACK0_START,
      #endif /* defined HAL_IMAGE_A */
        .imgType = OAD_IMG_TYPE_APP,
    #endif /* STACK_LIBRARY */
    
      // Image payload segment initialization
       {
         .segTypeImg = IMG_PAYLOAD_SEG_ID,
         .wirelessTech = OAD_WIRELESS_TECH_BLE,
         .rfu = DEFAULT_STATE,
         .startAddr = (uint32_t)&(_imgHdr.fixedHdr.imgID),
       }
     };
     #endif /*  defined(__clang__) */
    
  • How does the v5.10 SDK oscilloscope readings compare to the v3.20 version?  Although the OAD image header has probably changed in the past two years, I would not expect it to break for your project since it is still valid in default examples.  What happens if you ignore the return value of writeFlash?  Can you read it back properly?  There is another E2E post in which I see unexpected behavior from the NVS TI Driver.

    Regards,
    Ryan

  • I have reached out to him as well now. 

  • Alright, so here is what I understood:

    • The targeted erase address (0x010000) was returning success, but memory was not erased.
    • The address was compared against the MEMORY ORGANIZATION table.
      • 0x010000 => Block 16
    • Targeted erase address (16) returns success and erases memory.

    For reference, this is the MEMORY ORGANIZATION Table for my Flash Chip (same series as the one used by the LaunchPad). My EFL_PAGE_SIZE is set to 4096 (0x1000) which indicates a 4KB sector. 

    I have looked for methods calling eraseFlashPg that pass an address rather than a page index. Most methods provide an integer page, but there are two that do not and they both happen to be inside of the oadCreateFactoryImageBackup where my error is occurring.

    Line 3013 passes EFL_ADDR_META (0x0, Location of table of external flash image structures) to the Macro EXT_FLASH_PAGE which bitshifts 0 to the right by 12 to 0x0. Then this value is passed to eraseFlashPg which returns successfully but is allegedly not erasing. Line 3013 could be replaced by eraseFlashPg(0) since the block of the table should be fixed on the first page, but I have never observed it returning early at line 3013 or 3015.

    Line 3019 passes the value returned by oadFindFactImgAddr() for the location of the image in external flash. This function has a note, but that shouldn't affect our use case. 

    These macros, methods, and functions are identical to those in SDK 3.20.

    But maybe I am overlooking something. I selected address values from the MEMORY ORGANIZATION table and compared the calculated page against the actual page using the macro (addr >> 12).

    • Address 0x0h (0 == 0)
    • Address 0x1000h (0 != 1)
    • Address 0x2000h (0 != 2)
    • Address 0x9f000h (2 !=159)
    • Address 0xF0000h (3 != 240)

    That doesn't look like it returns the correct page/sector at all - but if it works in SDK 3.20, it shouldn't matter for SDK 5.10.

    What do you think, ?

  • Hi Kenneth,

    I haven't been able to review this today, however I was reminded of a previous E2E thread.  Would you consider reducing the CONFIG_NVSEXTERNAL Region Size in SysConfig to test?  I'm wondering if the NVS driver isn't suited to handle the larger size and adding the system configurator is causing an inconsistency in logic.

    Regards,
    Ryan

  • What do you think would be a reasonable value to set it to? It is currently the default value.

  • If it is the default value then perhaps my hypothesis is incorrect.  I know most examples use 0x256000 based on the external flash availability on-board LaunchPads.

    Regards,
    Ryan

  • As serious as this problem is, I should work on other problems and try to revisit it later.

    static const NVSSPI25X_HWAttrs nvsSPI25XHWAttrs[1] = {
        /* CONFIG_NVS_EXTERNAL */
        {
            .regionBaseOffset = 0x0,
            .regionSize = 0x100000,
            .sectorSize = 0x1000,
            .verifyBuf = verifyBuf,
            .verifyBufSize = 64,
            /* NVS opens SPI */
            .spiHandle = NULL,
            /* SPI driver index */
            .spiIndex = CONFIG_SPI_0,
            .spiBitRate = 4000000,
            /* GPIO driver pin index */
            .spiCsnGpioIndex = CONFIG_GPIO_0,
            .statusPollDelayUs = 100
        },
    };

    Please keep me apprised of any other people who appear to be having similar problems.

  • Alright, so it's been about 10 days since my last post on the subject of non-functional OAD. I stepped back and started from scratch on the problem and performed the following comparisons:

    • SDK 3.20 Example cc26x2r1lp_bim_offchip VS SDK 3.20 Working Project
      • This isolates any changes made to make the BIM work as intended.
    • SDK 3.20 Example cc26x2r1lp_bim_offchip VS SDK 5.10 Example cc26x2r1lp_bim_offchip
      • This isolates changes made to the BIM example over the past few years.

    Comparison Results:

    Initial Observations:

    • Only (1) security signing information and (2) pinout were changed to adapt the SDK 3.20 BIM to the external flash.
    • bsp.h (which contains the pinout of the SPI flash) has been replaced with board_spi.h in (1) ext_flash.c and (2) bsp_spi.c
      • This seems like a potential problem - however, board_spi.h is not found in:
      • C:\ti\simplelink_cc13x2_26x2_sdk_5_10_00_48\source\ti\common\flash\no_rtos\extFlash
      • Which is really weird... maybe my SDK 5.10 is corrupted/missing files?
    • crc32.c changed a true to a false... not entirely sure why, but maybe no big deal.
    • Other differences didn't seem particularly important seeing as how bim_main.c/main()was unchanged

    Request:

    , can you shed me a little light on the changes to: ext_flash.c, bsp_spi.c, and crc32.c

    I will seek out a fresh copy of the board_spi.h files and maybe reinstall my SDK.

  • board_spi.h is deprecated and has been replaced with bsp.h, otherwise there are no differences to ext_flash.c or bsp_spi.c pertinent towards this investigation.  Can you please provide a code snippet of the crc32.c line you are describing?

    Regards,
    Ryan