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.

Retaining paring when power cycled

Other Parts Discussed in Thread: SIMPLICITI, CC1101

How do you setup SimpliciTI to retain the paring information so when the power is cycled on the coordinator of the endpoints the automatically re-established their links? We are currently using CC1110-CC1111DK

  • Hi John,

    SimpliciTI does not have such a feature. An enddevice that is reseted could send a broadcast and every device checks its connection table if a link was established upon receiving the broadcast and starts the unlink/link process.

    The alternative would be to save the connection table in a persistant memory before the reset. The name of the connection table is sPersistInfo.

  • Is there example code for either of these solutions?

  • Please send me information on how to save / restore the information on the CC1110 devices.

  • I dont know how you can save data in flash during runtime because I dont have any experience with 8051 MCU, but basically you just have to save the content of the sPersistInfo struct in flash. Then you reset the device and overwrite the content of this struct in the RAM with the data in flash after you called smpl_init, because this call resets this structure.

    I have never implemented both suggestions, so there might be side-effects, at least for the second suggestion.

    You could also ask Hunter Wang for assistance, because I think that he successfully implemented it (http://e2e.ti.com/support/low_power_rf/f/156/t/147320.aspx).

  • What's the relationship between sPersistInfo and NVOBJECT?  I can enable NVOBJECT_SUPPORT in nwk_config.dat, which says "Adds support for gerting and setting connection context for saving across resets."

    IOCTL_OBJ_NVOBJ

    Non-volatile memory object

    Get and set the NV object. This permits a device to save connection context across power cycles so that communications can be restored in event of a reset.

    Are these different ways to do the same thing?

  • This function gives you only a pointer to the sPersistInfo structure nothing more.

  • Hello.

    mark sonn said:
    This function gives you only a pointer to the sPersistInfo structure nothing more

    It's enough.

    The ioctl call gives you what you need. You get a pointer to the NV object and the length of the object. You need to write your own flash driver and save the context described in the ioctl call. On power-up use the same call to find out where to put the saved information. It is up to you to manage the saved area in your flash. It is not intended that you directly manipulate the NV object. That is why there isn't any information about the object in the API document. You of course are free to mess things up on your own...

    You have another burden as well. Though the binding of Link ID to connection information is established by the NWK layer during the link transaction it is up to the user application to maintain the semantics of the connection. That means if you save the NV object, which contains connection information, you also need to save your application's Link ID map. It's your application that knows what Link ID belongs to what connection. In the case of an ED where there is likely only 1 connection and it is to the AP it is still good practice is to save the Link ID map. Though the Link ID is usually 1 for EDs in a single connection to an AP this is not guaranteed anywhere.

    Hope this helps.

    lfriedman

  • Yes, I'm going to need to store some other link-related variables, too, but that's very helpful, thanks.

    Aren't the linkIDs listed in sPersistInfo.connStruct[i].thisLinkID, though?

    Is the NVOBJECT size a fixed number?  Determined by fixed things like NUM_CONNECTIONS, maybe?  If not, is it possible to calculate the max size for a given compiled program?  I might want to do some kind of wear-leveling.

  • Hello.

    Jonathan9420 said:
    Aren't the linkIDs listed in sPersistInfo.connStruct[i].thisLinkID, though?

    Yes but as I mentioned only the application knows the context. Though one could peruse the structure for Link IDs, without context this would be pretty useless if there were more than a single connection. It's a better design to keep the context where it has meaning -- at the application. The Link ID is intended as a handle at the application layer where it has a context (the link transaction) not at the NWK layer where it is side effect.

    Jonathan9420 said:
    Is the NVOBJECT size a fixed number?

    Yes the size is fixed for a given compiled and instantiated image. Its size is not dynamic at run time.

    Jonathan9420 said:
    I might want to do some kind of wear-leveling.

    I don't recall the specifics of the MCU you are using but it might be a challenge in the 8051 Harvard architecture with relatively large page sizes and relatively small erase duty cycles...good luck!

    lfriedman

  • Hi,

    there is an example code on how this can be done (target used is eZ430-RF2500):

    http://processors.wiki.ti.com/index.php/SimpliciTI_FAQ#Restoring_connection_after_power_cycle

    Basically the sPersistInfo structure (retrieved by using IOCTL_OBJ_NVOBJ) and the linkID handle on the application level need to be stored in a non volatile memory.

  • Dear Leo,

    I have used the above example code for restoring the connection after the power cycle. Meanwhile I have a problem, I have my own struture that have for each ED all the information (ID, adress and other ED informations), some of this information is obtained by the following functio suggested by TI:

    void nwkGetPeerAddr(linkID_t sLinkId, addr_t *peerAddr)
    {
      uint8_t index;
     
      if(map_lid2idx(sLinkId, &index))
      {
        memcpy(peerAddr->addr, sPersistInfo.connStruct[index].peerAddr, NET_ADDR_SIZE);
      }  
    }
    I save in the flash the AP information as it is described in the example code, I didn't change anything. The only difference is each time I have an ED linklisten I make a new  nv_obj_write_nwk_cfg.

    Then I reboot the system e make an new call to the flash ( void* nv_obj_read_nwk_cfg(void)) as it is described by your example code, but when I use again the nwkGetPeerAddr function, for each ED number that I have in my system, I get  null values, why? Can you give an idea? Also, I'm using the 2955 and the CC1101

    Regards

    Ralph

  • Ralph,

    Ralph said:

    I save in the flash the AP information as it is described in the example code, I didn't change anything. The only difference is each time I have an ED linklisten I make a new  nv_obj_write_nwk_cfg.

    I guess you only call nv_obj_write_nwk_cfg() only if the SMPL_LinkListen() returns SUCCESS.

    I must honestly say, that it has been quite a while since i wrote the example code. But looking into the code, it is basically pretty straight forward. To mark that the INFO memory contains a valid network configuration, i put "SMPL" like kind of string bytes in the beginning of INFO memory. The nv_obj_read_nwk_cfg() will return NULL if it can't find this string. Have you tried during debugging to see the memory window what is the content of the INFO memory (starting at address 0x1000) after writing the network configuration and then after reboot?

  • Dear Leo,

     My partial code is as follows:

      if (SMPL_SUCCESS == SMPL_LinkListen(&sLID[sNumCurrentPeers]))
            {
              nwk_cfg_ram.objPtr = &data;   // point to pointer //
              
              if(SMPL_Ioctl(IOCTL_OBJ_NVOBJ, IOCTL_ACT_GET, &nwk_cfg_ram) == SMPL_SUCCESS)  // save network configuration in non volatile memory
              {
                 if(nv_obj_write_nwk_cfg(data, nwk_cfg_ram.objLen) != true)
                {
                  __no_operation(); // for debugging
                }
              }

    this is very similar to the code you provided in the SimpliciTI FAQ. So it should work perfectly well.

    In debugging, I can see some data on the flash after the nv_obj_write_nwk_cfg call. But I can't ensure that is in fact the real data.

    When I make the call to the nv_obj_read_nwk_cfg the return value is not NULL.

    Then I make :

     if(nwk_cfg_flash != NULL)
      {
        uint8_t i = 0;
        // point to pointer //
        nwk_cfg_ram.objPtr = &data;

        // restore network configuration to RAM //
        if(SMPL_Ioctl(IOCTL_OBJ_NVOBJ, IOCTL_ACT_GET, &nwk_cfg_ram) == SMPL_SUCCESS)
        {
          memcpy(data, nwk_cfg_flash, nwk_cfg_ram.objLen);
        }
        sNumCurrentPeers = nv_obj_read_lnk_numbers_of_id();
        
        for (i = 0; i < sNumCurrentPeers; i++)
        {
          // get link ID from flash //
          sLID[i] = nv_obj_read_lnk_id(i);
          nwkGetPeerAddr(sLID[i], &ed_addr);
          my_conn_struct[sNumCurrentPeers].type = ed_addr.addr[0];
          memcpy(my_conn_struct[sNumCurrentPeers].addr, my_addr.addr, sizeof(ed_addr));
          my_conn_struct[sNumCurrentPeers].sID = sLID[sNumCurrentPeers];
        }
      }

    }

    but the result in my variable: "ed_adress" is ZERO and I don't know why... any ideas?

    Regards

    Ralph

  • Dear Leo,

    Should I save my own structure and use only your NV functions to feed again the SimpliciTI basic struture? In each of the EDs I use the same functions (without the nwkGetPeerAddr function and my structure) and it is working.

    So there should be an error in the nwkGetPeerAddr or the strutucture that I use should also be saved in an SPI EEPROM, what do you think that should be the error?


    Regards

    Ralph

  • Ralph,

    i am not sure where the problem could be. Is it possible to get the screen capture of memory window showing the INFO memory in your application after calling  nv_obj_write_nwk_cfg() and also compare it with the memory windows showing the content of sPersistInfo variable in nwk.c?

  • Dear Leo,

    As you suggest, below is the data:

    Any sugestions?

    regards,

  • Ralph, taking a quick look at the memory dump, it seems that the content of the INFO memory acter calling nv_obj_write_nwk_cfg() is quite ok. The peer address is saved as "0x06 0x49 0x54 0x4F" in the info memory. The only thing is that if you use my example as is, it should be actually "0x4C 0x49 0x54 0x4F" ("LITO"). The first byte is different - i am not sure whether you change it on purpose or it is corrupted.

    So after calling nv_obj_write_nwk_cfg(), does the content of INFO memory stay the same after power cycle?

  • Dear Leo,

    The first byte was changed by me, the intention is that this first byte is as an identifier (ID) of the End Device.

    Also, in fact I can read (and also write) the correct configuration but only if I put the DNUM_CONNECTIONS variable at most at 3, if I put higher, for example 4 I can't write it correctly and I read zeros. Only problem, I need at least 7 connections. Is there any way to workaround this issue?

    Regards

    Ralph

  • Hi Ralph,

    maybe it is because the INFO memory is not enough to store 7 connections. I believe i used only INFO B-D which has in total 3*64  = 192 bytes. You need to store the connection somewhere else then in the main code memory if this is not enough.

  • Dear Leo,

    Finally I got the point, the problem was in the functions of writing to flash.

    Has I have to use several segments in this case I use 3 segments to save all the information the original code provided in your example can only save in one segment, also, it only erases only one segment.

    So changing your code to:

    bool nv_obj_write_nwk_cfg(void* nwk_cfg, uint16_t len)
    {
      bool ret = false;  
      uint8_t *Flash_ptr = (uint8_t*) INFO_FLASH_NWK_CFG_START_ADDR;
      uint8_t *data;
      uint16_t i=0, blk_wrt_cnt;
     
      size_msg_store = len;
      if((nwk_cfg != NULL) && (len <= INFO_FLASH_NWK_CFG_SIZE - 4))
      {
        // erase the memory segment
        nv_obj_erase_flash();
     
        // write the signature
        /* start block write */
        FCTL3 = FWKEY;                  // Clear Lock bit
        FCTL1 = FWKEY + WRT;            // Set WRT bit for write operation
          
        *Flash_ptr++ = 'S';             // Write signature
        *Flash_ptr++ = 'M';             // Write signature
        *Flash_ptr++ = 'P';             // Write signature
        *Flash_ptr++ = 'L';             // Write signature
     
        FCTL1 = FWKEY;                  // Clear WRT bit
        FCTL3 = FWKEY + LOCK;           // Set LOCK bit
     
        // write the data
        data = (uint8_t*) nwk_cfg;
        do
        {
          /* start block write */
          FCTL3 = FWKEY;                  // Clear Lock bit
          FCTL1 = FWKEY + WRT;            // Set BLKWRT + WRT bit for block write operation
          
          blk_wrt_cnt = 0;
          
          for (blk_wrt_cnt = 0; (blk_wrt_cnt < 64) && (i<len); i++, blk_wrt_cnt++)
          {
            *Flash_ptr++ = *data++;         // Write value to flash
          }
          FCTL1 = FWKEY;                    // Clear WRT bit
          FCTL3 = FWKEY + LOCK;             // Set LOCK bit
        }while(i<len);
        
        // return success
        ret = true;
      }
       
      return ret;
    }

    void nv_obj_erase_flash(void)
    {
      uint8_t *Flash_ptr = (uint8_t*) INFO_FLASH_NWK_CFG_START_ADDR;
      uint8_t i;

      // erase segment B, C, D
      for(i = 0; i < 3; i++)
      {
        FCTL3 = FWKEY;                            // Clear Lock bit
        FCTL1 = FWKEY + ERASE;              // Set Erase bit, allow interrupts
        *Flash_ptr = 0;                           // Dummy write to erase Flash seg
        Flash_ptr += 64;
        FCTL1 = FWKEY;                            // Clear ERASE bit
        FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
      }

    }

    with this I can save the 7 connections that I need :)

    Thanks Leo,

    Regards.

    Ralph

  • Ralph,

    glad to hear that you have solved the problem. You are right, i forgot that the function only erases one INFO section, so if you have bigger data structure, you need to erase also the other ones.