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.

Zigbee CC2530 bootloader : Problem with CRC calculation

Other Parts Discussed in Thread: CC2530

We are using serial bootloader of TI’s CC2530. We are facing problem with CRC calculation and following are the details problem

-          We are using TI’s CC2530F256 serial bootloader code for firmware upgrade.

-          We are using CRC16 with 2 byte checksum.

-          First 8KB flash of CC2530 i.e. memory location 0x0000 to 0x1FFF is reserved for bootloader code

-          Bootloader calculates CRC of remaining flash excluding 6 pages of NV storage and 1 page of lock bits  and 4 bytes of CRC locations (2 for CRC and 2 for shadow). PFA xcl file for the application.

-          Once image is upgraded over serial, bootloader calculates its CRC and then writes it to CRC shadow location.

-          We found that CRC calculated and CRC in flash never matches. But still jump to application image occurs.

-          After digging more into bootloader code we found that, bootloader never calculates the CRC and it directly writes to CRC shadow location without checking it.  Please look at the following code snippet where one can see that CRC is directly written to shadow. (sb_exec.c)

 

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

static uint8 sbCmnd(void)

{

  uint16 tmp = BUILD_UINT16(sbBuf[SB_DATA_STATE], sbBuf[SB_DATA_STATE+1]) + SB_IMG_OSET;

  uint16 crc[2];

  uint8 len = 1;

  uint8 rsp = SB_SUCCESS;

  uint8 rtrn = FALSE;

 

  switch (sbCmd2)

  {

            .

            .

            .

 

  case SB_ENABLE_CMD:

    HalFlashRead(HAL_SB_CRC_ADDR / HAL_FLASH_PAGE_SIZE,

                 HAL_SB_CRC_ADDR % HAL_FLASH_PAGE_SIZE,

                 (uint8 *)crc, sizeof(crc));

   // Bootload master must have verified extra checks to be issuing the SB_ENABLE_CMD.

    //if ((crc[0] != crc[1]) && (crc[0] != 0xFFFF) && (crc[0] != 0x0000))

    if (crc[1] != crc[0])

    {

      crc[1] = crc[0];

      HalFlashWrite((HAL_SB_CRC_ADDR / HAL_FLASH_WORD_SIZE), (uint8 *)crc, 1);

      HalFlashRead(  HAL_SB_CRC_ADDR / HAL_FLASH_PAGE_SIZE,

                     HAL_SB_CRC_ADDR % HAL_FLASH_PAGE_SIZE,

                     (uint8 *)crc, sizeof(crc));

    }

 

    // Bootload master must have verified extra checks to be issuing the SB_ENABLE_CMD.

    //if ((crc[0] == crc[1]) && (crc[0] != 0xFFFF) && (crc[0] != 0x0000))

    if (crc[0] == crc[1])

    {

      rtrn = TRUE;

    }

    else

    {

      rsp = SB_VALIDATE_FAILED;

    }

    break;

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

 

-          Please let me know if my understanding is correct.

-          We even tried to use the arithmetic sum option for CRC but in this case also CRC never matches.

-          We need to add CRC check in our firmware upgrade scheme so as to check the integrity of the image.

 

We are stuck with this and your timely help onto this will be highly appreciated.

 Thanks in advance.

Thanks and regards,

Vikas Javkar

 

 

  • Vikas,

        Your understanding is correct and it is the intended behavior if you use SB_ENABLE_CMD command, the comment:

    "// Bootload master must have verified extra checks to be issuing the SB_ENABLE_CMD." means that the host should use SB_READ_CMD to read back and validate the download before issueing the SB_ENABLE_CMD. For an example of how the calculate the CRC look at the calcCRC() function in sb_exec.c

    This is typically quicker than letting the CC2530 bootloader do the CRC check, but if you prefer that the CC2530 does the check then do not issue the SB_ENABLE_CMD, next time the cc2530 boots the boot loader will see that _crcShdw (crc[1]) = 0xFFFF and calculate the CRC its self. This may take some time.

    Regards,

    TC.

  • Hi TC,

    Thanks for the quick reply.

    I understood the logic you have explained for SB_ENABLE_CMD above.

    Now I am trying to do the CRC calculation in bootloader and I found that calculated CRC never matches with the one stored in flash.

    Following is the linker file I am using for Zstack application

    ////////////////////////////////////////////////////////////////////////////////
    //
    //
    // Segment limits
    // --------------
    //
    //
    // XDATA available to the program.
    //
    // Reserving address 0x0 for NULL.
    -D_XDATA_START=0x0001          // The boot loader code depends on stack setting this byte to 0xCD,
                                   // which happens because it is the last byte of the XSTACK.
    -D_XDATA_END=0x1EFF
    //
    //
    // The 8052 IDATA is overlayed on the SoC XDATA space from 0x1F00-0x1FFF.
    //
    -D_IDATA_END=0xFF              // Last address of Idata memory.
    //
    //
    //    CODE
    //
    -D_CODE_START=0x2000
    -D_CODE_END=0x7FFF             // Last address for ROOT bank.
    //
    -D_FIRST_BANK_ADDR=0x10000
    //
    //
    //
    // Special SFRs
    // ------------
    //
    //    Register bank setup
    //
    -D?REGISTER_BANK=0             // Default register bank (0,1,2,3).
    -D_REGISTER_BANK_START=0       // Start address for default register bank (00,08,10,18).
    //
    //
    //    PDATA page setup
    //
    -D?PBANK_NUMBER=00             // High byte of 16-bit address to the PDATA area.
    //
    //
    //    Virtual register setup
    //    ----------------------
    //
    -D_BREG_START=0x00             // The bit address where the BREG segments starts.
                                   // Must be placed on: _BREG_START%8=0 where _BREG_START <= 0x78.
    -D?VB=0x20                     // ?VB is used when referencing BREG as whole byte.
                                   // Must be placed on: ?VB=0x20+_BREG_START/8.
    //
    ////////////////////////////////////////////////////////////////////////////////



    ////////////////////////////////////////////////////////////////////////////////
    //
    // IDATA memory
    //

    // Setup "bit" segments (only for '__no_init bool' variables).
    -Z(BIT)BREG=_BREG_START
    -Z(BIT)BIT_N=0-7F

    -Z(DATA)REGISTERS+8=_REGISTER_BANK_START
    -Z(DATA)BDATA_Z,BDATA_N,BDATA_I=20-2F
    -Z(DATA)VREG+_NR_OF_VIRTUAL_REGISTERS=08-7F
    -Z(DATA)PSP,XSP=08-7F
    -Z(DATA)DOVERLAY=08-7F
    -Z(DATA)DATA_I,DATA_Z,DATA_N=08-7F

    -U(IDATA)0-7F=(DATA)0-7F
    -Z(IDATA)IDATA_I,IDATA_Z,IDATA_N=08-_IDATA_END
    -Z(IDATA)ISTACK+_IDATA_STACK_SIZE#08-_IDATA_END
    -Z(IDATA)IOVERLAY=08-FF

    ////////////////////////////////////////////////////////////////////////////////
    //
    // ROM memory
    //
    //
    // The following segments *must* be placed in the root bank. The order of
    // placement also matters for these segments, which is why we use the -Z
    // placement directive.
    //
    -Z(CODE)INTVEC=_CODE_START

    -Z(CODE)CHECKSUM=0x2090-0x2091
    -Z(CODE)CRC_SHDW=0x2092-0x2093

    -Z(CODE)BIT_ID,BDATA_ID,DATA_ID,IDATA_ID,IXDATA_ID,PDATA_ID,PDATA_Z,XDATA_ID=_CODE_START-_CODE_END
    //
    // Sleep PCON instruction must be 4-byte aligned.
    //
    -D_SLEEP_CODE_SPACE_START=(_CODE_END-7)
    -D_SLEEP_CODE_SPACE_END=(_CODE_END)
    -Z(CODE)SLEEP_CODE=_SLEEP_CODE_SPACE_START-_SLEEP_CODE_SPACE_END
    //
    // The following segments *must* be placed in the root bank, but the order
    // of placement within the root bank is not important, which is why we use the
    // -P directive here.
    //
    -P(CODE)CSTART,BANK_RELAYS,RCODE,DIFUNCT,NEAR_CODE=_CODE_START-_CODE_END
    //
    // Setup for constants located in code memory:
    //
    -P(CODE)CODE_C=_CODE_START-_CODE_END
    //
    // Define segments for const data in flash.
    // First the segment with addresses as used by the program (flash mapped as XDATA)
    -P(CONST)XDATA_ROM_C=0x8000-0xFFFF
    //
    // Then the segment with addresses as put in the hex file (flash bank 1)
    -P(CODE)XDATA_ROM_C_FLASH=0x18000-0x1FFFF
    //
    // Finally link these segments (XDATA_ROM_C_FLASH is the initializer segment for XDATA_ROM_C,
    // we map the flash in the XDATA address range instead of copying the data to RAM)
    -QXDATA_ROM_C=XDATA_ROM_C_FLASH
    //
    // The directive below ensures that the remaining space in the root bank gets
    // filled, then starts filling the banks.
    //
    -P(CODE)BANKED_CODE=_CODE_START-_CODE_END,0x18000-0x1FFFF,0x28000-0x2FFFF,0x38000-0x3FFFF,\
    0x48000-0x4FFFF,0x58000-0x5FFFF,0x68000-0x6FFFF,0x78000-0x7C7FF

    ////////////////////////////////////////////////////////////////////////////////
    //
    // XDATA memory
    //

    -Z(XDATA)XSTACK+_XDATA_STACK_SIZE=_XDATA_START-_XDATA_END
    -Z(XDATA)XDATA_Z,XDATA_I=_XDATA_START-_XDATA_END
    -P(XDATA)XDATA_N=_XDATA_START-_XDATA_END

    -cx51

    ////////////////////////////////////////////////////////////////////////////////
    //
    // Texas Instruments device specific
    // =================================
    //
    //
    // Layout of CODE banks
    // -------------------
    //
    //-D_BANK0_START=0x08000
    //-D_BANK0_END=0x0FFFF
    //
    //-D_BANK1_START=0x18000
    //-D_BANK1_END=0x1FFFF
    //
    //-D_BANK2_START=0x28000
    //-D_BANK2_END=0x2FFFF
    //
    //-D_BANK3_START=0x38000
    //-D_BANK3_END=0x3FFFF
    //
    //-D_BANK4_START=0x48000
    //-D_BANK4_END=0x4FFFF
    //
    //-D_BANK5_START=0x58000
    //-D_BANK5_END=0x5FFFF
    //
    //-D_BANK6_START=0x68000
    //-D_BANK6_END=0x6FFFF
    //
    //-D_BANK7_START=0x78000
    //-D_BANK7_END=0x7FFFF
    //
    //
    // Include these two lines when generating a .hex file for banked code model:
    //-M(CODE)[(_CODEBANK_START+_FIRST_BANK_ADDR)-(_CODEBANK_END+_FIRST_BANK_ADDR)]*\
    //_NR_OF_BANKS+_FIRST_BANK_ADDR=0x8000
    //
    //
    // Internal flash used for NV address space: reserving 6 pages.
    // NV memory segment size must coincide with page declarations in "hal_board_cfg.h" file.
    //
    -D_ZIGNV_ADDRESS_SPACE_START=(((_NR_OF_BANKS+1)*_FIRST_BANK_ADDR)-0x3800)
    -D_ZIGNV_ADDRESS_SPACE_END=(_ZIGNV_ADDRESS_SPACE_START+0x2FFF)
    -Z(CODE)ZIGNV_ADDRESS_SPACE=_ZIGNV_ADDRESS_SPACE_START-_ZIGNV_ADDRESS_SPACE_END
    //
    ////////////////////////////////////////////////////////////////////////////////



    ////////////////////////////////////////////////////////////////////////////////
    //
    //
    // Skip boot code, CRC/shadow & NV pages when calculating the CRC.
    //
    -J2,crc16,=2000-208F,2094-7C7FF
    //
    // Fill code gaps with 0xFFFF so that the CRC can be verified programatically.
    -HFFFF
    //
    ////////////////////////////////////////////////////////////////////////////////

    Bootloader uses calcCRC() function to calculate the CRC for HAL_SB_IMG_SIZE

    #define HAL_SB_IMG_ADDR       0x2000
    #define HAL_SB_CRC_ADDR       0x2090
    // Size of internal flash less 5 pages for boot loader, 6 pages for NV, & 1 page for lock bits.
    #define HAL_SB_IMG_SIZE      (0x40000 - 0x2000 - 0x3000 - 0x0800)

    I want to know if I am missing something here.

    Note : If I calculate the CRC with image size less than 32 K then CRC mathes but for image size larger than 32K it doesn't.

    Thanks in advance.

    - Vikas

  • Vikas,

        Can you confirm that you are using the cc2530-sb.xcl linker file supplied in ZStack to build the application?

    TC.

  • Thanks TC for quick reply.

    Yes we are using the "cc2530-sb.xcl" which comes with zstack.

  • Hi Vikas,

    There seems to be a bug in the bootloader, where the calculated crc fails to be written to the flash when using the bootloader to calculate the checksum (rather than calculating it externally and issuing SB_ENABLE_CMD). This happens because in the first case above, the checksum is written to flash before the DMA is initialized (the flash write commands makes use of DMA).

    To solve this, please add the following #include lines to sb_exec.c

        #include "hal_dma.h"
        #include "hal_defs.h"

    and add the following line to sbImgValid() in sb_exec.c, right after the line "crc[1] = calcCRC();":

        HAL_DMA_SET_ADDR_DESC0(&dmaCh0); //initialize DMA channel 0

    Please let me know if it solves your issue. (I did not find a relation between the image size and the success of writing the checksum).

    Regards,

    OD.

  • Hi, is this verified bug?
    I have situation where I manually set crc_shdw to match crc from image. After some time, my boards stopped working, and when i read images, crc and crc_shadow dont match, and boards are stuck in bootloader.
    I dont understand how this can happen, if bootloader see that crc and crc_shdw are identical, he shouldnt mess with them?

    Thank you in advance
    Simon