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: How to use Erase command after OTA is called in CC2530

Part Number: CC2530
Other Parts Discussed in Thread: , Z-STACK

Hi,

I want to erase External Flash chip for every new OTA call is happened in CC2530.

External Flash is used to store the incoming image in OTA once it is received full image, the image will be copied in the application memory of CC2530. In reference design of SmartRF05EB, M25PE20(Micron) chipset is used as External memory chip. With this chipset OTA is working fine. 

We have used "W25X20CL"(winbond) as external flash which has similar pins and commands also same. With this chip OTA was not worked initially, because this chip doesn't have "PAGE WRITE-0x0A" command, it has only "PAGE PROGRAM-0x02" command. But micron has both of the commands. 

After changing "XNV_WRPG_CMD" as 0x02 from 0x0A, OTA was worked. But it happened only once. Repeated OTA upgrade is not working. 

For the first time there is nothing in External Flash so OTA working fine, but in second time the data will be overwritten.Then there is a problem with reading or problem in written data so it's keep on fails. 

So I am thinking to erase external flash whenever OTA functionality is initialized, so there won't be any problem in write/read operations. 

In short explanation:

Hex(Bootloader+ Application) is flashed in CC2530

1. OTAserver--> Image1--> OTAClient--> OTA 100%complete-->Load time--> Rebooted & image1 is running.

2. OTAserver--> Image2--> OTAClient--> OTA 100%complete-->Load time--> OTA from 0% -->OTA 100%complete-->Load time--> OTA from 0% -->OTA 100%complete-->Load time--> OTA from 0% --> keep on repeating.

/******************************************************************************
  Filename:       hal_ota.c
  Revised:        $Date: 2010-11-18 08:22:50 -0800 (Thu, 18 Nov 2010) $
  Revision:       $Revision: 24438 $

  Description:    This module contains optionally-compiled Boot Code to support
                  OTA. The rest of the functionality is the H/W specific drivers
                  to read/write the flash/NV containing the ACTIVE and the
                  DOWNLOADED images.
  Notes:          Targets the Texas Instruments CC253x family of processors.


  Copyright 2010 Texas Instruments Incorporated. All rights reserved.

  IMPORTANT: Your use of this Software is limited to those specific rights
  granted under the terms of a software license agreement between the user
  who downloaded the software, his/her employer (which must be your employer)
  and Texas Instruments Incorporated (the "License").  You may not use this
  Software unless you agree to abide by the terms of the License. The License
  limits your use, and you acknowledge, that the Software may not be modified,
  copied or distributed unless embedded on a Texas Instruments microcontroller
  or used solely and exclusively in conjunction with a Texas Instruments radio
  frequency transceiver, which is integrated into your product.  Other than for
  the foregoing purpose, you may not use, reproduce, copy, prepare derivative
  works of, modify, distribute, perform, display or sell this Software and/or
  its documentation for any purpose.

  YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
  PROVIDED �AS IS� WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
  INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
  NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
  TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
  NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
  LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
  INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
  OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
  OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
  (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.

  Should you have any questions regarding your right to use this Software,
  contact Texas Instruments Incorporated at www.TI.com.
******************************************************************************/

/******************************************************************************
 * INCLUDES
 */
#include "comdef.h"
#include "hal_board_cfg.h"
#include "hal_dma.h"
#include "hal_flash.h"
#include "hal_ota.h"
#include "hal_types.h"

#include "ota_common.h"

/******************************************************************************
 * CONSTANTS
 */
#if HAL_OTA_XNV_IS_SPI
#define XNV_STAT_CMD  0x05
#define XNV_WREN_CMD  0x06
#define XNV_WRPG_CMD  0x02   //Page Program command changed to 0x02 from 0x0A
#define XNV_READ_CMD  0x0B

#define XNV_STAT_WIP  0x01
#endif

/******************************************************************************
 * TYPEDEFS
 */
typedef struct
{
  uint16 crc[2];
  uint32 programSize;
} OTA_CrcControl_t;

/******************************************************************************
 * LOCAL VARIABLES
 */
OTA_CrcControl_t OTA_crcControl;

#if HAL_OTA_BOOT_CODE
halDMADesc_t dmaCh0;
#endif

/******************************************************************************
 * LOCAL FUNCTIONS
 */
static uint16 runPoly(uint16 crc, uint8 val);

#if HAL_OTA_XNV_IS_SPI
static void HalSPIRead(uint32 addr, uint8 *pBuf, uint16 len);
static void HalSPIWrite(uint32 addr, uint8 *pBuf, uint16 len);
static void xnvSPIWrite(uint8 ch);
#endif

#if HAL_OTA_BOOT_CODE
static void dl2rc(void);
static uint16 crcCalc(void);

/******************************************************************************
 * @fn      main
 *
 * @brief   ISR for the reset vector.
 *
 * @param   None.
 *
 * @return  None.
 */
#pragma location="NEAR_CODE"
void main(void)
{
  HAL_BOARD_INIT();
#if HAL_OTA_XNV_IS_SPI
  XNV_SPI_INIT();
#endif
  /* This is in place of calling HalDmaInit() which would require init of the
   * other 4 DMA descriptors in addition to just Channel 0.
   */
  HAL_DMA_SET_ADDR_DESC0( &dmaCh0 );

  while (1)
  {
    HalFlashRead(HAL_OTA_CRC_ADDR / HAL_FLASH_PAGE_SIZE,
                 HAL_OTA_CRC_ADDR % HAL_FLASH_PAGE_SIZE,
                 (uint8 *)&OTA_crcControl, sizeof(OTA_crcControl));

    if (OTA_crcControl.crc[0] == OTA_crcControl.crc[1])
    {
      break;
    }
    else if ((OTA_crcControl.crc[0] != 0) && (OTA_crcControl.crc[0] == crcCalc()))
    {
      OTA_crcControl.crc[1] = OTA_crcControl.crc[0];
      HalFlashWrite((HAL_OTA_CRC_ADDR / HAL_FLASH_WORD_SIZE), (uint8 *)OTA_crcControl.crc, 1);
    }
    else
    {
      dl2rc();
    }
  }

  // Simulate a reset for the Application code by an absolute jump to location 0x0800.
  asm("LJMP 0x800\n");
}

/******************************************************************************
 * @fn      dl2rc
 *
 * @brief   Copy the DL image to the RC image location.
 *
 *  NOTE:   Assumes that DL image ends on a flash word boundary.
 *
 * @param   None.
 *
 * @return  None.
 */
static void dl2rc(void)
{
  uint32 oset;
  OTA_SubElementHdr_t subElement;
  OTA_ImageHeader_t header;
  uint16 addr = HAL_OTA_RC_START / HAL_FLASH_WORD_SIZE;
  uint8 buf[4];

  // Determine the length and starting point of the upgrade image
  HalOTARead(0, (uint8 *)&header, sizeof(OTA_ImageHeader_t), HAL_OTA_DL);
  HalOTARead(header.headerLength, (uint8*)&subElement, OTA_SUB_ELEMENT_HDR_LEN, HAL_OTA_DL);

  for (oset = 0; oset < subElement.length; oset += HAL_FLASH_WORD_SIZE)
  {
    HalOTARead(oset + header.headerLength + OTA_SUB_ELEMENT_HDR_LEN, buf, HAL_FLASH_WORD_SIZE, HAL_OTA_DL);
    if ((addr % (HAL_FLASH_PAGE_SIZE / HAL_FLASH_WORD_SIZE)) == 0)
    {
      HalFlashErase(addr / (HAL_FLASH_PAGE_SIZE / HAL_FLASH_WORD_SIZE));
    }
    HalFlashWrite(addr++, buf, 1);
  }
}

/******************************************************************************
 * @fn      crcCalc
 *
 * @brief   Run the CRC16 Polynomial calculation over the RC image.
 *
 * @param   None.
 *
 * @return  The CRC16 calculated.
 */
static uint16 crcCalc()
{
  uint32 oset;
  uint16 crc = 0;

  // Run the CRC calculation over the active body of code.
  for (oset = 0; oset < OTA_crcControl.programSize; oset++)
  {
    if ((oset < HAL_OTA_CRC_OSET) || (oset >= HAL_OTA_CRC_OSET + 4))
    {
      uint8 buf;
      HalOTARead(oset, &buf, 1, HAL_OTA_RC);
      crc = runPoly(crc, buf);
    }
  }

  return crc;
}
#endif //HAL_OTA_BOOT_CODE

/******************************************************************************
 * @fn      runPoly
 *
 * @brief   Run the CRC16 Polynomial calculation over the byte parameter.
 *
 * @param   crc - Running CRC calculated so far.
 * @param   val - Value on which to run the CRC16.
 *
 * @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;
}

/******************************************************************************
 * @fn      HalOTAChkDL
 *
 * @brief   Run the CRC16 Polynomial calculation over the DL image.
 *
 * @param   None
 *
 * @return  SUCCESS or FAILURE.
 */
uint8 HalOTAChkDL(uint8 dlImagePreambleOffset)
{
 (void)dlImagePreambleOffset;  // Intentionally unreferenced parameter

  uint32 oset;
  uint16 crc = 0;
  OTA_CrcControl_t crcControl;
  OTA_ImageHeader_t header;
  uint32 programStart;

#if HAL_OTA_XNV_IS_SPI
  XNV_SPI_INIT();
#endif

  // Read the OTA File Header
  HalOTARead(0, (uint8 *)&header, sizeof(OTA_ImageHeader_t), HAL_OTA_DL);

  // Calculate the update image start address
  programStart = header.headerLength + OTA_SUB_ELEMENT_HDR_LEN;

  // Get the CRC Control structure
  HalOTARead(programStart + HAL_OTA_CRC_OSET, (uint8 *)&crcControl, sizeof(crcControl), HAL_OTA_DL);

  if ((crcControl.programSize > HAL_OTA_DL_MAX) || (crcControl.programSize == 0))
  {
    return FAILURE;
  }

  // Run the CRC calculation over the downloaded image.
  for (oset = 0; oset < crcControl.programSize; oset++)
  {
    if ((oset < HAL_OTA_CRC_OSET) || (oset >= HAL_OTA_CRC_OSET+4))
    {
      uint8 buf;
      HalOTARead(oset + programStart, &buf, 1, HAL_OTA_DL);
      crc = runPoly(crc, buf);
    }
  }

  return (crcControl.crc[0] == crc) ? SUCCESS : FAILURE;
}

/******************************************************************************
 * @fn      HalOTAInvRC
 *
 * @brief   Invalidate the active image so that the boot code will instantiate
 *          the DL image on the next reset.
 *
 * @param   None.
 *
 * @return  None.
 */
void HalOTAInvRC(void)
{
  uint16 crc[2] = {0,0xFFFF};
  HalFlashWrite((HAL_OTA_CRC_ADDR / HAL_FLASH_WORD_SIZE), (uint8 *)crc, 1);
}

/******************************************************************************
 * @fn      HalOTARead
 *
 * @brief   Read from the storage medium according to image type.
 *
 * @param   oset - Offset into the monolithic image.
 * @param   pBuf - Pointer to the buffer in which to copy the bytes read.
 * @param   len - Number of bytes to read.
 * @param   type - Which image: HAL_OTA_RC or HAL_OTA_DL.
 *
 * @return  None.
 */
void HalOTARead(uint32 oset, uint8 *pBuf, uint16 len, image_t type)
{
  if (HAL_OTA_RC != type)
  {
#if HAL_OTA_XNV_IS_INT
    preamble_t preamble;

    HalOTARead(PREAMBLE_OFFSET, (uint8 *)&preamble, sizeof(preamble_t), HAL_OTA_RC);
    oset += HAL_OTA_RC_START + HAL_OTA_DL_OSET;
#elif HAL_OTA_XNV_IS_SPI
    oset += HAL_OTA_DL_OSET;
    HalSPIRead(oset, pBuf, len);
    return;
#endif
  }
  else
  {
    oset += HAL_OTA_RC_START;
  }

  HalFlashRead(oset / HAL_FLASH_PAGE_SIZE, oset % HAL_FLASH_PAGE_SIZE, pBuf, len);
}

/******************************************************************************
 * @fn      HalOTAWrite
 *
 * @brief   Write to the storage medium according to the image type.
 *
 *  NOTE:   Destructive write on page boundary! When writing to the first flash word
 *          of a page boundary, the page is erased without saving/restoring the bytes not written.
 *          Writes anywhere else on a page assume that the location written to has been erased.
 *
 * @param   oset - Offset into the monolithic image, aligned to HAL_FLASH_WORD_SIZE.
 * @param   pBuf - Pointer to the buffer in from which to write.
 * @param   len - Number of bytes to write. If not an even multiple of HAL_FLASH_WORD_SIZE,
 *                remainder bytes are overwritten with garbage.
 * @param   type - Which image: HAL_OTA_RC or HAL_OTA_DL.
 *
 * @return  None.
 */
void HalOTAWrite(uint32 oset, uint8 *pBuf, uint16 len, image_t type)
{
  if (HAL_OTA_RC != type)
  {
#if HAL_OTA_XNV_IS_INT
    oset += HAL_OTA_RC_START + HAL_OTA_DL_OSET;
#elif HAL_OTA_XNV_IS_SPI
    oset += HAL_OTA_DL_OSET;
    HalSPIWrite(oset, pBuf, len);
    return;
#endif
  }
  else
  {
    oset += HAL_OTA_RC_START;
  }

  if ((oset % HAL_FLASH_PAGE_SIZE) == 0)
  {
    HalFlashErase(oset / HAL_FLASH_PAGE_SIZE);
  }

  HalFlashWrite(oset / HAL_FLASH_WORD_SIZE, pBuf, len / HAL_FLASH_WORD_SIZE);
}

/******************************************************************************
 * @fn      HalOTAAvail
 *
 * @brief   Determine the space available for downloading an image.
 *
 * @param   None.
 *
 * @return  Number of bytes available for storing an OTA image.
 */
uint32 HalOTAAvail(void)
{
  return HAL_OTA_DL_MAX - HAL_OTA_DL_OSET;
}

#if HAL_OTA_XNV_IS_SPI
/******************************************************************************
 * @fn      xnvSPIWrite
 *
 * @brief   SPI write sequence for code size savings.
 *
 * @param   ch - The byte to write to the SPI.
 *
 * @return  None.
 */
static void xnvSPIWrite(uint8 ch)
{
  XNV_SPI_TX(ch);
  XNV_SPI_WAIT_RXRDY();
}

/******************************************************************************
 * @fn      HalSPIRead
 *
 * @brief   Read from the external NV storage via SPI.
 *
 * @param   addr - Offset into the external NV.
 * @param   pBuf - Pointer to buffer to copy the bytes read from external NV.
 * @param   len - Number of bytes to read from external NV.
 *
 * @return  None.
 *****************************************************************************/
static void HalSPIRead(uint32 addr, uint8 *pBuf, uint16 len)
{
#if !HAL_OTA_BOOT_CODE
  uint8 shdw = P1DIR;
  halIntState_t his;
  HAL_ENTER_CRITICAL_SECTION(his);
  P1DIR |= BV(3);
#endif

  XNV_SPI_BEGIN();
  do
  {
    xnvSPIWrite(XNV_STAT_CMD);
  } while (XNV_SPI_RX() & XNV_STAT_WIP);
  XNV_SPI_END();
  asm("NOP"); asm("NOP");

  XNV_SPI_BEGIN();
  xnvSPIWrite(XNV_READ_CMD);
  xnvSPIWrite(addr >> 16);
  xnvSPIWrite(addr >> 8);
  xnvSPIWrite(addr);
  xnvSPIWrite(0);

  while (len--)
  {
    xnvSPIWrite(0);
    *pBuf++ = XNV_SPI_RX();
  }
  XNV_SPI_END();

#if !HAL_OTA_BOOT_CODE
  P1DIR = shdw;
  HAL_EXIT_CRITICAL_SECTION(his);
#endif
}

/******************************************************************************
 * @fn      HalSPIWrite
 *
 * @brief   Write to the external NV storage via SPI.
 *
 * @param   addr - Offset into the external NV.
 * @param   pBuf - Pointer to the buffer in from which to write bytes to external NV.
 * @param   len - Number of bytes to write to external NV.
 *
 * @return  None.
 *****************************************************************************/
static void HalSPIWrite(uint32 addr, uint8 *pBuf, uint16 len)
{
  uint8 cnt;
#if !HAL_OTA_BOOT_CODE
  uint8 shdw = P1DIR;
  halIntState_t his;
  HAL_ENTER_CRITICAL_SECTION(his);
  P1DIR |= BV(3);
#endif

  while (len)
  {
    XNV_SPI_BEGIN();
    do
    {
      xnvSPIWrite(XNV_STAT_CMD);
    } while (XNV_SPI_RX() & XNV_STAT_WIP);
    XNV_SPI_END();
    asm("NOP"); asm("NOP");

    XNV_SPI_BEGIN();
    xnvSPIWrite(XNV_WREN_CMD);
    XNV_SPI_END();
    asm("NOP"); asm("NOP");

    XNV_SPI_BEGIN();
    xnvSPIWrite(XNV_WRPG_CMD);
    xnvSPIWrite(addr >> 16);
    xnvSPIWrite(addr >> 8);
    xnvSPIWrite(addr);

    // Can only write within any one page boundary, so prepare for next page write if bytes remain.
    cnt = 0 - (uint8)addr;
    if (cnt)
    {
      addr += cnt;
    }
    else
    {
      addr += 256;
    }

    do
    {
      xnvSPIWrite(*pBuf++);
      cnt--;
      len--;
    } while (len && cnt);
    XNV_SPI_END();
  }

#if !HAL_OTA_BOOT_CODE
  P1DIR = shdw;
  HAL_EXIT_CRITICAL_SECTION(his);
#endif
}

#elif !HAL_OTA_XNV_IS_INT
#error Invalid Xtra-NV for OTA.
#endif

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

**  code is hal_ota.c in zstack

Waiting for quick response.

  • If you dont need the contents of external SPI anymore you can delete it entirely before storing the new image being received OTA for the upgrade, quickly looking at the winbond SPI flash manual there are commands for sector and block erase which you may be able to use. However the method you propose of erasing the external flash completely before you start writing the new image will work if you dont have to use the old external flash contents anymore.
  • Thanks Suyash Jain...

    Which function should be used for Erasing the Flash entirely? And where that function should be called? If it is possible please add it in attached hal_ota.c file so that it will be helpful for me.

    As you mentioned in my another post, the issue is due to WinBond chip only. Because with micron and using same code I am not facing this issue.

  • I'm facing exactly the same issue here. I've been trying to use a different flash and replacing PAGE WRITE with PAGE PROGRAM made the OTA procedure start. However it doesn't seem to be able to run the new image (I edited a string on the display to recognise it) and after the image is downloaded completely the device restarts but doesn't run the new image previously downloaded and starts downloading it again despite the CRC check being successful. I'm experiencing the exactly same behaviour even with the Micron flash and the default PAGE WRITE command. I'm using the procedure and software described in Z-Stack Home 1.2.2a with 2 SmartRF05 boards v.1.8.1 + CC2530EM modules, one running the dongle software as Coordinator and the other one as End Device.
  • To debug this, I would recommended running first the out of box example application (no modifications) on the SmartRF05EB + CC2530. This should work, and then taking that as a reference expected behavior step by step compare against your application. Hopefully this will help resolve the issue.
  • Which function should be used for Erasing the Flash entirely? And where that function should be called? If it is possible please add it in attached hal_ota.c file so that it will be helpful for me.

    You can create a new function that you use to erase the flash right when you start the OTA download process.
    I would recommend referencing the "Z-Stack OTA Upgrade User's Guide.pdf" part of the Z-Stack install for details on the OTA process works and then you should be able to understand the code better and call this function at the right place.
  • I implemented the flash erase functionality and called it before the OTA upgrade starts. I tried it with flashes from different manufacturers and seems to work fine.

    Below the changes I made. Would be nice to get the TI approval on this.

    Thanks,

    John

    hal_ota.h

    .....
    
    void HalSPIEraseChip(void);
    void HalSPIChipWait(void);
    #endif

    hal_ota.c

    .....
    
    /* If flash does not support PAGE WRITE, use PAGE PROGRAM */
    #define XNV_PRGPG_ONLY 1
    
    /******************************************************************************
     * CONSTANTS
     */
    #if HAL_OTA_XNV_IS_SPI
    #define XNV_STAT_CMD  0x05
    #define XNV_WREN_CMD  0x06
    #define XNV_PRPG_CMD  0x02
    #define XNV_WRPG_CMD  0x0A
    #define XNV_ERCH_CMD  0xC7 //0x60
    #define XNV_READ_CMD  0x0B
    
    #define XNV_STAT_WIP  0x01
    #endif
    
    .....
    
    /******************************************************************************
     * @fn      HalSPIChipWait
     *
     * @brief   Wait for external NV storage to be ready.
     *
     * @param   none
     * @param   none
     *
     * @return  None.
     *****************************************************************************/
    void HalSPIChipWait(void)
    {
    #if !HAL_OTA_BOOT_CODE
      uint8 shdw = P1DIR;
      halIntState_t his;
      HAL_ENTER_CRITICAL_SECTION(his);
      P1DIR |= BV(3);
    #endif
    
      XNV_SPI_BEGIN();
      do
      {
        xnvSPIWrite(XNV_STAT_CMD);
      } while (XNV_SPI_RX() & XNV_STAT_WIP);
      XNV_SPI_END();
      asm("NOP"); asm("NOP");
    
    #if !HAL_OTA_BOOT_CODE
      P1DIR = shdw;
      HAL_EXIT_CRITICAL_SECTION(his);
    #endif
    }
    
    /******************************************************************************
     * @fn      HalSPIEraseChip
     *
     * @brief   Erase external NV storage via SPI.
     *
     * @param   none
     * @param   none
     *
     * @return  None.
     *****************************************************************************/
    void HalSPIEraseChip(void)
    {
    #if !HAL_OTA_BOOT_CODE
      uint8 shdw = P1DIR;
      halIntState_t his;
      HAL_ENTER_CRITICAL_SECTION(his);
      P1DIR |= BV(3);
    #endif
    
      XNV_SPI_BEGIN();
      do
      {
        xnvSPIWrite(XNV_STAT_CMD);
      } while (XNV_SPI_RX() & XNV_STAT_WIP);
      XNV_SPI_END();
      asm("NOP"); asm("NOP");
    
      XNV_SPI_BEGIN();
      xnvSPIWrite(XNV_WREN_CMD);
      XNV_SPI_END();
      asm("NOP"); asm("NOP");
    
      XNV_SPI_BEGIN();
      xnvSPIWrite(XNV_ERCH_CMD);
      XNV_SPI_END();
    
    #if !HAL_OTA_BOOT_CODE
      P1DIR = shdw;
      HAL_EXIT_CRITICAL_SECTION(his);
    #endif
    }
    
    .....
    
    /******************************************************************************
     * @fn      HalSPIWrite
     *
     * @brief   Write to the external NV storage via SPI.
     *
     * @param   addr - Offset into the external NV.
     * @param   pBuf - Pointer to the buffer in from which to write bytes to external NV.
     * @param   len - Number of bytes to write to external NV.
     *
     * @return  None.
     *****************************************************************************/
    static void HalSPIWrite(uint32 addr, uint8 *pBuf, uint16 len)
    {
      uint8 cnt;
    #if !HAL_OTA_BOOT_CODE
      uint8 shdw = P1DIR;
      halIntState_t his;
      HAL_ENTER_CRITICAL_SECTION(his);
      P1DIR |= BV(3);
    #endif
    
      while (len)
      {
        XNV_SPI_BEGIN();
        do
        {
          xnvSPIWrite(XNV_STAT_CMD);
        } while (XNV_SPI_RX() & XNV_STAT_WIP);
        XNV_SPI_END();
        asm("NOP"); asm("NOP");
    
        XNV_SPI_BEGIN();
        xnvSPIWrite(XNV_WREN_CMD);
        XNV_SPI_END();
        asm("NOP"); asm("NOP");
    
        XNV_SPI_BEGIN();
    #ifdef XNV_PRGPG_ONLY
        xnvSPIWrite(XNV_PRPG_CMD);
    #else
        xnvSPIWrite(XNV_WRPG_CMD);
    #endif
        xnvSPIWrite(addr >> 16);
        xnvSPIWrite(addr >> 8);
        xnvSPIWrite(addr);
    
        // Can only write within any one page boundary, so prepare for next page write if bytes remain.
        cnt = 0 - (uint8)addr;
        if (cnt)
        {
          addr += cnt;
        }
        else
        {
          addr += 256;
        }
    
        do
        {
          xnvSPIWrite(*pBuf++);
          cnt--;
          len--;
        } while (len && cnt);
        XNV_SPI_END();
      }
    
    #if !HAL_OTA_BOOT_CODE
      P1DIR = shdw;
      HAL_EXIT_CRITICAL_SECTION(his);
    #endif
    }

    zcl_yourapp.c

    .....
    
    /*********************************************************************
     * @fn      zclYourApp_ProcessOTAMsgs
     *
     * @brief   Called to process callbacks from the ZCL OTA.
     *
     * @param   none
     *
     * @return  none
     */
    static void zclYourApp_ProcessOTAMsgs( zclOTA_CallbackMsg_t* pMsg )
    {
      uint8 RxOnIdle;
    
      switch(pMsg->ota_event)
      {
      case ZCL_OTA_START_CALLBACK:
        if (pMsg->hdr.status == ZSuccess)
        {
          // Erase flash chip
          HalSPIEraseChip();
          Onboard_wait(0xFFFF);
          HalSPIChipWait();
    
          // Speed up the poll rate
          RxOnIdle = TRUE;
          ZMacSetReq( ZMacRxOnIdle, &RxOnIdle );
          NLME_SetPollRate( 2000 );
        }
        break;
    
    .....

  • Hello John

    By the time ZCL_OTA_START_CALLBACK is received zclOTA_ProcessQueryNextImageRsp has already sent a request for the next block, maybe the erasing is still in process when the next block is received, try increasing the time for the ZCL_OTA_IMAGE_BLOCK_REQ_DELAY_EVT sent in zclOTA_ProcessQueryNextImageRsp so that HalSPIEraseChip has enough time to finish before the next block is received.

    Regards,
    Dalila

  • Hi Dalila,

    thank you very much for taking the time to look at it. You are right it's better to be sure the flash is completely erased before the request for the next block is received. I had a better look at zcl_ota.c and I moved the HalSPIEraseChip call into zclOTA_ProcessQueryNextImageRsp, just before zclOTA_ImageUpgradeStatus changes to OTA_STATUS_IN_PROGRESS and the request for the next block is sent.
    Below the snippet.

    Thanks,
    John

    zcl_ota.c

    /******************************************************************************
    * @fn zclOTA_ProcessQueryNextImageRsp
    *
    * @brief Process received Query Next Image Response.
    *
    * @param pInMsg - pointer to the incoming message
    *
    * @return ZStatus_t
    */
    
    static ZStatus_t zclOTA_ProcessQueryNextImageRsp ( zclIncoming_t *pInMsg )
    
    .....
    
    if ( param.status == ZCL_STATUS_SUCCESS )
    {
    // parse message
    param.fileId.manufacturer = BUILD_UINT16 ( pData[0], pData[1] );
    pData += 2;
    param.fileId.type = BUILD_UINT16 ( pData[0], pData[1] );
    pData += 2;
    param.fileId.version = osal_build_uint32 ( pData, 4 );
    pData += 4;
    param.imageSize = osal_build_uint32 ( pData, 4 );
    
    // verify manufacturer id and image type
    if ( ( param.fileId.type == zclOTA_ImageType ) &&
    ( param.fileId.manufacturer == zclOTA_ManufacturerId ) )
    {
    // store file version and image size
    zclOTA_DownloadedFileVersion = param.fileId.version;
    zclOTA_DownloadedImageSize = param.imageSize;
    
    // initialize other variables
    zclOTA_FileOffset = 0;
    zclOTA_ClientPdState = ZCL_OTA_PD_MAGIC_0_STATE;
    
    // Erase flash chip
    HalSPIEraseChip();
    Onboard_wait(0xFFFF);
    HalSPIChipWait();
    
    // set state to 'in progress'
    zclOTA_ImageUpgradeStatus = OTA_STATUS_IN_PROGRESS;
    
    // store server address
    zclOTA_serverAddr = pInMsg->msg->srcAddr;
    
    // Store the file ID
    osal_memcpy ( &zclOTA_CurrentDlFileId, &param.fileId, sizeof ( zclOTA_FileID_t ) );
    
    // send image block request
    osal_start_timerEx ( zclOTA_TaskID, ZCL_OTA_IMAGE_BLOCK_REQ_DELAY_EVT, zclOTA_MinBlockReqDelay );
    status = ZCL_STATUS_CMD_HAS_RSP;
    
    osal_stop_timerEx ( zclOTA_TaskID, ZCL_OTA_IMAGE_QUERY_TO_EVT );
    }
    }
    
    .....