Silicon EFR32BG22 BG22(1) 片内OTA(双bank)

1 前提

通过Simplicity Studio新建的蓝牙工程默认是带有appLoader的,appLoader的一个缺点就是只能实现单区跟新,而且原厂没有开放appLoader的代码,有的时候可能没办满足用户的需求。比如在更新的时候需要led处于快闪的模式,appLoader就没办法做到。

1.1环境

(1)sdk: gecko_sdk_3.2
(2)IDE: Simplicity Studio 5.0
参考的链接:
(1)参考地址 写的很详细
(2)官方的git路径:参开地址
(3)boot

1.2 flash的分区情况

在这里插入图片描述

2 实现步骤

2.1 boot 工程的选择

做空中升级之前是需要先烧录一个BootLoader。做双区更新一般情况下flash需要512KB及以上的大小。本文使用的是这个工程Internal Storage Bootloader (single image on 512kB device)

BootLoader的工程需要设置Slot 0也就是app bank2的起始地址,app bank2也就是新固件的存放地址。这里的起始地址是278528(0x4 4000)。如下图所示:
在这里插入图片描述
(2)根据工程的autogen\linkerfile.ld文件可知,用户的应用程序存放的起始地址是0x6000,也就是说留给BootLoader的空间为24KB。
在这里插入图片描述

2.2 在工程中新建一个OTA服务

基于soc_empty -新建的工程默认有一个OTA服务,这个服务只有一个**Control characteristic,**而且在gatt_configuration.btconf文件中不可修改。这个服务不是我们所需要的,需要删除并自己新建一个OTA服务。
在这里插入图片描述可以在下图的位置删除这个服务:
在这里插入图片描述
然后自己手动添加服务,如下图:
在这里插入图片描述
这里的Data characteristic需要选择user如下图:
在这里插入图片描述
在这里插入图片描述
到此图形配置完成

3 升级流程

(1)通过Control characteristic进入升级模式,通过data characteristic接收新固件
设置标志,并重启
(2)bootloader_setImageToBootload(0);
(3)bootloader_rebootAndInstall();

3.2 代码的添加

1:基于app.c文件添加

#include "btl_interface.h"
#include "btl_interface_storage.h"

/* Flag for indicating DFU Reset must be performed */

static BootloaderInformation_t bldInfo;
static BootloaderStorageSlot_t slotInfo;

/* OTA variables */
static uint32_t ota_image_position = 0;
static uint8_t ota_in_progress = 0;
static uint8_t ota_image_finished = 0;
static uint16_t ota_time_elapsed = 0;

2:添加函数

/***********************************************************************
 *get_slot_info
 * @return
 */
static int32_t get_slot_info(void)
{
    int32_t err;
    bootloader_getInfo(&bldInfo);
    BLE_RTT("Gecko bootloader version: %u.%u\r\n", (bldInfo.version & 0xFF000000) >> 24,
                          (bldInfo.version & 0x00FF0000) >> 16);
    err = bootloader_getStorageSlotInfo(0, &slotInfo);
    if(err == BOOTLOADER_OK)
    {
        BLE_RTT("Slot 0 starts @ 0x%8.8x, size %u bytes\r\n", slotInfo.address, slotInfo.length);
    }
    else
    {
        BLE_RTT("Unable to get storage slot info, error %x\r\n", err);
    }
    return(err);
}

```c
```c

/***********************************************************************************
*erase_slot_if_needed
*/
static void erase_slot_if_needed(void)
{
uint32_t offset = 0, num_blocks = 0, i = 0;
uint8_t buffer[256];
bool dirty = false;
int32_t err = BOOTLOADER_OK;

/* check the download area content by reading it in 256-byte blocks */
num_blocks = slotInfo.length / 256;

while((dirty == 0) && (offset < 256*num_blocks) && (err == BOOTLOADER_OK))
{
    err = bootloader_readStorage(0, offset, buffer, 256);
    if(err == BOOTLOADER_OK)
    {
        i = 0;
        while(i < 256)
        {
            if(buffer[i++] != 0xFF)
            {
                dirty = true;
                break;
            }
        }
        offset += 256;
    }
    BLE_RTT("erase_slot_if_needed.....");
}

if(err != BOOTLOADER_OK)
{
    BLE_RTT("error reading flash! %x\r\n", err);
}
else if(dirty)
{
    BLE_RTT("download area is not empty, erasing...\r\n");
    bootloader_eraseStorageSlot(0);
    BLE_RTT("done\r\n");
}
else
{
    BLE_RTT("download area is empty\r\n");
}
return;

}

static void print_progress(void)
{
    // estimate transfer speed in kbps
    int kbps = ota_image_position*8/(1024*ota_time_elapsed);

    BLE_RTT("pos: %u, time: %u, kbps: %u\r\n", ota_image_position, ota_time_elapsed, kbps);
}

(3)初始化BootLoader
当接收到 -sl_bt_evt_system_boot_id -事件之后调用bootloader_init进行初始化

      // bootloader init must be called before calling other bootloader_xxx API calls
      bootloader_init();

      // read slot information from bootloader
      if(get_slot_info() == BOOTLOADER_OK)
      {
        // the download area is erased here (if needed), prior to any connections are opened
        erase_slot_if_needed();
      }
      else
      {
          BLE_RTT("Check that you have installed correct type of Gecko bootloader!\r\n");
      }

4.向Control characteristic写0,进入升级模式

//实测发现向Control characteristic写0生成的是这个事件
case sl_bt_evt_gatt_server_attribute_value_id:{
      uint32_t connection = evt->data.evt_gatt_server_attribute_value.connection;
      uint32_t characteristic = evt->data.evt_gatt_server_attribute_value.attribute;
      LOGD("characteristic == %d\r\n",characteristic);
      if(characteristic == gattdb_ota_control)
      {
        switch(evt->data.evt_gatt_server_attribute_value.value.data[0])
        {
        case 0://Erase and use slot 0
          // NOTE: download are is NOT erased here, because the long blocking delay would result in supervision timeout
          //bootloader_eraseStorageSlot(0);
          LOGD("control 0\r\n");
          ota_image_position=0;
          ota_in_progress=1;
          sl_bt_gatt_server_send_user_write_response(connection,characteristic,0);
          break;
        case 3://END OTA process
          //wait for connection close and then reboot
          ota_in_progress=0;
          ota_image_finished=1;
          LOGD("upload finished. received file size %u bytes\r\n", ota_image_position);
          sl_bt_gatt_server_send_user_write_response(connection,characteristic,0);
          break;
        default:
          break;
        }
      }
    }
      break;

5.向Data characteristic写新的固件
bootloader_writeStorage的起始地址就是BootLoader中设置的slot 0的地址。bootloader_writeStorage其实是在BootLoader中实现的,这里只是一个地址的引用。

 case sl_bt_evt_gatt_server_user_write_request_id:
    {
      uint32_t connection = evt->data.evt_gatt_server_user_write_request.connection;
      uint32_t characteristic = evt->data.evt_gatt_server_user_write_request.characteristic;

      LOGD("characteristic == %d\r\n",characteristic);
      if(characteristic == gattdb_ota_control)
      {
        switch(evt->data.evt_gatt_server_user_write_request.value.data[0])
        {
        case 0://Erase and use slot 0
          // NOTE: download are is NOT erased here, because the long blocking delay would result in supervision timeout
          //bootloader_eraseStorageSlot(0);
          LOGD("control 0\r\n");
          ota_image_position=0;
          ota_in_progress=1;
          break;
        case 3://END OTA process
          //wait for connection close and then reboot
          ota_in_progress=0;
          ota_image_finished=1;
          LOGD("upload finished. received file size %u bytes\r\n", ota_image_position);
          break;
        default:
          break;
        }
      } else if(characteristic == gattdb_ota_data)
      {
        if(ota_in_progress)
        {
            LOGD("wirite data\r\n");
          bootloader_writeStorage(0,//use slot 0
              ota_image_position,
            evt->data.evt_gatt_server_user_write_request.value.data,
            evt->data.evt_gatt_server_user_write_request.value.len);
          ota_image_position+=evt->data.evt_gatt_server_user_write_request.value.len;
        }
      }
      //gecko_cmd_gatt_server_send_user_write_response(connection,characteristic,0);
      sl_bt_gatt_server_send_user_write_response(connection,characteristic,0);
    }
      break;

6. 升级完成之后断开连接,所以需要添加固件的复制

    // This event indicates that a connection was closed.
    case sl_bt_evt_connection_closed_id:
      BLE_RTT("Connection closed, reason: 0x%2.2x\r\n", evt->data.evt_connection_closed.reason);
      if(ota_image_finished)
       {
          BLE_RTT("Installing new image.......\r\n");
          bootloader_setImageToBootload(0);
          bootloader_rebootAndInstall();

      }
      else
      {
          ble_adv_start(true);
          BLE_RTT("Started advertising\n");
      }
      break;

四 手机端验证

1.手动向Control characteristic写0
在这里插入图片描述
2 .选择一个.gbl文件
.gbl文件的制作方法参看
(1) 制作升级文件
当应用程序编译完成之后,只要执行根目录下的create_bl_files.bat批处理文件,平台就会自动帮我们生成可用来升级的.gbl文件。
第一次使用该文件的时候需要添加两个用户变量:
可以百度怎么在电脑上添加用户变量

在这里插入图片描述
在这里插入图片描述
然后点击这里就可以生成文件
在这里插入图片描述
在这里插入图片描述
去对应的路径找文件
在这里插入图片描述
(2):app连接成功后
手动向Control characteristic写0
在这里插入图片描述

在这里插入图片描述

(3)在选择需要升级的文件
在这里插入图片描述
4. 等待升级完成
在这里插入图片描述

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值