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内部flash数据丢失问题求教

Other Parts Discussed in Thread: CC2530

 我这里使用的TI的CC2530开发的产品中使用了内部的flash存储的数据最近发现有丢失现象,协议栈使用的是Zstack-CC2530-2.3.0-1.4.0,flash读写函数使用的是协议栈中提供的osal_nv_write(),osal_nv_read()和osal_nv_item_init()函数,在调用osal_nv_write()和osal_nv_read()之前都先调用的osal_nv_item_init(),判断osal_nv_item_init()返回成功才进行执行读写函数,程序中使用的NV item在 0x201-0x302之间,每一个item最多存储2个字节的数据,在研发阶段都没有发现什么问题,现在工程现场应用了一段时间,发现有些产品中这些数据被清除了,请帮忙分析一下原因。在客户应用中是否出现过这样的问题,我们在应用时还需要注意哪些问题,谢谢支持!

  • 数据被清除,是指全部NV数据都没有吗?

    还是说部分被改动了,部分还在。

  • 从返回样机查看,NV中的数据都被清掉了,网络信息(信道和PanID)都发生了改变,从读取效果看,跟刚下完程序一个效果。

  • 有没有可能中途出现过复位,然后在复位,启动以后start option有改动过了,导致重新擦除参数启动。

    你们程序里面有没有改动这个start option的地方,另外你们的节点如果重新加网的话,会自动把之前保存的应用相关的参数擦除掉吗?

  • 出现复位是有可能的,改动start option的地方也是有的,为了防止出现您说的这种情况,我们在程序中做了限制,start option需要配合和外部按键一起才能触发这种参数恢复默认值的操作,我们在应用的过程中对修改start option的操作做了记录,如果有类似的操作,只要不重新下载程序,都会有记录可查的,但从返回的问题样机根本看不出一点记录;另外节点如果重新加网的话,协调器中的参数也不会擦除掉。

  • 如果有部分数据丢失的话,有可能是在运行过程中,在对部分数据进行读写的时候,导致出错。

    如果数据全部都擦除的话,一定是软件的操作导致的。

    你们现场协调器和节点都出现NV数据被擦除的情况吗?

  • 我看到在协议栈中的main()函数里zgInit()函数之前有一个osal_nv_init()函数,能解释一下osal_nv_init()函数的工作过程吗?我这里出现数据丢失的问题现象都很一致,nv中的数据都被重置了,包括在zgInit()函数中没有进行过复位操作的几个NV Item,从现象上来看就是跟刚下完程序一个效果,所以我现在还是比较怀疑在zgInit()之外还有其他的地方出现了问题,请帮忙分析一下,谢谢支持!

  • 您可以在IAR内追踪该函数,osal_nv_init 主要是调用了(void)initNV(); 

    /*********************************************************************
    * @fn osal_nv_init
    *
    * @brief Initialize NV service.
    *
    * @param p - Not used.
    *
    * @return none
    */
    void osal_nv_init( void *p )
    {
    (void)p; // Suppress Lint warning.
    (void)initNV(); // Always returns TRUE after pages have been erased.
    }

    而(void)initNV(); 的定义可以在OSAL_Nv.c查找到

    /*********************************************************************
    * @fn initNV
    *
    * @brief Initialize the NV flash pages.
    *
    * @param none
    *
    * @return TRUE
    */
    static uint8 initNV( void )
    {
    osalNvPgHdr_t pgHdr;
    uint8 oldPg = OSAL_NV_PAGE_NULL;
    uint8 findDups = FALSE;
    uint8 pg;

    pgRes = OSAL_NV_PAGE_NULL;

    for ( pg = OSAL_NV_PAGE_BEG; pg <= OSAL_NV_PAGE_END; pg++ )
    {
    HalFlashRead(pg, OSAL_NV_PAGE_HDR_OFFSET, (uint8 *)(&pgHdr), OSAL_NV_HDR_SIZE);

    if ( pgHdr.active == OSAL_NV_ERASED_ID )
    {
    if ( pgRes == OSAL_NV_PAGE_NULL )
    {
    pgRes = pg;
    }
    else
    {
    setPageUse( pg, TRUE );
    }
    }
    // An Xfer from this page was in progress.
    else if ( pgHdr.xfer != OSAL_NV_ERASED_ID )
    {
    oldPg = pg;
    }
    }

    // If a page compaction was interrupted before the old page was erased.
    if ( oldPg != OSAL_NV_PAGE_NULL )
    {
    /* Interrupted compaction before the target of compaction was put in use;
    * so erase the target of compaction and start again.
    */
    if ( pgRes != OSAL_NV_PAGE_NULL )
    {
    erasePage( pgRes );
    (void)compactPage( oldPg, OSAL_NV_ITEM_NULL );
    }
    /* Interrupted compaction after the target of compaction was put in use,
    * but before the old page was erased; so erase it now and create a new reserve page.
    */
    else
    {
    erasePage( oldPg );
    pgRes = oldPg;
    }
    }
    else if ( pgRes != OSAL_NV_PAGE_NULL )
    {
    erasePage( pgRes ); // The last page erase could have been interrupted by a power-cycle.
    }
    /* else if there is no reserve page, COMPACT_PAGE_CLEANUP() must have succeeded to put the old
    * reserve page (i.e. the target of the compacted items) into use but got interrupted by a reset
    * while trying to erase the page to be compacted. Such a page should only contain duplicate items
    * (i.e. all items will be marked 'Xfer') and thus should have the lost count equal to the page
    * size less the page header.
    */

    for ( pg = OSAL_NV_PAGE_BEG; pg <= OSAL_NV_PAGE_END; pg++ )
    {
    // Calculate page offset and lost bytes - any "old" item triggers an N^2 re-scan from start.
    if ( initPage( pg, OSAL_NV_ITEM_NULL, findDups ) != OSAL_NV_ITEM_NULL )
    {
    findDups = TRUE;
    pg = (OSAL_NV_PAGE_BEG - 1); // Pre-decrement so that loop increment will start over at zero.
    continue;
    }
    }

    if (findDups)
    {
    // Final pass to calculate page lost after invalidating duplicate items.
    for ( pg = OSAL_NV_PAGE_BEG; pg <= OSAL_NV_PAGE_END; pg++ )
    {
    (void)initPage( pg, OSAL_NV_ITEM_NULL, FALSE );
    }
    }

    if ( pgRes == OSAL_NV_PAGE_NULL )
    {
    uint8 idx, mostLost = 0;

    for ( idx = 0; idx < OSAL_NV_PAGES_USED; idx++ )
    {
    // Is this the page that was compacted?
    if (pgLost[idx] == (OSAL_NV_PAGE_SIZE - OSAL_NV_PAGE_HDR_SIZE))
    {
    mostLost = idx;
    break;
    }
    /* This check is not expected to be necessary because the above test should always succeed
    * with an early loop exit.
    */
    else if (pgLost[idx] > pgLost[mostLost])
    {
    mostLost = idx;
    }
    }

    pgRes = mostLost + OSAL_NV_PAGE_BEG;
    erasePage( pgRes ); // The last page erase had been interrupted by a power-cycle.
    }

    return TRUE;
    }