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.

CC2530 Bootloader被擦除

Other Parts Discussed in Thread: CC2530, CC2538, CC2430

我用STM32给cc2530 做seralboot升级中遇到了一个奇怪的问题, 部分设备的bootloder头(最前面的2kbytes(第一个page))被擦除了,这个现象在墨西哥和英国的有些设备中出现了这个问题,在上海地做过很多试验都没有复现(做了超过一个星期的升级,每15min升级一次), 不知道这个是否和bootloder的改动有关,请大神们帮忙看看。
zstack mesh 1.0上原来计算SB_ENABLE_CMD是每个字节每个字节读取flash的,我觉得有点慢,就改成了每512 bytes一读计算,因为本地不能复现,然后在已经出货的国外设备中出现这个问题,我们又没办法调试(把出问题的设备带回来,然后我把zigbee read back回来,发现bootloader头部被擦除了2k bytes,而且读出来出问题的两个设备读出来的数据是一样的,头部2k都擦除), 我不知道是否和电压有关,本地做了如下实验都无法复现,现在不知道什么问题,求大神们指点,帮看看有没有什么问题,谢谢:
1. 每15min给设备升级一次zigbee, 超过一个星期不能复现,
2. 每次设备run起来然后就设备断电重启,超过一个星期不能复现

我的修改如下:

/**************************************************************************************************
* @fn sbCmnd
*
* @brief Act on the SB command and received buffer.
*
* input parameters
*
* None.
*
* output parameters
*
* None.
*
* @return TRUE to indicate that the SB_ENABLE_CMD command was successful; FALSE otherwise.
**************************************************************************************************
*/
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_HANDSHAKE_CMD:
break;

case SB_WRITE_CMD:
if ((tmp % SB_WPG_SIZE) == 0)
{
HalFlashErase(tmp / SB_WPG_SIZE);
}

HalFlashWrite(tmp, sbBuf+SB_DATA_STATE+2, SB_RW_BUF_LEN / HAL_FLASH_WORD_SIZE);
break;

case SB_READ_CMD:
#if !MT_SYS_OSAL_NV_READ_CERTIFICATE_DATA
if ((tmp / (HAL_FLASH_PAGE_SIZE / 4)) >= HAL_NV_PAGE_BEG)
{
rsp = SB_FAILURE;
break;
}
#endif
HalFlashRead(tmp / (HAL_FLASH_PAGE_SIZE / 4),
(tmp % (HAL_FLASH_PAGE_SIZE / 4)) << 2,
sbBuf + SB_DATA_STATE + 3, SB_RW_BUF_LEN);
sbBuf[SB_DATA_STATE+2] = sbBuf[SB_DATA_STATE+1];
sbBuf[SB_DATA_STATE+1] = sbBuf[SB_DATA_STATE];
len = SB_RW_BUF_LEN + 3;
break;

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));
// }

if (crc[0] != crc[1])
{
crc[1] = calcCRC();
if (crc[0] != crc[1])
{
crc[1] = recalcCRC();
}
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]) && (crc[0] != 0xFFFF) && (crc[0] != 0x0000))
{
rtrn = TRUE;
}
else
{
rsp = SB_VALIDATE_FAILED;
}
break;

default:
break;
}

sbResp(rsp, len);
return rtrn;
}

/**************************************************************************************************
* @fn calcCRC
*
* @brief Run the CRC16 Polynomial calculation over the RC image.
*
* input parameters
*
* None.
*
* output parameters
*
* None.
*
* @return The CRC16 calculated.
**************************************************************************************************
*/
static uint16 calcCRC(void)
{
uint32 addr;
uint16 crc = 0;
uint32 offset = HAL_SB_IMG_ADDR;
uint16 read_size = 512;
uint8 buf[512];
uint16 i;

// Run the CRC calculation over the active body of code.
/* for (addr = HAL_SB_IMG_ADDR; addr < HAL_SB_IMG_ADDR + HAL_SB_IMG_SIZE; addr++)
{
if (addr == HAL_SB_CRC_ADDR)
{
addr += 3;
}
else
{
uint8 buf;
HalFlashRead(addr / HAL_FLASH_PAGE_SIZE, addr % HAL_FLASH_PAGE_SIZE, &buf, 1);
crc = runPoly(crc, buf);
}
}
*/

// modified by qnchen
for ( addr = offset; addr < offset + HAL_SB_IMG_SIZE; addr += read_size )
{
HalFlashRead(addr / HAL_FLASH_PAGE_SIZE, addr % HAL_FLASH_PAGE_SIZE, buf, read_size);
for ( i = 0; i < read_size; i++ )
{
// crc in 0x2090
if ( (addr - offset + i) == (HAL_SB_CRC_ADDR - HAL_SB_IMG_ADDR) )
{
i += 3;
}
else
{
crc = runPoly(crc, buf[i]);
}
}
}

// IAR note explains that poly must be run with value zero for each byte of crc.
crc = runPoly(crc, 0);
crc = runPoly(crc, 0);

return crc;
}


/**************************************************************************************************
* @fn calcCRC
*
* @brief Run the CRC16 Polynomial calculation over the RC image.
*
* input parameters
*
* None.
*
* output parameters
*
* None.
*
* @return The CRC16 calculated.
**************************************************************************************************
*/
static uint16 recalcCRC(void)
{
uint32 addr;
uint16 crc = 0;
uint32 offset = HAL_SB_IMG_ADDR;
uint16 read_size = 256;
uint8 buf[256];
uint16 i;

for ( addr = offset; addr < offset + HAL_SB_IMG_SIZE; addr += read_size )
{
HalFlashRead(addr / HAL_FLASH_PAGE_SIZE, addr % HAL_FLASH_PAGE_SIZE, buf, read_size);
for ( i = 0; i < read_size; i++ )
{
// crc in 0x2090
if ( (addr - offset + i) == (HAL_SB_CRC_ADDR - HAL_SB_IMG_ADDR) )
{
i += 3;
}
else
{
crc = runPoly(crc, buf[i]);
}
}
}

// IAR note explains that poly must be run with value zero for each byte of crc.
crc = runPoly(crc, 0);
crc = runPoly(crc, 0);

return crc;
}

  • I run with TI-ZStack mesh 1.0 on CC2530, but some of my zigbee device was crash, On my Shanghai(China) lab never happened this, but in Mexico and England

    have several device zigbee crash(but not all), and the head of bootloader was erased(First page(2kbytes)), for local can't reproduce the issue, even I update the zigbee for more

    then 1 week, and device will update the firmware every ten minutes(Do like the serial boot tool),I don't know whether my change of bootloader cause this, original SB_ENABLE_CMD calculate the CRC read with one by one byte, and I change to every 512bytes. Also we find only the device have upgraded will happen to this issue, Now we don't know the voltage or the software change cause this, but we local can't reproduce this. I hope to get the help from you. 

    My change as follow:

    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));
    // }

    if (crc[0] != crc[1])
    {
    crc[1] = calcCRC();
    if (crc[0] != crc[1])
    {
    crc[1] = recalcCRC();
    }
    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]) && (crc[0] != 0xFFFF) && (crc[0] != 0x0000))
    {
    rtrn = TRUE;
    }
    else
    {
    rsp = SB_VALIDATE_FAILED;
    }
    break;

    /**************************************************************************************************
    * @fn calcCRC
    *
    * @brief Run the CRC16 Polynomial calculation over the RC image.
    *
    * input parameters
    *
    * None.
    *
    * output parameters
    *
    * None.
    *
    * @return The CRC16 calculated.
    **************************************************************************************************
    */
    static uint16 calcCRC(void)
    {
    uint32 addr;
    uint16 crc = 0;
    uint32 offset = HAL_SB_IMG_ADDR;
    uint16 read_size = 512;
    uint8 buf[512];
    uint16 i;

    // Run the CRC calculation over the active body of code.
    /* for (addr = HAL_SB_IMG_ADDR; addr < HAL_SB_IMG_ADDR + HAL_SB_IMG_SIZE; addr++)
    {
    if (addr == HAL_SB_CRC_ADDR)
    {
    addr += 3;
    }
    else
    {
    uint8 buf;
    HalFlashRead(addr / HAL_FLASH_PAGE_SIZE, addr % HAL_FLASH_PAGE_SIZE, &buf, 1);
    crc = runPoly(crc, buf);
    }
    }
    */

    // modified by qnchen
    for ( addr = offset; addr < offset + HAL_SB_IMG_SIZE; addr += read_size )
    {
    HalFlashRead(addr / HAL_FLASH_PAGE_SIZE, addr % HAL_FLASH_PAGE_SIZE, buf, read_size);
    for ( i = 0; i < read_size; i++ )
    {
    // crc in 0x2090
    if ( (addr - offset + i) == (HAL_SB_CRC_ADDR - HAL_SB_IMG_ADDR) )
    {
    i += 3;
    }
    else
    {
    crc = runPoly(crc, buf[i]);
    }
    }
    }

    // IAR note explains that poly must be run with value zero for each byte of crc.
    crc = runPoly(crc, 0);
    crc = runPoly(crc, 0);

    return crc;
    }

    static uint16 recalcCRC(void)
    {
    uint32 addr;
    uint16 crc = 0;
    uint32 offset = HAL_SB_IMG_ADDR;
    uint16 read_size = 256;
    uint8 buf[256];
    uint16 i;

    for ( addr = offset; addr < offset + HAL_SB_IMG_SIZE; addr += read_size )
    {
    HalFlashRead(addr / HAL_FLASH_PAGE_SIZE, addr % HAL_FLASH_PAGE_SIZE, buf, read_size);
    for ( i = 0; i < read_size; i++ )
    {
    // crc in 0x2090
    if ( (addr - offset + i) == (HAL_SB_CRC_ADDR - HAL_SB_IMG_ADDR) )
    {
    i += 3;
    }
    else
    {
    crc = runPoly(crc, buf[i]);
    }
    }
    }

    // IAR note explains that poly must be run with value zero for each byte of crc.
    crc = runPoly(crc, 0);
    crc = runPoly(crc, 0);

    return crc;
    }


    /**************************************************************************************************
    * @fn runPoly
    *
    * @brief Run the CRC16 Polynomial calculation over the byte parameter.
    *
    * input parameters
    *
    * @param crc - Running CRC calculated so far.
    * @param val - Value on which to run the CRC16.
    *
    * output parameters
    *
    * None.
    *
    * @return crc - Updated for the run.
    **************************************************************************************************
    */
    static uint16 runPoly(uint16 crc, uint8 val)
    {
    const uint16 poly = 0x1021;
    uint8 cnt;

    for (cnt = 0; cnt < 8; cnt++, val <<= 1)
    {
    uint8 msb = (crc & 0x8000) ? 1 : 0;

    crc <<= 1;
    if (val & 0x80) crc |= 0x0001;
    if (msb) crc ^= poly;
    }

    return crc;
    }

  • 正好我们最近在做CC2538 ZNP的firmware更新,我们平台是arm linux,所以使用的是移植的zigbee linux gateway里面的sbl_tool.bin,通过UART口进行更新的。

    没有遇到你这类的问题,据我对bootloader的代码分析,首先bootloader是和最开始的那个带bootloader的固件一起使用smartrf programmer刷进去的,后面再次更新的话,就不需要带bootloader了。

    更新固件的原理和使用smartrf programmer更新原理一样,也是给出偏移地址和待写入的字节数量,然后bootloader会计算出需要擦出的page数目,并擦除,然后再写入。如此反复,直到最后一个page写完。

    回头猜测一下你的问题,不太可能是外部电压的问题,还是代码有bug,很难复现,你得好好分析一下偏移地址是否计算出来待擦出的page有问题,可能就是这个问题导致bootloader所在的page被擦出了。
  • Thanks Hold li, 正常操作应该是不会出现这个问题的,因为我在看计算写入地址的时候里面还带了一个offset address, 也就是bootloader 的尾,也就是说它会从bootloader的尾问开始写, 2530的image 存储方式是bootloader+app, 2538的是app+bootlader,这里面我就不太清楚是否和我计算crc方式有关,原来 是一个字节一个字节读,我觉得有点慢,然后我就改成了512一读计算CRC

  • 不排除是偏移地址在计算的时候出错,导致bootloader被意外擦除。

    我后面花些时间分析一下cc2530的bootloader工作机制,另外你们stm32平台和cc2530是通过uart通讯的吧,波特率多少,smt平台我不太熟悉,估计应该是跑不了真正的linux,不知你在stm上是如何存储读取cc2530的固件的

  • 我在cc2430碰過類似的問題
    至今無解,只能推斷是2430晶片的bug

    我發現到我的firmware在進行更新的時候,極少的機器會發生bootloader的某一頁被抹除
    後來查到最後的結論是

    我用debug模式,監控IAR所編譯出來的組合語言,並且單步執行的時候發現到,當系統執行了flash erase之後,R0 ~ R7的某個值居然被更動了!
    如果剛好你的變數,就暫存在R0 ~ R7,那你下一次flash erase的參數就會是錯誤的,那就會抹除到錯誤的flash頁

    估計是你HalFlashErase這邊造成異常了,當R0 ~ R7異常被更動時,HalFlashErase引入的參數就會是錯誤的,就會抹除錯誤的flash頁面

    case SB_WRITE_CMD:
    if ((tmp % SB_WPG_SIZE) == 0)
    {
    HalFlashErase(tmp / SB_WPG_SIZE);
    }

    下面是我之前發的討論串
    e2echina.ti.com/.../125382

  • 首先不排除silicon级别的bug,毕竟除了OSAL,silicon上也有软件在运行,只是不对用户开放代码。

    关于擦出的计算,显然是这里出了问题,您说得可能是R系列寄存器里面的值被意外修改?
  • e2echina.ti.com/.../125382

    請看這篇,我當初也想得到答案,但是無奈沒人回應,也找不到原因在哪
  • Lin Ting-Yu, 谢谢你的回复!

    我会根据你说的再进一步看看是否是相同的问题!!我这边对于这个问题也是无解目前,目前只是说对一些操作做了保护措施(还要进一步测试),但root cause没有找到!!