MCU OTA Update

Last Updated on : 2024-05-10 08:08:19download

Overview

An over-the-air (OTA) update is the wireless delivery of new software, firmware, or other data to connected devices.

The MCU SDK supports OTA updates for the MCU. You can upload the update file to the Developer Platform. The Wi-Fi module can download the update from the server and send it to the MCU through the serial port. This way, the MCU gets the update and writes it to the local flash memory for installation. For more information, see Update Firmware and Select and Change the Firmware Version.

Process

The OTA update consumes the memory of the MCU. After a device is paired, an OTA update can be initiated through the preset configuration or check for updates. Here is how the OTA update works:

ModuleMCUInitiate an MCU OTA update.Return the maximum transmission unit.Send the first packet.Save the update and acknowledge the receipt within 5s.If there is no response within 5s, resend the packet three times. If still no response, the module will declare the update as a failure.Send the nth packet.Acknowledge the receipt.Send the last packet.Verify the firmware update, switch to the new version, and restart to complete the update.ModuleMCU

After the Wi-Fi module completes the update transmission, it will send the MCU the command 0x01 to request the product information. The MCU must reply with the new MCU software version number within one minute. The new version number should be consistent with that configured on the Developer Platform.

A successful OTA update can only be declared once the module completes the update transmission, and the MCU reports the latest firmware version number to the module after a restart.

Scenario

In debugging phase or after product delivery, you can deploy MCU updates over OTA to fix issues and add new features. The OTA update feature is recommended if your MCU has enough memory resources.

  • Firmware management: You must upload the verified firmware updates to the Developer Platform for OTA update deployment. For more information, see Update Firmware.

  • Description: You can implement the serial communication between your MCU and the Tuya module by porting the MCU SDK or interfacing with the protocol without the SDK. Either approach requires you to develop a bootloader on your own.

    • Porting MCU SDK: With the OTA-related functions provided in the SDK, the MCU can respond with the size of a single packet, start the update process, and receive and process the update package. See the examples in the following sections.

    • Interfacing without SDK: You need to implement the OTA-related protocols, and file transfer and processing.

      The RAM of your MCU must be greater than 260 bytes. You must implement the basic features of the protocol before working on the OTA feature.

Trigger mechanisms

  • You can specify how an OTA update is triggered. The module only serves as the channel for update transmission, without any data parsing operation.

  • Three trigger mechanisms are available:

    • Update notification: Users receive a firmware update notification on the app and choose whether to install updates.
    • Forced update: Users receive a firmware update notification on the app and have no option but to update the firmware.
    • Check for updates: Users will not receive a firmware update notification on the app but need to manually check for new updates.

Commands

The commands used in the MCU OTA update process.

Command Description
0x0a Start MCU OTA update
0x0b Transfer update package

Start MCU OTA update

The module sends the command 0x0a to tell the MCU the size of the update file. The MCU returns the maximum size of each packet.

Maximum transmission unit

Return value Size
0x00 256 bytes. It is the default value and is compatible with legacy firmware.
0x01 512 bytes
0x02 1,024 bytes

The module sends the following data.

Field Bytes Description
Header 2 0x55aa
Version 1 0x00
Command 1 0x0a
Data length 2 0x0004/0x0008
Data 4 The size of the update file in bytes. The data type is an unsigned integer, and the data is transmitted in big-endian format.
Data 1 The MCU type, ranging from 10 to 19.
Data 3 Reserved for future use.
Checksum 1 Start from the header, add up all the bytes, and then divide the sum by 256 to get the remainder.

Example: 55 aa 00 0a 00 04 00 00 68 00 75

It indicates the size of the update is 26624 bytes, namely 26 KB.

The MCU returns the following data.

Field Bytes Description
Header 2 0x55aa
Version 1 0x03
Command 1 0x0a
Data length 2 0x0001
Data 1 The options for the maximum size of each packet:
  • 0x00: 256 bytes. It is the default value and is compatible with legacy firmware.
  • 0x01: 512 bytes.
  • 0x02: 1,024 bytes.
Checksum 1 Start from the header, add up all the bytes, and then divide the sum by 256 to get the remainder.

Example: 55 aa 03 0a 00 01 00 0d

Transfer update package

The module sends the update to the MCU in multiple packets. If the MCU fails to respond to the update transfer command within five seconds, the module will resend the command, and declare a failed update after three unsuccessful attempts.

  • Data format: fragment offset + payload data.
  • When the MCU receives a frame with a length of four bytes and the fragment offset is equal to or greater than the size of the firmware update, the transfer is completed.

The module sends the following data.

Field Bytes Description
Header 2 0x55aa
Version 1 0x00
Command 1 0x0b
Data length 2 0x0004 + N
Data 4 + N
  • Data[0] to Data[3]: The packet offset.
  • Data[4] to Data[n]: The payload.
Checksum 1 Start from the header, add up all the bytes, and then divide the sum by 256 to get the remainder.

Example:

Assume that the size of the update is 530 bytes, and the MCU does not need to respond to the last packet.

  • For the first packet, the packet offset is 0x00000000, and the packet length is 256 bytes.
    55 aa 00 0b 01 04 00000000 xx…xx XX
  • For the second packet, the packet offset is 0x00000100, and the packet length is 256 bytes.
    55 aa 00 0b 01 04 00000100 xx…xx XX
  • For the third packet, the packet offset is 0x00000200, and the packet length is 18 bytes.
    55 aa 00 0b 00 16 00000200 xx…xx XX
  • For the last packet, the packet offset is 0x00000212, and the packet length is 0 bytes.
    55 aa 00 0b 00 04 00000212 xx…xx XX

The MCU returns the following data.

Field Bytes Description
Header 2 0x55aa
Version 1 0x03
Command 1 0x0b
Data length 2 0x0000
Data 0 None
Checksum 1 Start from the header, add up all the bytes, and then divide the sum by 256 to get the remainder.

Example: 55 aa 03 0b 00 00 0d

Example

Enable MCU OAT update

Enable SUPPORT_MCU_FIRM_UPDATE to turn on the MCU OTA update feature.

#define         SUPPORT_MCU_FIRM_UPDATE                 // Enable the OTA update feature, which is disabled by default.

Set maximum transmission unit

/* Firmware package size selection */
#ifdef SUPPORT_MCU_FIRM_UPDATE
#define PACKAGE_SIZE                   0        // Maximum 256 bytes per packet
//#define PACKAGE_SIZE                   1        // Maximum 512 bytes per packet
//#define PACKAGE_SIZE                   2        // Maximum 1,024 bytes per packet
#endif
  1. The serial data handler data_handle() receives the MCU OTA update request from the module.

    /**
    * @brief Data frame processing.
    * @param[in] {offset} The start bit.
    * @return Null
    */
    void data_handle(unsigned short offset)
    {
    ......
            case UPDATE_START_CMD:                                  // Initiate an OTA update
                // Get the global variable of the maximum transmission unit.
                firm_flag = PACKAGE_SIZE;
                if(firm_flag == 0) {
                    firm_size = 256;
                }else if(firm_flag == 1) {
                    firm_size = 512;
                }else if(firm_flag == 2) {
                    firm_size = 1024;
                }
    
                firm_length = wifi_data_process_buf[offset + DATA_START];
                firm_length <<= 8;
                firm_length |= wifi_data_process_buf[offset + DATA_START + 1];
                firm_length <<= 8;
                firm_length |= wifi_data_process_buf[offset + DATA_START + 2];
                firm_length <<= 8;
                firm_length |= wifi_data_process_buf[offset + DATA_START + 3];
    
                upgrade_package_choose(PACKAGE_SIZE);
                firm_update_flag = UPDATE_START_CMD;
            break;
        ......
    }
    
  2. The MCU SDK calls upgrade_package_choose() from protocol.c to return the maximum size of each packet. You need to set the maximum transmission unit with the above macro for packet fragmentation.

    /**
    * @brief Select the maximum transmission unit.
    * @param[in] {package_sz} Maximum transmission unit
    * @ref           0x00: 256 bytes (default)
    * @ref           0x01: 512 bytes
    * @ref           0x02: 1,024 bytes
    * @return Null
    * @note   To be implemented by you.
    */
    void upgrade_package_choose(unsigned char package_sz)
    {
        #error "Complete the code for setting the maximum transmission unit and then delete this row"
        unsigned short send_len = 0;
        send_len = set_wifi_uart_byte(send_len, package_sz);
        wifi_uart_write_frame(UPDATE_START_CMD, MCU_TX_VER, send_len);
    }
    
  3. Module Debugging Assistant

    MCU OTA Update

Save update

  1. The module sends the update packet as per the specified maximum transmission unit, and the MCU receives it from the data_handle().

    /**
    * @brief Data frame processing.
    * @param[in] {offset} The start bit.
    * @return Null
    */
    void data_handle(unsigned short offset)
    {
    ......
            case UPDATE_TRANS_CMD:                                  //Start update file transfer.
                if(firm_update_flag == UPDATE_START_CMD) {
                    //Stop data reporting.
                    stop_update_flag = ENABLE;
    
                    total_len = (wifi_data_process_buf[offset + LENGTH_HIGH] << 8) | wifi_data_process_buf[offset + LENGTH_LOW];
    
                    dp_len = wifi_data_process_buf[offset + DATA_START];
                    dp_len <<= 8;
                    dp_len |= wifi_data_process_buf[offset + DATA_START + 1];
                    dp_len <<= 8;
                    dp_len |= wifi_data_process_buf[offset + DATA_START + 2];
                    dp_len <<= 8;
                    dp_len |= wifi_data_process_buf[offset + DATA_START + 3];
    
                    firmware_addr = (unsigned char *)wifi_data_process_buf;
                    firmware_addr += (offset + DATA_START + 4);
    
                    if((total_len == 4) && (dp_len == firm_length)) {
                        // The last packet.
                        ret = mcu_firm_update_handle(firmware_addr,dp_len,0);
                        firm_update_flag = 0;
                    }else if((total_len - 4) <= firm_size) {
                        ret = mcu_firm_update_handle(firmware_addr,dp_len,total_len - 4);
                    }else {
                        firm_update_flag = 0;
                        ret = ERROR;
                    }
    
                    if(ret == SUCCESS) {
                        wifi_uart_write_frame(UPDATE_TRANS_CMD, MCU_TX_VER, 0);
                    }
                    //Resume data reporting.
                    stop_update_flag = DISABLE;
                }
            break;
    ......
    }
    
  2. The MCU SDK calls mcu_firm_update_handle() to send the data, address, and data length to the MCU for processing the firmware update. This function needs to be implemented by you.

    /**
    * @brief The MCU enters the update mode.
    * @param[in] {value} The buffer.
    * @param[in] {position} The address of the current packet.
    * @param[in] {length} The length of the firmware update. When it is zero, the update file transfer is completed.
    * @return Null
    * @note   To be implemented by you.
    */
    unsigned char mcu_firm_update_handle(const unsigned char value[],unsigned long position,unsigned short length)
    {
        #error "Complete the implementation for OTA update and then delete this row."
        if(length == 0) {
            // The update file transfer is completed.
    
        }else {
            //Process the received update file.
    
        }
    
        return SUCCESS;
    }
    
  3. Module Debugging Assistant

    MCU OTA Update

Finish update

When mcu_firm_update_handle() receives a packet length of 0, the transmission is completed, and the MCU can begin update installation. This function needs to be implemented by you.

/**
* @brief The MCU enters the update mode.
* @param[in] {value} The buffer.
* @param[in] {position} The address of the current packet.
* @param[in] {length} The length of the firmware update. When it is zero, the update file transfer is completed.
* @return Null
* @note   To be implemented by you.
*/
unsigned char mcu_firm_update_handle(const unsigned char value[],unsigned long position,unsigned short length)
{
    #error "Complete the implementation for OTA update and then delete this row"
    if(length == 0) {
        //The update file transfer is completed.
    }else {
        //Process the received update file.
    }
    return SUCCESS;
}