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.

RTOS/CC1310: NVS Driver to write new application

Part Number: CC1310
Other Parts Discussed in Thread: CC2650

Tool/software: TI-RTOS

Hi,

In my product I have two projects stored: bootloader and application.

The bootloader is stored at address 0x00000 of the flash memory.

The application is stored at address 0x10000 of the flash memory.

The bootloader must receive a .bin file containing a new application and replace the original application stored at address 0x10000.

In order to do that, I need a way to write to the CC1310 flash memory.

I found a example in the thread below:

e2e.ti.com/.../528113

I tried the example and it worked well. I was able to write and read from the flash memory.

However, in my case I need to write a large among of data, so a don't want to use a RAM buffer (as showed in the example).

I don't know how to configure the driver to not use a RAM buffer. I tried as follows:

//char myCopyBlock[4096]; Commented!
const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[CC1310_LAUNCHXL_NVSCOUNT] = {
{
        .block = (void *)0x10000,   // Address where the application starts
        .blockSize = 0x10000,       // Size of application
        .copyBlock = NULL,          // Don't want to use RAM!
        .isRam = false              // Don't want to use RAM!
    }
};


I didn't work.

How can I configure it to write to flash memory without use a copy of previous data?

Is there a better way to do what I need? Maybe another driver?

  • Hi Mad River,

    I don't see why you wouldn't want to use the RAM. The memory is volatile and you recover whatever you have used once you reboot your device into the application.

    The bootloader should be very small and the only RAM space would be to store the binary data.

    If that's not the case, can you explain why you don't want to use the RAM to store the Flash data/

    Regards,
    Michel
  • Michel Solecki said:
    Hi Mad River,

    I don't see why you wouldn't want to use the RAM. The memory is volatile and you recover whatever you have used once you reboot your device into the application.

    The bootloader should be very small and the only RAM space would be to store the binary data.

    If that's not the case, can you explain why you don't want to use the RAM to store the Flash data/

    Regards,
    Michel

    Hi Michel,

    As far I could understand, the copyBlock size must be equal of the block size.

    The block size I want to address is almost the entire flash. Right now I am using half of the flash to store the bootloader and the other half to store the application,

    In the future I want to reduce the bootloader size for 1/4 of the flash and use the other 3/4 to application.

    In the first case, the NVS driver requires 0x10000 bytes to be allocated to copyBlock. It is impracticable.

    Please, let me known if I am missing something.

    Ramsay said:
    Hi Mad River,

    Your attributes look okay. Please provide some details on the failure. Are you getting an error code from the NVI API? Is the data not written correctly? Does the program crash?

    Thank you,
    ~Ramsey

    Hi Ramsay,

    NVS_write() is returning NVS_ECOPYBLOCK.

    As you could see, I attributed NULL to the copyBlock. Inside the write function we have:

        /* If not an erase operation, the copy block must not be NULL */
        if ((buffer != NULL) && (hwAttrs->copyBlock == NULL)) {
            Log_warning1("NVS:(%p) copyBlock must be non-NULL.",
                    (IArg)(hwAttrs->block));
            return (NVS_ECOPYBLOCK);
        }

    That is my problem. I don't know how to solve it.

    I am trying to use  <driverlib/flash.h> directly. But can't find examples about it.

  • Mad River,

    Your device has 128KiB of flash. You have partitioned half for the boot loader and half for the application. You want the boot loader to access the 64KiB of flash allocated to the application so it can update the firmware. Have I got this correct?

    I believe your NVS attribute configuration is correct. Unfortunately, the copyBlock must be the same size as the flash block, 64KiB in this case. It would not be possible for the boot loader to allocate a 64KiB copy buffer, there is only 20KiB of RAM. So you must set isRam to false.

    I'm guessing your are calling NVS_write() with NVS_WRITE_ERASE. If so, it will fail because this option requires a copy buffer. To work around this, I suggest you call NVS_write() with a null buffer pointer and no flags. This indicates you simply want to erase the flash. Follow this with a call to NVS_write() and with NVS_WRITE_VALIDATE.

    If this works, great. If not, I suspect the next issue will be the flash sector size. On the CC1310, the flash sector size is 4KiB. I suggest you update the flash by operating on one flash sector at a time, not the entire 64KiB block at once. In other words, call NVS_write() once for each flash sector. Do this for the erase as well. I believe this comes about because the lower level driver operates only on flash sectors. I don't see any code in the NVS driver which breaks down the given block into sectors.

    The NVS API is still under development. It is still going through design review. As such, some of the APIs will change in future releases, so please be mindful of this. We will consider your use-case in our design review. Our goal is to make it easy to use and flexible for all customers. Thank you for your patients.

    ~Ramsey

  • Hi Ramsey,

    Your device has 128KiB of flash. You have partitioned half for the boot loader and half for the application. You want the boot loader to access the 64KiB of flash allocated to the application so it can update the firmware. Have I got this correct?

    You got it correct!

    If this works, great. If not, I suspect the next issue will be the flash sector size. On the CC1310, the flash sector size is 4KiB. I suggest you update the flash by operating on one flash sector at a time, not the entire 64KiB block at once. In other words, call NVS_write() once for each flash sector. Do this for the erase as well. I believe this comes about because the lower level driver operates only on flash sectors. I don't see any code in the NVS driver which breaks down the given block into sectors.

    Currently I am trying to do exactly that, but using the <driverlib/flash.h>.
    I am making use of functions such: FlashSectorErase() and FlashProgram().
    Questions:

    1. Is there any issues in using <driverlib/flash.h> instead of NVS driver??
    2. In case of the NVS driver, to erase and program one sector each time I need to dinamically change the block address. In the example it is attributed at compile time. Can I configure it at runtime?

  • Hi Mad River,

    Mad River said:
    1. Is there any issues in using <driverlib/flash.h> instead of NVS driver??

    I have used the <driverlib/flach.h> with the CC2650 (not used in a bootloader but to store application data) and it works very well.

    The only precaution to use is the pages that you will be using to store your application.

    • The last page of the device contains the CCA and should not be erased. This is needed for you device to work.
    • If you use the osal_snv (not sure if this is the same thing as the NVS that you're talking about), but that reserves another page. I believe that you can use that page, but I would ask TI to confirm this statement.

    Regards,

    Michel

  • Mad River,

    Using the NVS driver gives you a level of abstraction from the low-level device peripheral libraries. In theory, if your application uses the TI-Drivers, then it will be easier to move your application to another device in the future. If you make direct calls to the CC13xxWare libraries in your application, then your code becomes tightly coupled to that device. So, you would give up this portability if you don't use the NVS driver.

    You must still define the entire 64KiB block of flash in your hardware attributes. But when you make your call to NVS_write(), set the offset to the address of the flash sector, and the buffer size to the flash sector size (4KiB). This way you will update only one flash sector at a time.

    Your NVS block is 64KiB starting at address 0x10000. You sector layout would look like this:

    Sector  Address
    ---------------------
       0    0x10000
       1    0x11000
       2    0x12000
      ...   ...
      15    0x1F000

    You would invoke NVS_write() as follows to update one sector at a time.

    NVS_write(h, 0x0000, buffer, 0x1000, NVS_WRITE_VALIDATE) /* write sector 0 */
    NVS_write(h, 0x1000, buffer, 0x1000, NVS_WRITE_VALIDATE) /* write sector 1 */
    NVS_write(h, 0x2000, buffer, 0x1000, NVS_WRITE_VALIDATE) /* write sector 2 */

    I have not tried this. Let me know if it works.

    ~Ramsey

  • I will try this as soon as possible!

    Thank you very much!

  • Ramsey said:

    I have not tried this. Let me know if it works.

    ~Ramsey

    Hi Ramsey,

    I tried the following code, but it never returns from NVS_write.

    Can you check it, please?

    Void heartBeatFxn(UArg arg0, UArg arg1)
    {
        NVS_Handle nvsHandle;
        uint32_t status;
    
        /* Confirming the sector size on this device is 4096 */
        if (FlashSectorSizeGet() != 4096) {
            System_abort("Oops! The sector size is not 4096");
        }
    
        NVS_init();
        nvsHandle = NVS_open(CC1310_LAUNCHXL_NVS1F000, NULL);
    
        // Write a known pattern
        memset(buffer, 0xAA, sizeof(buffer));
        status = NVS_write(nvsHandle, 0x0000, buffer, sizeof(buffer), NVS_WRITE_VALIDATE);
        if (status != NVS_SOK) {
            System_abort("NVS_write failed");
        }
    
        // Write a known pattern
        memset(buffer, 0x55, sizeof(buffer));
        status = NVS_write(nvsHandle, 0x1000, buffer, sizeof(buffer), NVS_WRITE_VALIDATE);
        if (status != NVS_SOK) {
            System_abort("NVS_write failed");
        }
    
        // Write a known pattern
        memset(buffer, 0xCC, sizeof(buffer));
        status = NVS_write(nvsHandle, 0x2000, buffer, sizeof(buffer), NVS_WRITE_VALIDATE);
        if (status != NVS_SOK) {
            System_abort("NVS_write failed");
        }
    
        // Validate sector
        memset(buffer, 0x00, sizeof(buffer));
        status = NVS_read(nvsHandle, 0x0000, buffer, sizeof(buffer));
        if (status != NVS_SOK) {
            System_abort("NVS_read failed");
        }
    
        // Validate sector
        memset(buffer, 0x00, sizeof(buffer));
        status = NVS_read(nvsHandle, 0x1000, buffer, sizeof(buffer));
        if (status != NVS_SOK) {
            System_abort("NVS_read failed");
        }
    
        // Validate sector
        memset(buffer, 0x00, sizeof(buffer));
        status = NVS_read(nvsHandle, 0x2000, buffer, sizeof(buffer));
        if (status != NVS_SOK) {
            System_abort("NVS_read failed");
        }
    
        while (1) {
            Task_sleep((UInt)arg0);
            PIN_setOutputValue(ledPinHandle, Board_LED1,
                               !PIN_getOutputValue(Board_LED1));
        }
    }

    I have tried with all these configurations:

    // 1
    const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[CC1310_LAUNCHXL_NVSCOUNT] = {
    {
            .block = (void *)0x10000,
            .blockSize = 0x10000,
            .copyBlock = NULL,
            .isRam = false
        }
    };

    // 2
    char myCopyBlock[4096];
    const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[CC1310_LAUNCHXL_NVSCOUNT] = {
    {
            .block = (void *)0x10000,
            .blockSize = 0x10000,
            .copyBlock = myCopyBlock,
            .isRam = false
        }
    };

    // 3
    char myCopyBlock[4096];
    const NVSCC26XX_HWAttrs nvsCC26xxHWAttrs[CC1310_LAUNCHXL_NVSCOUNT] = {
    {
            .block = (void *)0x10000,
            .blockSize = 0x10000,
            .copyBlock = myCopyBlock,
            .isRam = true
        }
    };

  • Mad River,

    I have discovered that in NVSCC26XX_open() (which is called from NVS_open(), even on the CC1310), there is a check that the block size cannot be larger than the flash sector size.

    /* The block cannot be larger than a flash page */
    if ((uint32_t)(hwAttrs->blockSize) > FlashSectorSizeGet()) {
        Semaphore_post(Semaphore_handle(&writeSem));
                                                                               
        Log_warning1("NVS:(%p) blockSize must not be greater than page size.",
                (IArg)(hwAttrs->block));
        return (NULL);
    }

    My guess is that the NVS_open() returned a NULL handle. Please check your handle value.

    I'm afraid you will have to create 16 blocks of 4KiB each to cover your flash memory region. I will report this issue.

    Another point I see, is that you are not erasing the flash before writing it. Keep in mind how flash memory works. When you erase it, all bits are set (0xFF). When you write, it can only clear bits. If you try to write the same memory again, it can only clear additional bits, but it cannot set any bits. So, if you write a 0xF0 followed by a write of 0x0F, the result will be 0x00. Since you are calling NVS_write() with NVS_WRITE_VALIDATE, the validate would fail. So, be sure to erase the memory with a call to NVS_write() with a NULL buffer before writing the actual data.

    Finally, the data buffer must be aligned on a 4 byte boundary. Be sure to align your buffer definition.

    #pragma DATA_ALIGN(buffer, 4)
    char buffer[0x1000];

    So, for now you will have to create 16 blocks in your HWAttrs structure. You will have to open 16 handles. However, since you will be updating one block at a time, you can allocate one copy block to share with all 16 flash blocks. This allows you to use the NVS_WRITE_ERASE flag and so your code becomes simpler again. You don't need a separate erase step.

    ~Ramsey

  • Ramsey said:

    Mad River,

    I have discovered that in NVSCC26XX_open() (which is called from NVS_open(), even on the CC1310), there is a check that the block size cannot be larger than the flash sector size.

    /* The block cannot be larger than a flash page */
    if ((uint32_t)(hwAttrs->blockSize) > FlashSectorSizeGet()) {
        Semaphore_post(Semaphore_handle(&writeSem));
                                                                               
        Log_warning1("NVS:(%p) blockSize must not be greater than page size.",
                (IArg)(hwAttrs->block));
        return (NULL);
    }

    My guess is that the NVS_open() returned a NULL handle. Please check your handle value.

    I'm afraid you will have to create 16 blocks of 4KiB each to cover your flash memory region. I will report this issue.

    Another point I see, is that you are not erasing the flash before writing it. Keep in mind how flash memory works. When you erase it, all bits are set (0xFF). When you write, it can only clear bits. If you try to write the same memory again, it can only clear additional bits, but it cannot set any bits. So, if you write a 0xF0 followed by a write of 0x0F, the result will be 0x00. Since you are calling NVS_write() with NVS_WRITE_VALIDATE, the validate would fail. So, be sure to erase the memory with a call to NVS_write() with a NULL buffer before writing the actual data.

    Finally, the data buffer must be aligned on a 4 byte boundary. Be sure to align your buffer definition.

    #pragma DATA_ALIGN(buffer, 4)
    char buffer[0x1000];

    So, for now you will have to create 16 blocks in your HWAttrs structure. You will have to open 16 handles. However, since you will be updating one block at a time, you can allocate one copy block to share with all 16 flash blocks. This allows you to use the NVS_WRITE_ERASE flag and so your code becomes simpler again. You don't need a separate erase step.

    ~Ramsey

    I ended up implementing my bootloader using the flash.h driver.

    It is working pretty well.

    Anyway, thank you very much for the support.

    I think I will wait for a new release of the NVS driver and use it in my next project.

    Do you know when it will be release?

  • Mad River,

    The official NVS driver support is planned for June/July 2017. I've been told the NVS API will change, but it will add functionality, not remove any.

    ~Ramsey