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.

CC2640R2F: Bootloading over UART - Sending binary image fails with COMMAND_RET_FLASH_FAIL

Part Number: CC2640R2F
Other Parts Discussed in Thread: UNIFLASH, CC2640

Hi, I am trying to flash an image to a 2640 device over UART using the bootloader. We are able to establish a connection to the bootloader and send commands successfully. However, we have not been unable to flash an image successfully. The process always fails on the CMD_GET_STATUS packet after a successful COMMAND_SEND_DATA is sent. The packet returns with an ACK, but the received status is a failure with the status code COMMAND_RET_FLASH_FAIL.  If I send only 1 byte of data in the COMMAND_SEND_DATA packet, we are able to send a few packets successfully. However, the process will always fail around the 8th byte in the image. I am sending a 2640 .bin image which was built using Code Composer Studio and the hex2bin script. I have validated the image using Uniflash, by flashing the image onto the device without issue. Is there a step that I am missing? 

Below is the code we are using. This code is for a cc3220 we are using to communicate with the cc2640. I have already validated that the packets are sent correctly. The entrypoint is the OTA2640() function:

#include <Board.h>
#include <device-control/device-control.h>
#include <errors/errors.h>
#include <file-system/file-system.h>
#include <logger/logger.h>
#include <stdio.h>
#include <ti/devices/cc32xx/inc/hw_types.h>
#include <ti/drivers/GPIO.h>
#include <ti/drivers/net/wifi/device.h>
#include <uart/uart.h>
#include <unistd.h>

#include <ti/devices/cc32xx/driverlib/prcm.h>

void start2640Bootloader()
{
    Stop2640();
    GPIO_write(1, 1);
    usleep(100000);
    Start2640();
    usleep(100000);
}

typedef struct bootloaderPacket bootloaderPacket;
struct bootloaderPacket
{
    uint8_t size;
    uint8_t checksum;
    uint8_t data[253];
};

void setChecksum(bootloaderPacket *blPacket)
{
    blPacket->checksum = 0;
    uint8_t i = 0;
    for (i = 0; i < blPacket->size - 2; i++)
    {
        blPacket->checksum += blPacket->data[i];
    }
}

bootloaderPacket createBootloaderPacket(uint8_t command, void *data, uint8_t dataSize)
{
    bootloaderPacket blPacket;

    blPacket.data[0] = command;
    memcpy(&blPacket.data[1], data, dataSize);

    blPacket.size = dataSize + 3;
    setChecksum(&blPacket);

    return blPacket;
}

error *SendBootloaderPacket(UARTHandle uartHandle, bootloaderPacket *blPacket)
{
    int8_t retVal = UART_write(uartHandle, blPacket, blPacket->size);
    if (retVal < 0)
    {
        return NewError("Unable to send bootloader packet");
    }

    usleep(10000);

    return NULL;
}

#define BootloaderACK 0xCC
#define BootloaderNACK 0x33

error *sendAck(UARTHandle uartHandle)
{
    uint8_t ackPacket[] = {BootloaderACK};
    int8_t retVal = UART_write(uartHandle, ackPacket, sizeof(ackPacket));
    if (retVal < 0)
    {
        return NewError("Unable to send ack");
    }

    return NULL;
}

bool readResponseIsAck(UARTHandle uartHandle)
{
    uint8_t uartReadData;

    do
    {
        UART_read(uartHandle, &uartReadData, 1);
    } while (uartReadData == 0);

    if (uartReadData != BootloaderACK)
    {
        LogInteger("Did not get an ACK: %d\n", uartReadData);
        return false;
    }

    return true;
}

bool readResponseIsNack(UARTHandle uartHandle)
{
    return !readResponseIsAck(uartHandle);
}

bootloaderPacket readBootloaderPacket(UARTHandle uartHandle)
{
    bootloaderPacket blPacket;

    do
    {
        UART_read(uartHandle, &blPacket.size, 1);
    } while (blPacket.size == 0);

    UART_read(uartHandle, &blPacket.checksum, 1);
    UART_read(uartHandle, blPacket.data, blPacket.size - 2);

    return blPacket;
}

bool readResponseStatusIsSuccess(UARTHandle uartHandle)
{
    bootloaderPacket blPacket = readBootloaderPacket(uartHandle);

    switch (blPacket.data[0])
    {
    case COMMAND_RET_SUCCESS:
        Log("Status response: success\n");
        return true;
    case COMMAND_RET_UNKNOWN_CMD:
        Log("Status response: unknown command\n");
        return false;
    case COMMAND_RET_INVALID_CMD:
        Log("Status response: invalid command\n");
        return false;
    case COMMAND_RET_INVALID_ADR:
        Log("Status response: invalid address\n");
        return false;
    case COMMAND_RET_FLASH_FAIL:
        Log("Status response: flash fail\n");
        return false;
    default:
        LogInteger("Status response: unexpected value: %d\n", blPacket.data[0]);
        return false;
    }
}

uint8_t autobaudBytes[] = {0x55, 0x55};

error *setBootloaderBaud(UARTHandle uartHandle)
{
    UART_write(uartHandle, autobaudBytes, sizeof(autobaudBytes));

    if (readResponseIsNack(uartHandle))
    {
        NewError("setBootloaderBaud response was a NACK");
    }

    return NULL;
}

bootloaderPacket createPingPacket()
{
    return createBootloaderPacket(BL_PING, NULL, 0);
}

error *ping2640Bootloader(UARTHandle uartHandle)
{
    bootloaderPacket pingPacket = createPingPacket();
    SendBootloaderPacket(uartHandle, &pingPacket);
    if (readResponseIsNack(uartHandle))
    {
        return NewError("ping2640Bootloader response was a NACK");
    }

    Log("Ping success\n");

    return NULL;
}

bootloaderPacket createGetStatusPacket()
{
    return createBootloaderPacket(BL_GET_STATUS, NULL, 0);
}

error *get2640BootloaderStatus(UARTHandle uartHandle)
{

    bootloaderPacket getStatusPacket = createGetStatusPacket();
    SendBootloaderPacket(uartHandle, &getStatusPacket);
    if (readResponseIsNack(uartHandle))
    {
        return NewError("get2640BootloaderStatus response was a NACK");
    }

    Log("Get Bootloader Status Success!!\n");

    if (!readResponseStatusIsSuccess(uartHandle))
    {
        return NewError("Get bootloader status did not return a success\n");
    }

    sendAck(uartHandle);

    return NULL;
}

bootloaderPacket createEraseFlashPacket(uint32_t startAddress, uint32_t dataSize)
{

    uint8_t data[8];

    data[0] = (startAddress >> 24) & 0xFF;
    data[1] = (startAddress >> 16) & 0xFF;
    data[2] = (startAddress >> 8) & 0xFF;
    data[3] = (startAddress)&0xFF;

    data[4] = (dataSize >> 24) & 0xFF;
    data[5] = (dataSize >> 16) & 0xFF;
    data[6] = (dataSize >> 8) & 0xFF;
    data[7] = (dataSize)&0xFF;

    return createBootloaderPacket(BL_DOWNLOAD, &data, sizeof(data));
}

error *erase2640BootloaderFlash(UARTHandle uartHandle)
{
    bootloaderPacket eraseFlashPacket = createEraseFlashPacket(0x0000, 0x20000);
    SendBootloaderPacket(uartHandle, &eraseFlashPacket);
    if (readResponseIsNack(uartHandle))
    {
        return NewError("erase2640BootloaderFlash response was a NACK!!!!!");
    }

    Log("erase2640BootloaderFlash Success!\n");

    return NULL;
}

bootloaderPacket createDownloadStartPacket(uint32_t startAddress, uint32_t dataSize)
{

    uint8_t downloadCmd[8];

    downloadCmd[0] = (startAddress >> 24) & 0xFF;
    downloadCmd[1] = (startAddress >> 16) & 0xFF;
    downloadCmd[2] = (startAddress >> 8) & 0xFF;
    downloadCmd[3] = (startAddress)&0xFF;

    downloadCmd[4] = (dataSize >> 24) & 0xFF;
    downloadCmd[5] = (dataSize >> 16) & 0xFF;
    downloadCmd[6] = (dataSize >> 8) & 0xFF;
    downloadCmd[7] = (dataSize)&0xFF;

    return createBootloaderPacket(BL_DOWNLOAD, &downloadCmd, sizeof(downloadCmd));
}

error *start2640BootloaderDownload(UARTHandle uartHandle, uint32_t dataSize)
{
    bootloaderPacket startDownloadPacket = createDownloadStartPacket(0x0000, dataSize);
    SendBootloaderPacket(uartHandle, &startDownloadPacket);
    if (readResponseIsNack(uartHandle))
    {
        return NewError("start2640BootloaderDownload response was a NACK!!!!!");
    }

    Log("start2640BootloaderDownload Success!\n");

    return NULL;
}

bootloaderPacket createSendDataPacket(void *data, uint32_t dataSize)
{
    return createBootloaderPacket(BL_SEND_DATA, data, dataSize);
}

error *send2640BootloaderData(UARTHandle uartHandle, void *data, uint32_t dataSize)
{
    bootloaderPacket sendDataPacket = createSendDataPacket(data, dataSize);
    SendBootloaderPacket(uartHandle, &sendDataPacket);
    if (readResponseIsNack(uartHandle))
    {
        return NewError("send2640BootloaderData response was a NACK!!!!!");
    }

    Log("send2640BootloaderData Success!\n");

    return NULL;
}

error *OTA2640()
{
    UARTHandle uartHandle = createUARTHandle(Board_UART0);

    start2640Bootloader();

    error *err = setBootloaderBaud(uartHandle);
    if (err != NULL)
    {
        return err;
    }

    err = ping2640Bootloader(uartHandle);
    if (err != NULL)
    {
        return err;
    }

    err = erase2640BootloaderFlash(uartHandle);
    if (err != NULL)
    {
        return err;
    }

    err = get2640BootloaderStatus(uartHandle);
    if (err != NULL)
    {
        return err;
    }

    GetFileInfoResponse fileInfoResponse = getFileInfo("cc2640.bin");
    if (fileInfoResponse.err != NULL)
    {
        return fileInfoResponse.err;
    }

    err = start2640BootloaderDownload(uartHandle, fileInfoResponse.fileInfo.Len);
    if (err != NULL)
    {
        return err;
    }

    err = get2640BootloaderStatus(uartHandle);
    if (err != NULL)
    {
        return err;
    }

    OpenFileResponse openFileResonse = openReadFile("cc2640.bin");
    if (openFileResonse.err != NULL)
    {
        return openFileResonse.err;
    }

    uint8_t dataBytes[252];
    uint32_t fileOffset = 0;

    while (fileOffset < fileInfoResponse.fileInfo.Len)
    {

        ReadFileResponse readFileResponse = readFile(openFileResonse.fileHandle, dataBytes, sizeof(dataBytes), fileOffset);
        if (readFileResponse.err != NULL)
        {
            return readFileResponse.err;
        }

        fileOffset += readFileResponse.bytesRead;

        err = send2640BootloaderData(uartHandle, dataBytes, readFileResponse.bytesRead);
        if (err != NULL)
        {
            return err;
        }

        err = get2640BootloaderStatus(uartHandle);
        if (err != NULL)
        {
            return err;
        }
    }

    return NULL;
}
  • Hi,

    Do you erase the flash before you upload the image?

    From your code it looks like it should happen in the erase2640BootloaderFlash function:

    error *erase2640BootloaderFlash(UARTHandle uartHandle)
    {
        bootloaderPacket eraseFlashPacket = createEraseFlashPacket(0x0000, 0x20000);
        SendBootloaderPacket(uartHandle, &eraseFlashPacket);
        if (readResponseIsNack(uartHandle))
        {
            return NewError("erase2640BootloaderFlash response was a NACK!!!!!");
        }
        Log("erase2640BootloaderFlash Success!\n");
        return NULL;
    }

    This function then calls createEraseFlashPacket to create the command:

    bootloaderPacket createEraseFlashPacket(uint32_t startAddress, uint32_t dataSize)
    {
        uint8_t data[8];
    
        data[0] = (startAddress >> 24) & 0xFF;
    
        data[1] = (startAddress >> 16) & 0xFF;
    
        data[2] = (startAddress >> 8) & 0xFF;
    
        data[3] = (startAddress)&0xFF;
    
        data[4] = (dataSize >> 24) & 0xFF;
    
        data[5] = (dataSize >> 16) & 0xFF;
    
        data[6] = (dataSize >> 8) & 0xFF;
    
        data[7] = (dataSize)&0xFF;
    
        return createBootloaderPacket(BL_DOWNLOAD, &data, sizeof(data));
    }

    But this is not a flash erase command (COMMAND_SECTOR_ERASE or COMMAND_BANK_ERASE).

    Am I missing something here or is there a bug in your createEraseFlashPacket function?

    Best Regards,

    R.M

  • Thank You! This solved my issue.