图 1
先调用初始化函数,分别对数据传输传输协议,固件管理进行初始化

图 2
示例配置为 3 分区方案(APP + download + factory)

图 3
将片内 512K 的 Flash 划出 4 个 32K 的分区来,分别对应 Bootload,APP,download,factory

图 4

上电先检查标志位,如果标志为没有设为更新固件或恢复出厂。则将 Bootloader 执行流程设为查找固件并运行

flowchart LR

app{"校检\nAPP区"} --> |Y| sp{应用程序SP\n是否指向\n片内RAM}
sp -->|Y| ok(FM_ERR_OK); sp-->|N| err(FM_ERR_JUMP_TO_APP_ERR);
app -->|N| fpk{检验\n下载区或\n恢复区}
fpk -->|Y| check{"是否以\nfpk开头"} -->|Y| ok
check -->|N| err
fpk -->|N| err

图 7

flowchart LR
id{"更新方式\n将Version信息\n写入APP区"}
old_version("从APP区末尾的读取FPK信息\n将old_version存到\n_fpk_head.fw_old_ver中")
check{"比较_fpk_head中\nfw_old_ver跟\nfw_new_ver\n是否相同"}

id -->|Y| old_version --> check
id -->|N| check
check -->|相同| 不需更新
check -->|不同| 需要更新

重要的数据类型

classDiagram
class FIRMWARE_UPDATE_INFO {
    + BOOT_STATUS status
    + BOOT_EXE_FLOW exe_flow
    + BOOT_UPDATE_STEP step
    + PP_CMD_EXE_RESULT cmd_exe_result
    + PP_CMD_ERR_CODE cmd_exe_err_code
    + uint8_t start
    + uint8_t total_progress
}
<> FIRMWARE_UPDATE_INFO

class FPK_HEAD {
    + char name[4]
    + uint8_t cnfig[4]
    + char fw_old_ver[FPK_VERSION_SIZE]
    + char fw_new_ver[FPK_VERSION_SIZE]
    + char user_string[FPK_USER_STRING_SIZE]
    + char part_name[FPK_PART_NAME_SIZE]
    + uint32_t raw_size
    + uint32_t pkg_size
    + uint32_t raw_crc
    + uint32_t pkg_crc
    + uint32_t head_crc
}
<> FPK_HEAD

程序更新状态图

stateDiagram

state "检查APP区" as __check_app
state update <>
state verify <>
state "跳转至APP区运行" as __jump_to_app
state "检查downlad区" as __check_download

EXE_FLOW_FIND_RUNNING_FIRMWARE : 在APP、download、factory\n分区查找有无可以固件
EXE_FLOW_NEED_HOST_SEND_FIRMWARE : 需要主机发送固件

[*] --> EXE_FLOW_FIND_RUNNING_FIRMWARE
EXE_FLOW_FIND_RUNNING_FIRMWARE --> EXE_FLOW_NEED_HOST_SEND_FIRMWARE : 所有分区\n都无有效固件
EXE_FLOW_FIND_RUNNING_FIRMWARE --> update : download区\n有固件
update --> __check_app: 需要\n更新固件
update --> __jump_to_app : 不需\n更新固件

__check_app --> verify
verify --> __jump_to_app : APP区\nCRC校验通过
verify --> __check_download : APP区\nCRC校验失败

按键驱动框架

按键相关数据结构

图 8
图 9
图 10
![图 10](mOTA%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0/e96451108dd5681809e9d0f8d5e2986150033a2232196f49b771c70e8211be67.png)  
 1

按键状态机

stateDiagram

state "初始状" as s0
state "第1次按键按下状态" as s1
state "已有1次单击事件发生状态" as s2
state "第2次按键按下过状态" as s3
state "按键处于长按状态" as s4

state KEY_CLICK_EVENT_WHEN_DBLCLICK <>
state PRESS_TICK <>
state PRESS_s2 <>

s0 --> s1 : 有按键按下

s1 --> KEY_CLICK_EVENT_WHEN_DBLCLICK : 按键已释放
KEY_CLICK_EVENT_WHEN_DBLCLICK --> 触发单击事件处理 : 双击事件依旧\n触发单击事件
触发单击事件处理 --> s2
KEY_CLICK_EVENT_WHEN_DBLCLICK --> s2 : 双击事件\n不触发单击事件

s1 --> PRESS_TICK : 按键仍然处于按下状态

PRESS_TICK --> 触发长按事件处理 : 按下时间大于\n长按测试时间
PRESS_TICK --> 按下时间递增 : 按下时间小于等于\n长按测试时间
按下时间递增 --> s1
触发长按事件处理 --> s4


s4 --> s0 : 按键已释放
s4 --> s4 : 按键仍然牌按下状态

s2 --> 释放时间递增 : 按键处于释放状态
释放时间递增 --> PRESS_s2
s2 --> 触发双击事件处理 : 按键处于按下状态

PRESS_s2 --> 单击事件处理 : 释放时间大于\n双击间隔时间
PRESS_s2 --> s2 : 释放时间小于等于\n双击间隔时间
单击事件处理 --> s0

触发双击事件处理 --> s3
s3 --> s0 : 按键已释放
s3 --> s3 : 按键未释放
stateDiagram

state "初始状态" as s0
state "第1次按下状态" as s1
state "第1次释放状态" as s2
state "第2次按下状态" as s3
state "长按按下状态" as s4

[*] --> s0
s0 --> s1 : 有键按下\n触发按键按下事件
s1 --> s4 : 按下时长大\n于长按时间\n触发长按事件
s4 --> s0 : 按键释放
s4 --> s4 : 按键未释放\n触发长按保持事件
s1 --> s2 : 按键释放
s2 --> s3 : 按键按下\n触发双击事件
s2 --> s0 : 超时按键未按下\n触发单击事件
s3 --> s0 : 按键释放
s3 --> s3 : 按键未释放

从上面状态图可以看出,该按键框架支持“按键首次按下”,“按键单击”,“按键双击”,“按键长按”,“按键长按并保持”5 种事件的处理

数据传输层

传输层相关的数据结构

classDiagram

class DATA_TRANSFER {
    uint8_t if_id
    uint8_t *rx_buff
    uint16_t *rx_len
    uint32_t rx_buff_size
}

重要的函数功能框图

DT_Init

数据传输层初始化

flowchart LR
s("初台化\nDATA_TRANSFER\n结构体")
subgraph DT_Port_Init
    %% direction TB
    id1("底层\n接口\n硬件\n初始\n化")
    id1 --> if1{"是否\n启用断帧\n检测"}
    id2("初始化\n断帧检测\n定时器")
end
    if1 --> |Y| id2 --> e(返回)
    if1 --> |N| e
s --> DT_Port_Init

底层接口硬件初始化

flowchart TB

subgraph BSP_UART_Init
direction LR
s("根据DATA_TRANSFER\n中的if_id找到对应\nUART_STRUCT设备")
s --> if1{是否\n已初始化} --> |Y| err(BSP_UART_ERR_NO_INIT)
    subgraph BSP_UART_Port_Init
        direction TB
        sub1("初始化全局\n接收回调函数指针\n_UART_RxCallback")
        sub2("初始化全局\n接收空闲回调函数指针\n_UART_RxIdleCallback")
        sub3("初始化全局\nDMA接收回调函数指针\n_UART_DMA_RxCallback")
        sub4("初始化全局\nDMA接收回调函数指针\n_UART_DMA_TxCallback")
        sub5("初始化UART_STRUCT\n设备中的handle结构体")
        sub6("如果使用DMA发送\n初始化DMA对象的父对象")

        sub1 --> sub2 --> sub3 --> sub4 --> sub5 --> sub6
    end
if1 --> |N| BSP_UART_Port_Init
BSP_UART_Port_Init --> id1(设置UART_STRUCT\n为已初始化)
id1 --> e(BSP_UART_ERR_OK)
end

id2("挂载用户数据到if_id对应的UART_STRUCT结构体中")

subgraph BSP_UART_EnableReceive
direction LR
s2("初始化UART_STRUCT\n的接收缓冲区、大小、长度")
    subgraph BSP_UART_Port_EnableReceive
    sif1{"是否启用\nDMA接收"} --> |N| ss2_1("开启硬件\n接收中断")
    sif1 --> |Y| ss2_2("初始化DMA\n并开启对应中断")
    end
s2 --> BSP_UART_Port_EnableReceive
end

BSP_UART_Init --> id2 --> BSP_UART_EnableReceive