美文网首页
华为云OTA升级

华为云OTA升级

作者: xEndLess | 来源:发表于2022-04-21 23:08 被阅读0次

这里只记录差分升级。详细流程见官网文档。本文章只为简化OTA流程,重点放在端侧设备如何从代码层接入。
系统:openharmony kernel-liteos-m;
SDK:IoT Device SDK Tiny;
MCU:STM32F407ZGT6 HAL库

升级包制作

这里需要用到一个ota_tools的工具,官方文档有详细说明。这里不展开阐述。


diff_packflow.png

升级包打包上传

官方文档有详细说明,这里不展开阐述。

IOT平台升级流程

IOT升级流程.png

设备端程序开发说明

升级包存储

img.png

Loader:如果有升级需求,则执行升级(解压以及差分还原)。应该就是bootloader。
Running:设备的应用程序
Flag:存储OTA的一些主要的FLAG(OTA状态、下载升级包大小等,为了防止意外的掉电行为,Flag需要做备份区域)
Backup:用于备份当前的程序,区域大小一般和Running区域大小一致
Download:根据选择解决方案(差分还是全量)来定义其大小

升级执行

SDK提供了三个api供开发者调用
ota_backup(执行备份操作,将当前运行的程序存储到备份区)
ota_patch(升级还原,根据下载包的内容决定做差分升级还是全量升级)
ota_recover(升级回滚,将备份区的内容拷贝到当前执行区)
对开发者而言,需要先备份然后执行升级、防止意外的升级失败。

进度上报

最后搞

OTA实践

首先,需要思考Running、Flag、Backup、Download和FlagBackup分别存储在什么介质上。
因为我的板子上有w25q64jvssiq芯片。所以Flag、Backup、Download和FlagBackup准备放在片外spi flash中。Loader和Running放在片内flash中。
然后,需要提供两套操作flash的api。

片外SPI FLASH驱动

我这里使用SFUD作为SPI FLASH驱动。关于SFUD的移植见SFUD官方文件或者SFUD移植

片内FLASH驱动

照搬GitHub - LiteOS/LiteOS_Lab at iot_link
"LiteOS_Lab-iot_link\targets\STM32F429IGTx_FIRE\Src\ota_flash\hal_flash.c"。源码如下:

#include <string.h>
#include "hal_flash.h"
#include "main.h"

#ifdef HAL_FLASH_MODULE_ENABLED

#define FLASH_SECTOR_ILEGAL 0xFFFFFFFF
#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000)   /* Base address of Sector 0, 16 Kbytes   */
#define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000)   /* Base address of Sector 1, 16 Kbytes   */
#define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000)   /* Base address of Sector 2, 16 Kbytes   */
#define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000)   /* Base address of Sector 3, 16 Kbytes   */
#define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08010000)   /* Base address of Sector 4, 64 Kbytes   */
#define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000)   /* Base address of Sector 5, 128 Kbytes  */
#define ADDR_FLASH_SECTOR_6 ((uint32_t)0x08040000)   /* Base address of Sector 6, 128 Kbytes  */
#define ADDR_FLASH_SECTOR_7 ((uint32_t)0x08060000)   /* Base address of Sector 7, 128 Kbytes  */
#define ADDR_FLASH_SECTOR_8 ((uint32_t)0x08080000)   /* Base address of Sector 8, 128 Kbytes  */
#define ADDR_FLASH_SECTOR_9 ((uint32_t)0x080A0000)   /* Base address of Sector 9, 128 Kbytes  */
#define ADDR_FLASH_SECTOR_10 ((uint32_t)0x080C0000)  /* Base address of Sector 10, 128 Kbytes */
#define ADDR_FLASH_SECTOR_11 ((uint32_t)0x080E0000)  /* Base address of Sector 11, 128 Kbytes */
#define ADDR_FLASH_SECTOR_END ((uint32_t)0x08100000) /* End address of Sector 11 */

static uint32_t prv_flash_get_sector(uint32_t addr)
{
    uint32_t sector = 0;

    if ((addr < ADDR_FLASH_SECTOR_1) && (addr >= ADDR_FLASH_SECTOR_0))
    {
        sector = FLASH_SECTOR_0;
    }
    else if ((addr < ADDR_FLASH_SECTOR_2) && (addr >= ADDR_FLASH_SECTOR_1))
    {
        sector = FLASH_SECTOR_1;
    }
    else if ((addr < ADDR_FLASH_SECTOR_3) && (addr >= ADDR_FLASH_SECTOR_2))
    {
        sector = FLASH_SECTOR_2;
    }
    else if ((addr < ADDR_FLASH_SECTOR_4) && (addr >= ADDR_FLASH_SECTOR_3))
    {
        sector = FLASH_SECTOR_3;
    }
    else if ((addr < ADDR_FLASH_SECTOR_5) && (addr >= ADDR_FLASH_SECTOR_4))
    {
        sector = FLASH_SECTOR_4;
    }
    else if ((addr < ADDR_FLASH_SECTOR_6) && (addr >= ADDR_FLASH_SECTOR_5))
    {
        sector = FLASH_SECTOR_5;
    }
    else if ((addr < ADDR_FLASH_SECTOR_7) && (addr >= ADDR_FLASH_SECTOR_6))
    {
        sector = FLASH_SECTOR_6;
    }
    else if ((addr < ADDR_FLASH_SECTOR_8) && (addr >= ADDR_FLASH_SECTOR_7))
    {
        sector = FLASH_SECTOR_7;
    }
    else if ((addr < ADDR_FLASH_SECTOR_9) && (addr >= ADDR_FLASH_SECTOR_8))
    {
        sector = FLASH_SECTOR_8;
    }
    else if ((addr < ADDR_FLASH_SECTOR_10) && (addr >= ADDR_FLASH_SECTOR_9))
    {
        sector = FLASH_SECTOR_9;
    }
    else if ((addr < ADDR_FLASH_SECTOR_11) && (addr >= ADDR_FLASH_SECTOR_10))
    {
        sector = FLASH_SECTOR_10;
    }
    else if ((addr < ADDR_FLASH_SECTOR_END) && (addr >= ADDR_FLASH_SECTOR_11))
    {
        sector = FLASH_SECTOR_11;
    }
    else
    {
        sector = FLASH_SECTOR_ILEGAL;
    }

    return sector;
}

int hal_flash_read(void *buf, int32_t len, uint32_t location)
{
    if (NULL == buf || len < 0 || len >= ADDR_FLASH_SECTOR_END - ADDR_FLASH_SECTOR_0)
    {
        return -1;
    }

    if (FLASH_SECTOR_ILEGAL != prv_flash_get_sector(location) && FLASH_SECTOR_ILEGAL != prv_flash_get_sector(location + len))
    {
        memcpy(buf, (uint8_t *)location, len);
        return 0;
    }
    else
    {
        return -1;
    }
}

int hal_flash_erase(uint32_t addr, int32_t len)
{
    uint32_t begin_sector;
    uint32_t end_sector;
    uint32_t i;

    if (len < 0 || len >= ADDR_FLASH_SECTOR_END - ADDR_FLASH_SECTOR_0)
    {
        return -1;
    }

    if (HAL_FLASH_Unlock() != HAL_OK)
    {
        return -1;
    }

    begin_sector = prv_flash_get_sector(addr);
    end_sector = prv_flash_get_sector(addr + len);

    if (FLASH_SECTOR_ILEGAL == begin_sector || FLASH_SECTOR_ILEGAL == end_sector)
    {
        return -1;
    }

    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
                           FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);

    for (i = begin_sector; i <= end_sector; ++i)
    {
        FLASH_Erase_Sector(i, FLASH_VOLTAGE_RANGE_3);
    }

    return 0;
}

int hal_flash_write(const void *buf, int32_t len, uint32_t *location)
{
    int i;
    uint8_t *pbuf;
    uint32_t location_cur;

    if (NULL == buf || NULL == location || len < 0 || len >= ADDR_FLASH_SECTOR_END - ADDR_FLASH_SECTOR_0)
    {
        return -1;
    }

    location_cur = *location;
    pbuf = (uint8_t *)buf;

    if (FLASH_SECTOR_ILEGAL == prv_flash_get_sector(location_cur) || FLASH_SECTOR_ILEGAL == prv_flash_get_sector(location_cur + len))
    {
        return -1;
    }

    for (i = 0; i < len; ++i)
    {
        if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE,
                              location_cur + i, pbuf[i]) != HAL_OK)
        {
            return -1;
        }
    }
    *location += len;

    return 0;
}

int hal_flash_erase_write(const void *buf, int32_t len, uint32_t location)
{
    if (NULL == buf)
    {
        return -1;
    }

    if (hal_flash_erase(location, len) != 0)
    {
        (void)HAL_FLASH_Lock();
        return -1;
    }

    if (hal_flash_write(buf, len, &location) != 0)
    {
        (void)HAL_FLASH_Lock();
        return -1;
    }

    return 0;
}

void hal_flash_lock(void)
{
    (void)HAL_FLASH_Lock();
}
#endif /* HAL_FLASH_MODULE_ENABLED */

在移植片内flash驱动的时候,最好结合HAL库对照看一下MCU芯片(STM32F407ZGT6)的datasheet。以下是官方提供的STM32F407ZGT6的FLASH结构图。只有12个sector。


stm32f407 flash.png

img_demo/img_null.c

img_demo/img_null.c和img_demo/img_memory.c是官方的demo。从这两个文件可以看出,Running、Flag、Backup、Download和FlagBackup可以根据存储介质的不同,提供各自的接口:

static int imgerase_func(uintptr_t  arg, int imgsize)
static int imgflush_func(uintptr_t  arg, int imgsize)
static int imgread_func(uintptr_t  arg, int offset, void *buf, int len)
static int imgwrite_func(uintptr_t  arg, int offset,const void *buf, int len)

我们现在需要做的是根据以上4个API,编写片内flash和spi flash对应的4个API,并注册到ota中。复制文件img_null.c为img_flash.c。更改后源码如下:

#include <ota_img.h>
#include "sfud.h"
#include "hal_flash.h"

///< we make the SPI flash as the FLAG DOWNLOAD  BACKUP
#ifndef CONFIG_OTAIMG_FLAGSIZE
#define CONFIG_OTAIMG_FLAGSIZE        4096
#endif

#ifndef CONFIG_OTAIMG_DOWNLOADSIZE
#define CONFIG_OTAIMG_DOWNLOADSIZE   (512*1024)
#endif

#ifndef CONFIG_OTAIMG_BACKUPSIZE
#define CONFIG_OTAIMG_BACKUPSIZE     (512*1024)
#endif

#define CN_OTAIMG_BASEOFFET  0
#define CN_OTAIMG_FLAG_OFFSET          (CN_OTAIMG_BASEOFFET)
#define CN_OTAIMG_DOWNLOAD_OFFSET      (CN_OTAIMG_FLAG_OFFSET + CONFIG_OTAIMG_FLAGSIZE)
#define CN_OTAIMG_BACKUP_OFFSET        (CN_OTAIMG_DOWNLOAD_OFFSET + CONFIG_OTAIMG_DOWNLOADSIZE)
#define CN_OTAIMG_FLAGBACKUP_OFFSET    (CN_OTAIMG_BACKUP_OFFSET + CONFIG_OTAIMG_BACKUPSIZE)
/**
 * The INNER flash FOR OTA WE USED
 *
 *     |----LOADER(128KB)---|-------RUNNINGIMG(512KB)----------|
 * */
#ifndef CONFIG_OTAIMG_RUNNINGSIZE
#define CONFIG_OTAIMG_RUNNINGSIZE        (512*1024)
#endif

#ifndef CONFIG_OTAIMG_RUNNINGBASE
#define CONFIG_OTAIMG_RUNNINGBASE        0x08020000
#endif
sfud_flash *w25q64jv;

/*************************************** spi flash *************************************/
static int spiflash_erase(uintptr_t arg, int imgsize)
{
    int result = -1;
    uint32_t addr;

    addr = (uint32_t)arg;
    if(sfud_erase(w25q64jv, addr, imgsize) == SFUD_SUCCESS)
    {
        result = 0;
    }

    return result;
}

static int spiflash_write(uintptr_t arg, int offset, const void *buf, int len)
{
    uint32_t addr;
    int result = -1;

    addr = (uint32_t)arg + (uint32_t)offset;
    if (sfud_write(w25q64jv, addr, len, (const uint8_t *)buf) == SFUD_SUCCESS)
    {
        result = 0;
    }

    return result;
}

static int spiflash_read(uintptr_t arg, int offset, void *buf, int len)
{
    uint32_t addr;
    int result = 0;

    addr = (uint32_t)arg + (uint32_t)offset;
    if (sfud_read(w25q64jv, addr, len, (uint8_t *)buf) != SFUD_SUCCESS)
    {
        result = -1;
    }

    return result;
}

static int spiflash_flush(uintptr_t arg, int imgsize)
{
    return 0;
}
/******************************* inner flash ************************************/
static int innerflash_erase(uintptr_t arg, int imgsize)
{
    int result = 0;
    uint32_t addr;

    addr = (uint32_t)arg;
    result =  hal_flash_erase(addr, imgsize);
    return result;
}

static int innerflash_flush(uintptr_t arg, int imgsize)
{
    return 0;
}

static int innerflash_read(uintptr_t arg, int offset, void *buf, int len)
{
    uint32_t addr;
    int result = 0;

    addr = (uint32_t)arg + (uint32_t)offset;
    result = hal_flash_read(buf, len, addr);

    return result;
}

static int innerflash_write(uintptr_t arg, int offset, const void *buf, int len)
{
    uint32_t addr;
    int result = 0;

    addr = (uint32_t)arg + (uint32_t)offset;
    result = hal_flash_write(buf, len, &addr);

    return result;
}

static const ota_img_t g_otaimg_flag = {
    .name = "FLAG",
    .size = CONFIG_OTAIMG_FLAGSIZE,
    .type = EN_OTA_IMG_FLAG,
    .arg = (uintptr_t) CN_OTAIMG_FLAG_OFFSET,
    {
        .write = spiflash_write,
        .read = spiflash_read,
        .erase = spiflash_erase,
        .flush = spiflash_flush,
    },
};

static const ota_img_t  g_otaimg_flagbackup = {
    .name = "FLAGBACKUP",
    .size = CONFIG_OTAIMG_FLAGSIZE,
    .type = EN_OTA_IMG_FLAGBACKUP,
    .arg = (uintptr_t)CN_OTAIMG_FLAGBACKUP_OFFSET,
    {
        .write = spiflash_write,
        .read = spiflash_read,
        .erase = spiflash_erase,
        .flush = spiflash_flush,
    },
};

static const ota_img_t g_otaimg_backup = {
    .name = "BACKUP",
    .size = CONFIG_OTAIMG_BACKUPSIZE,
    .type = EN_OTA_IMG_BACKUP,
    .arg = (uintptr_t)CN_OTAIMG_BACKUP_OFFSET,
    {
        .write = spiflash_write,
        .read = spiflash_read,
        .erase = spiflash_erase,
        .flush = spiflash_flush,
    },
};

static const ota_img_t g_otaimg_download = {
    .name = "DOWNLOAD",
    .size = CONFIG_OTAIMG_DOWNLOADSIZE,
    .type = EN_OTA_IMG_DOWNLOAD,
    .arg = (uintptr_t)CN_OTAIMG_DOWNLOAD_OFFSET,
    {
        .write = spiflash_write,
        .read = spiflash_read,
        .erase = spiflash_erase,
        .flush = spiflash_flush,
    },
};

static const ota_img_t g_otaimg_running = {
    .name = "RUNNING",
    .size = CONFIG_OTAIMG_RUNNINGSIZE,
    .type = EN_OTA_IMG_RUNNING,
    .arg = (uintptr_t)CONFIG_OTAIMG_RUNNINGBASE,
    {
        .write = innerflash_write,
        .read = innerflash_read,
        .erase = innerflash_erase,
        .flush = innerflash_flush,
    },
};

int ota_img_init()
{
    sfud_init();
    w25q64jv = sfud_get_device(SFUD_W25Q64JV_DEVICE_INDEX);

    ota_img_bind(EN_OTA_TYPE_FOTA, &g_otaimg_flag);
    ota_img_bind(EN_OTA_TYPE_SOTA, &g_otaimg_flag);

    ota_img_bind(EN_OTA_TYPE_FOTA, &g_otaimg_flagbackup);
    ota_img_bind(EN_OTA_TYPE_SOTA, &g_otaimg_flagbackup);

    ota_img_bind(EN_OTA_TYPE_FOTA, &g_otaimg_backup);
    ota_img_bind(EN_OTA_TYPE_SOTA, &g_otaimg_backup);

    ota_img_bind(EN_OTA_TYPE_FOTA, &g_otaimg_running);
    ota_img_bind(EN_OTA_TYPE_SOTA, &g_otaimg_running);

    ota_img_bind(EN_OTA_TYPE_FOTA, &g_otaimg_download);
    ota_img_bind(EN_OTA_TYPE_SOTA, &g_otaimg_download);

    return 0;
}

业务层

失败了,RAM不够,暂时先放一放,先把其他功能做稳定之后再尝试
未完待续……

相关文章

网友评论

      本文标题:华为云OTA升级

      本文链接:https://www.haomeiwen.com/subject/vawisrtx.html