8.2 Host Assisted DFU

The DFU utility functions can be ported on a given Host MCU to perform the DFU operations. There is an example host MCU code (ota_demo) to simulate the DFU utility and perform the update operations on a given partition.

Host MCU can send AT command +TBL to trigger the RNWF11 module to reboot and enter the bootloader for DFU. Another method to enter bootloader is configuring MCLR pin to reset the RNWF11 and send boot command (0xa7) over UART.

Following is the reference code for resetting the RNWF11 to bootloader mode for DFU:
Note: The name of the function and its implementation might change across MCUs. However, there is no significant change in the following code snippet and reference code. It is recommended to refer to the latest code for the exact implementation.
int Reset_To_Bootloader(void)
{
    unsigned char value;
    int timeout = ENTER_BTL_CMD_TIMEOUT;
    
    DFU_Reset(); 
    
    while (timeout)
    {
        if(UART2.IsTxReady()) 
        {
            UART2.Write(BL_CMD_ENTER_BTL); 
            while(!UART2.IsTxDone());
        }
        if(UART2.IsRxReady())
        {      
            value = UART2.Read();
            if (value == BL_RESP_OK)
            {
                printf("[%s] success entering bootloader..\r\n",__func__);
                return APP_FUNC_RESULT_SUCCESS;
            }
        }      
        DELAY_milliseconds(200);
        timeout -= 200;
    }
    
    return APP_FUNC_RESULT_FAIL;
}

Bootloader Command

When the RNWF11 module executes bootloader, the host MCU can communicate with the RNWF11 by sending bootloader commands over UART.

Following table lists the details of the commands which can be sent by Host MCU to communicate with bootloader on the RNWF11:

Table 8-2. Bootloader Command Type
Bootloader CommandDescription
#define BL_CMD_UNLOCK (0xa0)Unlocks the memory for writing
#define BL_CMD_DATA (0xa1)Sends image data for DFU
#define BL_CMD_VERIFY (0xa2)Verifies the CRC
#define BL_CMD_RESET (0xa3)Performs module Reset
#define BL_CMD_READ_VERSION (0xa6)Reads bootloader version
#define BL_CMD_ENTER_BTL (0xa7)Enter bootloader mode
#define BL_CMD_ERASE_APP (0xa8)Erases program Flash
#define BL_CMD_SET_BAUD_RATE (0xa9)Sets UART baudrate
Table 8-3. Bootloader Command Format
Byte0 .. 3 4 .. 789 .. 9 + Payload size
Size (Bytes)441Payload Size
ValueBL_GUARD (0x5048434D)SizeCommand Type Payload

Bootloader Response Byte

For each command, 1 byte response is received from the bootloader. Following is the response byte value:

Table 8-4. Bootloader Response Byte
Bootloader CommandResponse Byte Value
#define BL_RESP_OK0x50
#define BL_RESP_ERROR0x51
#define BL_RESP_INVALID0x52
#define BL_RESP_CRC_OK0x53
#define BL_RESP_CRC_FAIL0x54
#define BL_RESP_NONE0xFF

Following snippet of code can send the bootloader command according to the command format:

uint8_t send_request(uint8_t cmd, uint8_t *data, int dataLen) {
    uint8_t req[HEADER_SIZE + CMD_ONLY_EXTRA_SIZE + dataLen];
    int resp;
    int cnt = 10;
    uint8_t byteResp;
    
    memset (req, 0, sizeof(req));
    
    req[0] = (uint8_t)(BL_GUARD & 0xFF);        // store the least significant byte
    req[1] = (uint8_t)((BL_GUARD >> 8) & 0xFF); 
    req[2] = (uint8_t)((BL_GUARD >> 16) & 0xFF);
    req[3] = (uint8_t)((BL_GUARD >> 24) & 0xFF);
    req[4] = (uint8_t)(dataLen & 0xFF);        // store the least significant byte
    req[5] = (uint8_t)((dataLen >> 8) & 0xFF); 
    req[6] = (uint8_t)((dataLen >> 16) & 0xFF);
    req[7] = (uint8_t)((dataLen >> 24) & 0xFF);
    req[8] = cmd;
    
    RNWF_IF_Write((uint8_t *)&req, HEADER_SIZE);
    DELAY_microseconds(WRITE_DELAY_USEC);
    
    if ( 0 == dataLen)
    {
        uint8_t extraData[4];
        memset(extraData, 0, sizeof(extraData));
        RNWF_IF_Write(extraData, CMD_ONLY_EXTRA_SIZE);
        DELAY_microseconds(WRITE_DELAY_USEC);
    }
    else
    {  
        RNWF_IF_Write(data, dataLen);
        DELAY_microseconds(WRITE_DELAY_USEC);
    }
    
    resp = 0;
    while (resp == 0 && cnt > 0)
    {
        resp = RNWF_IF_Read(&byteResp, 1);
        
        if (resp == 0)
        {
            DBG_MSG_OTA("ERROR: no response after write, %d\r\n", cnt);
            byteResp = BL_RESP_NONE;
        }
        cnt--;
    }
    
    return byteResp;
}

DFU Process

The following sequence diagram and procedure describes the DFU process between the host MCU and the RNWF11 bootloader.

Figure 8-4. DFU Process Sequence Diagram
  1. Host MCU sends BL_CMD_READ_VERSION command line to check the Bootloader revision and determines if the RNWF11 is in the Bootloader mode. The RNWF11 Bootloader responds with BL_RESP_OK command and the bootloader version. Host MCU verifies the bootloader version to determine if the RNWF11 is in the Bootloader mode.
  2. Host MCU sends BL_CMD_UNLOCK command line to unlock the Flash memory for programming. Start address and size need to be input with this command. The RNWF11 Bootloader responds with BL_RESP_OK command.
  3. Host MCU sends BL_CMD_DATA command line to transfer the image data to the RNWF11 for programming. Address, image data and size are required to be input with this command.
  4. After all the image data is programmed to the RNWF11, send BL_CMD_VERIFY command line to check the CRC of the flashed image. CRC value is input with this command. The RNWF11 Bootloader responds with BL_RESP_CRC_OK command if the CRC verification is success.
  5. Host MCU sends BL_CMD_RESET command line to reset the RNWF11 to run the new firmware image. The RNWF11 Bootloader responds with BL_RESP_OK command.
  6. After the RNWF11 resets and run to application, Host MCU can send AT+GMR command to read the firmware version and verify if the RNWF11 is executing the new firmware.