从8051到stm32, 从串口下载到JLINK调试,从keil到arm-none-eabi-gcc,从"Hello wrold"到通信协议,一路起来已学会很多,是时候写一下bootloader了。
基本原理
- 单片机代码编译完后可以生成".hex"和".bin"文件,而bin文件写入到单片机的FLASH里面,单片机就能正常运行了。
- 单片机启动后,会从0x0800 0000地址开始运行。bootloader的程序从0x0800 000开始。
- bootloader功能就是开机在固定时内(比如100ms内)检测是否需要升级,否则跳转到APP地址上。
如何升级
- 上位机只要把bin文件通过通讯接口(串口、USB、WIFI...)发送到单片机,单机将收到的bin文件数据存到FLASH里面就能完成升级。
- bin文件很大,单片机RAM不够大,不能一次性接收,需要将bin拆包。
- 单片机擦除FLASH时需要一定的时间,写入速度较快。所以最好只擦除bin需要的大小。
- 单片机需要确保收到的数据是正确的,因此需要数据检验。
- 上位机需要查询、写入、擦除、读取、跳转等的功能,每次通讯都需要回应以确保成功。
数据包格式
[4byte:CRC][1byte:CMD][1byte:~CMD][2byte:dataSize][nbyte:data]
因为使用空闲中断来收到数据,并且通讯都是独占的不会中断,因此不需要帧头和帧尾,统一使用crc32来校验,所是32位的,放前面可以更方便来做不定长数据包。FRAME_DATA_SIZE 一般为flash页大小,因为需要按页擦除,因此擦一页发一页。不同单片机的页大小是不一样的。
struct pack_info
{
union
{
struct
{
uint32_t crc;
uint32_t addr;
uint32_t cmd1 : 8;
uint32_t cmd2 : 8;
uint32_t data_size : 16;
uint8_t data[FRAME_DATA_SIZE];
};
uint8_t buffer[FRAME_DATA_SIZE + 12];
};
uint32_t buffer_size;
};
固件信息
- 代码可不能随便刷的,否则容易变砖。如果不担心变砖可以不需要这个!
- 因此我们需要知道bin文件是针对哪个型号的,单片机又是什么型号的。
- 最好还能知道已经刷进去的程序是什么版本的等等,因此需要把固件信息存下来。
- 所以要在单片机上分配块FLASH页面,而bin文件上又保存这些信息呢,总不能上传时再输入吧。
-
typedef union bootloader { struct { uint32_t infoCrc;//固件信息校验 uint32_t magic;//固件信息标志,固定为0x5A1234A5,代码里写入 uint32_t start_addr;//固件起始地址 uint32_t size;//固件大小 uint32_t FWcrc;//固件校验 uint32_t version;//版本号,格式为:主版本号.子版本号.编译号.序号 uint32_t pid;//产品ID,格式为:主板ID.核心ID.产品ID.功能ID uint32_t date;//编译日期 uint32_t bootTimes;//启动次数 AT32_MCU_TYPE whoAmI; char name[256];//固件名称,代码里写入,后面再改也行 }; uint8_t buffer[FLASH_SectorSize]; } firmware_info_t;
FLASH分区
以AT32F413RCT7为例,它FLASH大小为256kb,页大小为2kb。数据手册上有。
代码从0x0800 000开始,如果只用串口通讯,则bootloader程序约为4kb,如果使用USB通讯则会有14kb左右,以编译器为准。因为FLASH划分为如下:
【bootloader区】【固件信息区】【用户代码区】【用户配置区0】【用户配置区1】
/**
* @brief
* TOTAL FLASH SIZE: 256Kb
* [Bloader:0-14Kb][FWINFO:14-16Kb][APP:16-252Kb][CONFIG0:252-254Kb][CONFIG2:254-256Kb]
*/
#define FLASH_SECTOR_COUNT 128
#define FLASH_SectorSize (uint32_t)2048
#define FLASH_Base_Addr (uint32_t)0x08000000
#define FLASH_IAP_Size (uint32_t)0x4000 // 0x08004000~0x0800FFFF
#define FLASH_APP_ADDR (uint32_t)(FLASH_Base_Addr | FLASH_IAP_Size)
#define FLASH_TOTAL_SIZE (FLASH_SECTOR_COUNT * FLASH_SectorSize)
#define FLASH_END_ADDR (FLASH_Base_Addr + FLASH_TOTAL_SIZE)
#define FLASH_APP_END_ADDR (FLASH_END_ADDR - FLASH_SectorSize * 2)
#define FLASH_APP_SIZE (FLASH_TOTAL_SIZE - FLASH_SectorSize * 3 - FLASH_IAP_Size)
#define FLASH_FWINFO_ADDR (FLASH_APP_ADDR - FLASH_SectorSize)
#define FLASH_CONFIG_ADDR0 (FLASH_APP_END_ADDR + FLASH_SectorSize)
#define FLASH_CONFIG_ADDR1 (FLASH_CONFIG_ADDR0 + FLASH_SectorSize)
*.ld文件数据分区
ld文件是编译器编译代码时用来划分数据对应flash位置的,gcc编译器才有的。可以将代码的数据安排到指定FLASH位置上。
bootlader的*.ld文件
只要改变memory就分配完了,整个bootlaoder程序不能超过16Kb.如下:
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 14K
FWINFO (rx) : ORIGIN = 0x08003800, LENGTH = 2K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K
SPIM (rx) : ORIGIN = 0x08400000, LENGTH = 16384K
}
APP的*.ld文件
分配flash
/* Program Entry, set to mark it as "used" and avoid gc */
MEMORY
{
FWINFO (rx) : ORIGIN =0x08003800,LENGTH =2k
ROM (rx) : ORIGIN =0x08004000,LENGTH =236k
RAM (rw) : ORIGIN =0x20000000,LENGTH =32k
}
将变量分配到flash上
SECTIONS
{
.firemware_info : ALIGN(4)
{
KEEP(*(firemware_info))
} > FWINFO
定义固件信息
#include "bootloader.h"
const firmware_info_t zino_firemware_info __attribute__((section("firemware_info")))= {
.infoCrc = ~FLASH_FW_MAGIC,
.magic = FLASH_FW_MAGIC,
.start_addr = 0x08004000,
.size = 0,
.FWcrc = 0,
.version = VESION2INT(0,0,0,1),
.pid =PID2INT(1,2,3,4),
.name = "ZINO Digital Power Supply V0.1",
.date = DATE2INT(2024,11,19),
.whoAmI.ID = 0x30240,
.whoAmI.Serial = AT32F413xxx7,
.whoAmI.Model=__AT32F413RCT7,
.whoAmI.Flash = _256KB,
.whoAmI.Footprint = LQFP64,
};
这样编译好后,bin文件的前2kb就是固件信息的结构体数据 ,bin文件可以查看
添加固件校验值
bin文件被编译完成后,并不会自己计算固件信息里面的固件CRC,因此需要另一个程序来计算这个值,并重新写入到固件里面。这样就能得到一个带有校验值、MCU型号、程序版本等等的固件了。
固件生成工具
只需要会一点c语言就行,fopen bin文件,读取前面一部分固件信息,再把后一部分真正的代码计算出CRC32,然后再写回去生成一个新的文件。。。用gcc编译超方便的 ~~~
/*
* @Author: LVGRAPE
* @LastEditors: LVGRAPE
*/
#include "bootloader.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define CRC32_INIT_VALUE 0xFFFFFFFF
#define CRC32_XOR_VALUE 0xFFFFFFFF
uint32_t crc32_cal(const uint8_t *pdata, int32_t len, uint32_t initial, uint32_t finalXor, bool inputReflected, bool resultReflected);
/**
* @brief
* make -f ./win_iap_tool/firminfo.mk
* ./win_iap_tool/makefirmware.exe ./win_iap_tool/ZINO_FC_V4_V1.0.1_20241115.bin test
* @param argc
* @param argv
* @return int
*/
int main(int argc, char *argv[])
{
char *newName = NULL;
if (argc < 2)
{
printf("Usage: %s <*.bin> <newName(optional)> %d\n", argv[0], argc);
return -1;
}
if (argc == 3)
{
newName = argv[2];
}
firmware_info_t firmInfo;
at32_mcu_init_model(&firmInfo.whoAmI, argv[1]);
FILE *fw = fopen(argv[1], "rb");
if (fw == NULL)
{
printf("open file error\n");
return -1;
}
size_t thisRead = fread(&firmInfo, 1, sizeof(firmInfo), fw);
if (thisRead != sizeof(firmInfo))
{
printf("read firmInfo size error\n");
return -1;
}
printf("name:%s\n", firmInfo.name);
printf("infoCrc: 0x%08X\n", firmInfo.infoCrc);
printf("magic: 0x%08X\n", firmInfo.magic);
printf("startAddr: 0x%08X\n", firmInfo.start_addr);
printf("size: 0x%08X\n", firmInfo.size);
printf("version: 0x%08X\n", firmInfo.version);
printf("pid: 0x%08X\n", firmInfo.pid);
printf("date: 0x%08X\n", firmInfo.date);
printf("Serial: 0x%08X\n", firmInfo.whoAmI.Serial);
printf("ID: 0x%08X\n", firmInfo.whoAmI.ID);
printf("Model: 0x%08X, %s\n", firmInfo.whoAmI.Model, at32_mcu_mode2str(&firmInfo.whoAmI));
printf("Flash: 0x%08X, %s\n", firmInfo.whoAmI.Flash, at32_mcu_flash2str(&firmInfo.whoAmI));
printf("Footprint: 0x%08X, %s\n", firmInfo.whoAmI.Footprint, at32_mcu_footprint2str(&firmInfo.whoAmI));
if (firmInfo.magic != FLASH_FW_MAGIC && firmInfo.infoCrc != ~FLASH_FW_MAGIC)
{
printf("firmware magic error\n");
return -1;
}
if (firmInfo.whoAmI.Model >= AT32_MCU_MODEL_COUNT)
{
printf("mcu model unknow!\n");
return -1;
}
AT32_MCU_TYPE mcuType = AT32_MCU_LIST[firmInfo.whoAmI.Model];
if (mcuType.Model != firmInfo.whoAmI.Model)
{
printf("mcu model error!\n");
return -1;
}
if (mcuType.Flash != firmInfo.whoAmI.Flash)
{
printf("mcu flash error!\n");
return -1;
}
if (mcuType.Footprint != firmInfo.whoAmI.Footprint)
{
printf("mcu footprint error!\n");
return -1;
}
if (mcuType.Serial != firmInfo.whoAmI.Serial)
{
printf("mcu Serial error!\n");
return -1;
}
if (mcuType.ID != firmInfo.whoAmI.ID)
{
printf("mcu ID error!\n");
return -1;
}
fseek(fw, 0, SEEK_SET);
fseek(fw, 0, SEEK_END);
size_t fwSize = ftell(fw);
size_t fwTotalsize = fwSize - sizeof(firmInfo);
size_t fwEndAddr = firmInfo.start_addr + firmInfo.size;
fseek(fw, 0, SEEK_SET);
printf("fwTotalsize(without fwInfo): 0x%08X\n", fwTotalsize);
size_t flashToalSize = at32_mcu_flash_size[firmInfo.whoAmI.Flash];
size_t flashEndAddr = FLASH_Base_Addr + flashToalSize;
printf("flashToalSize: %d,[0x%08X-0x%08X]\n", flashToalSize, FLASH_Base_Addr, flashEndAddr);
if (fwEndAddr > flashEndAddr)
{
printf("firmware size overflow!\n");
return -1;
}
firmInfo.size = fwTotalsize;
uint8_t *fwBuf = (uint8_t *)malloc(fwSize);
thisRead = fread(fwBuf, 1, fwSize, fw);
if (thisRead != fwSize)
{
printf("firmware read fwSize error!\n");
return -1;
}
/**use new name */
if (newName)
{
memset(firmInfo.name, 0, sizeof(firmInfo.name));
memcpy(firmInfo.name, newName, strlen(newName));
printf("get new name: %s\n", firmInfo.name);
}
char *newFwname;
size_t newFwnameLen = strlen(firmInfo.name);
const char *src= firmInfo.name;
if(strcmp(&src[newFwnameLen - 4], ".bin") != 0)
{
newFwname = (char *)malloc(newFwnameLen + 5);
strcpy(newFwname, src);
strcat(newFwname, ".bin");
printf("newFwname: %s\n", newFwname);
}
else
{
newFwname = (char *)malloc(newFwnameLen + 1);
strcpy(newFwname, src);
printf("newFwname: %s\n", newFwname);
}
/**update fw crc, info crc */
firmInfo.FWcrc = crc32_cal(&fwBuf[FLASH_SectorSize], fwTotalsize, CRC32_INIT_VALUE, CRC32_XOR_VALUE, 1, 1);
firmInfo.infoCrc = crc32_cal((const uint8_t *)&firmInfo+4, sizeof(firmInfo) - 4, CRC32_INIT_VALUE, CRC32_XOR_VALUE, 1, 1);
printf("FWcrc: 0x%08X, infoCrc:0x%08X\n", firmInfo.FWcrc, firmInfo.infoCrc);
/**updata firmInfo with crc*/
memcpy(fwBuf, &firmInfo, sizeof(firmInfo));
/**write new firmware */
FILE *fwOut = fopen(newFwname, "wb");
if (!fwOut)
{
printf("new firmware creat error!\n");
return -1;
}
size_t thisWrite = fwrite(fwBuf, 1, fwSize, fwOut);
if (thisWrite != fwSize)
{
printf("firmware write fwSize error!\n");
return -1;
}
printf("Success! New: %s\n", newFwname);
fclose(fwOut);
free(fwBuf);
return 0;
}
运行结果:
make firmare
./UploadTool/makeFirmware.exe ./build/ZINO_POWER_V1.0.1_20250110.bin ZINO_DPS_ZINO_POWER_V1.0.1_20250110.bin
name:ZINO Digital Power Supply V0.1
infoCrc: 0xA5EDCB5A
magic: 0x5A1234A5
startAddr: 0x08004000
size: 0x00000000
version: 0x00000001
pid: 0x01020304
date: 0x07E80B13
Serial: 0x00000047
ID: 0x00030240
Model: 0x0000000F, AT32F413RCT7
Flash: 0x00000002, 256KB
Footprint: 0x00000003, LQFP64
fwTotalsize(without fwInfo): 0x00015EFC
flashToalSize: 262144,[0x08000000-0x08040000]
get new name: ZINO_DPS_ZINO_POWER_V1.0.1_20250110.bin
newFwname: ZINO_DPS_ZINO_POWER_V1.0.1_20250110.bin
FWcrc: 0xFF0BC36F, infoCrc:0x40693BE8
Success! New: ZINO_DPS_ZINO_POWER_V1.0.1_20250110.bin
单片机型号信息
- at32单片机上,有一个装置存储了具体的型号信息,可以读出来. 文档找不到了,可找他们工程师要。
- 我把他们当时的型号都搞进来了。可以通过读flash识别出来型号。可以通过型号来定义单片机。
- 固件生成时,通过型号来定义单片机,那么固件信息就带型号了。
- 烧录时,通过读flash来识别型号,那可以知道固件和单片机匹配与否了。
/*
* @Author: LVGRAPE
* @LastEditors: LVGRAPE
*/
/*
* @Author: LVGRAPE
* @LastEditors: LVGRAPE
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
typedef uint32_t AT32_MCU_ID;
typedef enum
{
AT32F403xxx6 = 0x27, //0X27,
AT32F413xxx7 = 0x47, //0X47,
AT32F415xxx7 = 0x57, //0X57,
AT32F403Axxx7 = 0x77, //0X77,
AT32F407xxx7 = 0x87, //0X87,
} AT32_MCU_Serial;
typedef enum AT32_MCU_MODEL_LIST
{
__AT32F403ZCT6 = 0,
__AT32F403VCT6,
__AT32F403RCT6,
__AT32F403CCT6,
__AT32F403ZGT6,
__AT32F403VGT6,
__AT32F403RGT6,
__AT32F403CGT6,
__AT32F403ZET6,
__AT32F403VET6,
__AT32F403RET6,
__AT32F403CET6,
__AT32F403CGU6,
__AT32F403CEU6,
__AT32F403CCU6,
__AT32F413RCT7,
__AT32F413RBT7,
__AT32F413CCT7,
__AT32F413CBT7,
__AT32F413KCU7_4,
__AT32F413KBU7_4,
__AT32F413C8T7,
__AT32F413CCU7,
__AT32F413CBU7,
__AT32F415RCT7,
__AT32F415CCT7,
__AT32F415KCU7_4,
__AT32F415RCT7_7,
__AT32F415RBT7,
__AT32F415CBT7,
__AT32F415KBU7_4,
__AT32F415RBT7_7,
__AT32F415R8T7,
__AT32F415C8T7,
__AT32F415R8T7_7,
__AT32F415K8U7_4,
__AT32F415CBU7,
__AT32F415CCU7,
__AT32F403AVCT7,
__AT32F403ARCT7,
__AT32F403ACCT7,
__AT32F403ACCU7,
__AT32F403AVGT7,
__AT32F403ARGT7,
__AT32F403ACGT7,
__AT32F403ACGU7,
__AT32F403AVET7,
__AT32F403ARET7,
__AT32F403ACET7,
__AT32F403ACEU7,
__AT32F407VCT7,
__AT32F407RCT7,
__AT32F407VGT7,
__AT32F407RGT7,
__AT32F407VET7,
__AT32F407RET7,
AT32_MCU_MODEL_COUNT,
} AT32_MCU_MODEL;
typedef enum
{
_64KB = 0,
_128KB,
_256KB,
_512KB,
_1024KB,
AT32_MCU_FLASH_COUNT,
} AT32_MCU_FLASH;
typedef enum
{
QFN32 = 0,
QFN48,
LQFP48,
LQFP64,
LQFP100,
LQFP144,
AT32_MCU_Footprint_COUNT,
} AT32_MCU_Footprint;
typedef struct mcuInfo
{
AT32_MCU_Serial Serial:8;
AT32_MCU_ID ID;
AT32_MCU_MODEL Model:8;
AT32_MCU_FLASH Flash:8;
AT32_MCU_Footprint Footprint:8;
uint8_t UID[12];
} AT32_MCU_TYPE;
typedef enum
{
Cortex_M0_r0p0 = 0,
Cortex_M0plus_r0p0,
Cortex_M1_r0p0,
Cortex_M1_r0p1,
Cortex_M1_r1p0,
Cortex_M3_r0p0,
Cortex_M3_r1p0,
Cortex_M3_r1p1,
Cortex_M3_r2p0,
Cortex_M3_r2p1,
Cortex_M4_r0p0,
Cortex_M4_r0p1,
Cortex_count,
}AT32_MCU_Cortex;
typedef struct at32_mcu_core_info
{
AT32_MCU_Cortex core;
uint32_t id;
}at32_mcu_core;
#define AT32MCU_FOREACH(x) for (uint8_t(x) = 0; (x) < AT32_MCU_MODEL_COUNT; (x)++)
#define MCU_UNIQUE_96BIT_ID_BASE_ADDR_31_0 ((uint32_t)0x1FFFF7E8)
#define MCU_UNIQUE_96BIT_ID_BASE_ADDR_63_32 ((uint32_t)0x1FFFF7EC)
#define MCU_UNIQUE_96BIT_ID_BASE_ADDR_95_64 ((uint32_t)0x1FFFF7F0)
#define AT32_MCU_SERIAL_ADDR 0x1FFFF7F3
#define AT32_MCU_PID_BASE_ADDR 0xE0042000
#define AT32_MCU_SERIAL_ID (*(uint8_t*)AT32_MCU_SERIAL_ADDR)
#define AT32_MCU_PID (*(uint32_t*)AT32_MCU_PID_BASE_ADDR)
extern const char AT32_MCU_Cortex_str[Cortex_count+1][16];
extern const AT32_MCU_TYPE AT32_MCU_LIST[AT32_MCU_MODEL_COUNT];
extern const char AT32_MCU_Model_str[AT32_MCU_MODEL_COUNT + 1][16];
extern const char AT32_MCU_FLASH_str[AT32_MCU_FLASH_COUNT + 1][8];
extern const char AT32_MCU_Footprint_str[AT32_MCU_Footprint_COUNT + 1][8];
extern const uint32_t at32_mcu_flash_size[AT32_MCU_FLASH_COUNT];
extern AT32_MCU_TYPE whoAmI;
// char *at32_mcu_core2str(at32_mcu_core *core);
char *at32_mcu_mode2str(AT32_MCU_TYPE *mcu);
char *at32_mcu_flash2str(AT32_MCU_TYPE *mcu);
char *at32_mcu_footprint2str(AT32_MCU_TYPE *mcu);
char *at32_mcu_core2str(uint32_t id);
uint32_t at32_mcu_get_coreID(void);
uint8_t at32_mcu_who_am_i(AT32_MCU_TYPE *mcu);
uint8_t at32_mcu_init_model(AT32_MCU_TYPE *mcu, char *model);
#ifdef __cplusplus
}
#endif
/*
* @Author: LVGRAPE
* @LastEditors: LVGRAPE
*/
/*
* @Author: LVGRAPE
* @LastEditors: LVGRAPE
*/
#include "AT32Models.h"
#include <string.h>
// #include "USART_Configuration.h"
const AT32_MCU_TYPE AT32_MCU_LIST[AT32_MCU_MODEL_COUNT] = {
{0x27, 0x50240, __AT32F403ZCT6, _256KB, LQFP144},
{0x27, 0x50241, __AT32F403VCT6, _256KB, LQFP100},
{0x27, 0x50242, __AT32F403RCT6, _256KB, LQFP64},
{0x27, 0x50243, __AT32F403CCT6, _256KB, LQFP48},
{0x27, 0x50344, __AT32F403ZGT6, _1024KB, LQFP144},
{0x27, 0x50345, __AT32F403VGT6, _1024KB, LQFP100},
{0x27, 0x50346, __AT32F403RGT6, _1024KB, LQFP64},
{0x27, 0x50347, __AT32F403CGT6, _1024KB, LQFP48},
{0x27, 0x502C8, __AT32F403ZET6, _512KB, LQFP144},
{0x27, 0x502C9, __AT32F403VET6, _512KB, LQFP100},
{0x27, 0x502CA, __AT32F403RET6, _512KB, LQFP64},
{0x27, 0x502CB, __AT32F403CET6, _512KB, LQFP48},
{0x27, 0x5034C, __AT32F403CGU6, _1024KB, QFN48},
{0x27, 0x502CD, __AT32F403CEU6, _512KB, QFN48},
{0x27, 0x5024E, __AT32F403CCU6, _256KB, QFN48},
{0x47, 0x30240, __AT32F413RCT7, _256KB, LQFP64},
{0x47, 0x301C1, __AT32F413RBT7, _128KB, LQFP64},
{0x47, 0x30242, __AT32F413CCT7, _256KB, LQFP48},
{0x47, 0x301C3, __AT32F413CBT7, _128KB, LQFP48},
{0x47, 0x30244, __AT32F413KCU7_4, _256KB, QFN32},
{0x47, 0x301C5, __AT32F413KBU7_4, _128KB, QFN32},
{0x47, 0x30106, __AT32F413C8T7, _64KB, LQFP48},
{0x47, 0x30247, __AT32F413CCU7, _256KB, QFN48},
{0x47, 0x301C0, __AT32F413CBU7, _128KB, QFN48},
{0x57, 0x30240, __AT32F415RCT7, _256KB, LQFP64},
{0x57, 0x30241, __AT32F415CCT7, _256KB, LQFP48},
{0x57, 0x30242, __AT32F415KCU7_4, _256KB, QFN32},
{0x57, 0x30243, __AT32F415RCT7_7, _256KB, LQFP64},
{0x57, 0x301C4, __AT32F415RBT7, _128KB, LQFP64},
{0x57, 0x301C5, __AT32F415CBT7, _128KB, LQFP48},
{0x57, 0x301C6, __AT32F415KBU7_4, _128KB, QFN32},
{0x57, 0x301C7, __AT32F415RBT7_7, _128KB, LQFP64},
{0x57, 0x30108, __AT32F415R8T7, _64KB, LQFP64},
{0x57, 0x30109, __AT32F415C8T7, _64KB, LQFP48},
{0x57, 0x3010B, __AT32F415R8T7_7, _64KB, QFN32},
{0x57, 0x3010A, __AT32F415K8U7_4, _64KB, LQFP64},
{0x57, 0x301CD, __AT32F415CBU7, _128KB, QFN48},
{0x57, 0x3024C, __AT32F415CCU7, _256KB, QFN48},
{0x77, 0x50240, __AT32F403AVCT7, _256KB, LQFP100},
{0x77, 0x50241, __AT32F403ARCT7, _256KB, LQFP64},
{0x77, 0x50242, __AT32F403ACCT7, _256KB, LQFP48},
{0x77, 0x50243, __AT32F403ACCU7, _256KB, QFN48},
{0x77, 0x50344, __AT32F403AVGT7, _1024KB, LQFP100},
{0x77, 0x50345, __AT32F403ARGT7, _1024KB, LQFP64},
{0x77, 0x50346, __AT32F403ACGT7, _1024KB, LQFP48},
{0x77, 0x50347, __AT32F403ACGU7, _1024KB, QFN48},
{0x77, 0x502CD, __AT32F403AVET7, _512KB, LQFP100},
{0x77, 0x502CE, __AT32F403ARET7, _512KB, LQFP64},
{0x77, 0x503CF, __AT32F403ACET7, _512KB, LQFP48},
{0x77, 0x503D0, __AT32F403ACEU7, _512KB, QFN48},
{0x87, 0x50249, __AT32F407VCT7, _256KB, LQFP100},
{0x87, 0x5024A, __AT32F407RCT7, _256KB, LQFP64},
{0x87, 0x5034B, __AT32F407VGT7, _1024KB, LQFP100},
{0x87, 0x5034C, __AT32F407RGT7, _1024KB, LQFP64},
{0x87, 0x502D1, __AT32F407VET7, _512KB, LQFP100},
{0x87, 0x502D2, __AT32F407RET7, _512KB, LQFP64},
};
const uint32_t at32_mcu_flash_size[AT32_MCU_FLASH_COUNT] =
{
0x10000,
0x20000,
0x40000,
0x80000,
0x100000,
};
const char AT32_MCU_Model_str[AT32_MCU_MODEL_COUNT + 1][16] =
{
"AT32F403ZCT6",
"AT32F403VCT6",
"AT32F403RCT6",
"AT32F403CCT6",
"AT32F403ZGT6",
"AT32F403VGT6",
"AT32F403RGT6",
"AT32F403CGT6",
"AT32F403ZET6",
"AT32F403VET6",
"AT32F403RET6",
"AT32F403CET6",
"AT32F403CGU6",
"AT32F403CEU6",
"AT32F403CCU6",
"AT32F413RCT7",
"AT32F413RBT7",
"AT32F413CCT7",
"AT32F413CBT7",
"AT32F413KCU7-4",
"AT32F413KBU7-4",
"AT32F413C8T7",
"AT32F413CCU7",
"AT32F413CBU7",
"AT32F415RCT7",
"AT32F415CCT7",
"AT32F415KCU7-4",
"AT32F415RCT7-7",
"AT32F415RBT7",
"AT32F415CBT7",
"AT32F415KBU7-4",
"AT32F415RBT7-7",
"AT32F415R8T7",
"AT32F415C8T7",
"AT32F415R8T7-7",
"AT32F415K8U7-4",
"AT32F415CBU7",
"AT32F415CCU7",
"AT32F403AVCT7",
"AT32F403ARCT7",
"AT32F403ACCT7",
"AT32F403ACCU7",
"AT32F403AVGT7",
"AT32F403ARGT7",
"AT32F403ACGT7",
"AT32F403ACGU7",
"AT32F403AVET7",
"AT32F403ARET7",
"AT32F403ACET7",
"AT32F403ACEU7",
"AT32F407VCT7",
"AT32F407RCT7",
"AT32F407VGT7",
"AT32F407RGT7",
"AT32F407VET7",
"AT32F407RET7",
"unknown",
};
const char AT32_MCU_FLASH_str[AT32_MCU_FLASH_COUNT + 1][8] =
{
"64KB",
"128KB",
"256KB",
"512KB",
"1024KB",
"unknown",
};
const char AT32_MCU_Footprint_str[AT32_MCU_Footprint_COUNT + 1][8] =
{
"QFN32",
"QFN48",
"LQFP48",
"LQFP64",
"LQFP100",
"LQFP144",
"unknown",
};
const char AT32_MCU_Cortex_str[Cortex_count + 1][16] =
{
"Cortex-M0-r0p0",
"Cortex-M0+-r0p0",
"Cortex-M1-r0p1",
"Cortex-M1-r0p1",
"Cortex-M1-r1p0",
"Cortex-M3-r0p0",
"Cortex-M3-r1p0",
"Cortex-M3-r1p1",
"Cortex-M3-r2p0",
"Cortex-M3-r2p1",
"Cortex-M4-r0p0",
"Cortex-M4-r0p1",
"unknown",
};
const uint32_t AT32_MCU_CORE_ID[Cortex_count] =
{
0x410CC200,
0x410CC600,
0x410CC210,
0x410CC211,
0x411CC210,
0x410FC230,
0x410FC231,
0x411FC231,
0x412FC230,
0x412FC231,
0x410FC240,
0x410FC241,
};
char *at32_mcu_mode2str(AT32_MCU_TYPE *mcu)
{
if (mcu->Model < AT32_MCU_MODEL_COUNT)
return (char *)AT32_MCU_Model_str[mcu->Model];
else
return (char *)AT32_MCU_Model_str[AT32_MCU_MODEL_COUNT];
}
char *at32_mcu_flash2str(AT32_MCU_TYPE *mcu)
{
if (mcu->Flash < AT32_MCU_FLASH_COUNT)
return (char *)AT32_MCU_FLASH_str[mcu->Flash];
else
return (char *)AT32_MCU_FLASH_str[AT32_MCU_FLASH_COUNT];
}
char *at32_mcu_footprint2str(AT32_MCU_TYPE *mcu)
{
if (mcu->Footprint < AT32_MCU_Footprint_COUNT)
return (char *)AT32_MCU_Footprint_str[mcu->Footprint];
else
return (char *)AT32_MCU_Footprint_str[AT32_MCU_Footprint_COUNT];
}
uint8_t at32_mcu_who_am_i(AT32_MCU_TYPE *mcu)
{
uint8_t serial = AT32_MCU_SERIAL_ID;
uint32_t id = AT32_MCU_PID;
serial = ((id >> 28) | (serial << 4));
id = id & 0xFFFFF;
// usartPrintf(">>s:%d - id:%d\n\n", serial, id);
AT32MCU_FOREACH(i)
{
// usartPrintf(">>s:%d - %d\n\n", AT32_MCU_LIST[i].Serial, AT32_MCU_LIST[i].ID);
if ((AT32_MCU_LIST[i].Serial == serial) && (AT32_MCU_LIST[i].ID == id))
{
mcu->Serial = serial;
mcu->ID = id;
mcu->Model = AT32_MCU_LIST[i].Model;
mcu->Flash = AT32_MCU_LIST[i].Flash;
mcu->Footprint = AT32_MCU_LIST[i].Footprint;
return 0;
}
}
mcu->Serial = serial;
mcu->ID = id;
mcu->Model = AT32_MCU_MODEL_COUNT;
mcu->Flash = AT32_MCU_Footprint_COUNT;
mcu->Footprint = AT32_MCU_Footprint_COUNT;
return 1;
}
uint32_t at32_mcu_get_coreID(void)
{
/*
内核的系统控制块(SCB) 中存在一个名为CPU ID基本寄存器的寄存器, 它是只读的, 其中包括处
理器类型和版本号。该寄存器的地址为0XE000ED00(只支
持特权访问),在程序中, 可以利用SCB->CPUID访问该寄存器,也可通过绝对地址访问,如
*(uint32_t *)0xE000ED00。
*/
return *(uint32_t *)0xE000ED00;
}
char *at32_mcu_core2str(uint32_t id)
{
for (uint16_t i = 0; i < Cortex_count; i++)
{
if (id == AT32_MCU_CORE_ID[i])
return (char *)AT32_MCU_Cortex_str[i];
}
return (char *)AT32_MCU_Cortex_str[Cortex_count];
}
uint8_t at32_mcu_init_model(AT32_MCU_TYPE *mcu, char *model)
{
for(uint16_t i = 0; i < AT32_MCU_MODEL_COUNT; i++)
{
if(strcmp(model, AT32_MCU_Model_str[i]) == 0)
{
memcpy(mcu, &AT32_MCU_LIST[i], sizeof(AT32_MCU_TYPE));
return 0;
}
}
mcu->Serial = 0;
mcu->ID = 0;
mcu->Model = AT32_MCU_MODEL_COUNT;
mcu->Flash = AT32_MCU_Footprint_COUNT;
mcu->Footprint = AT32_MCU_Footprint_COUNT;
return 1;
}
BOOTLOADER程序
通过以上信息整理,我们就能知道bootloader需要一些什么操作了:
typedef struct bootloader_info
{
uint32_t version;
uint32_t currentAddr;
uint32_t totalSize;
uint32_t SizeLeft;
uint32_t timeOut;
uint32_t dt;
uint32_t appAddr;
uint32_t appSize;
uint32_t fwInfoAddr;
uint32_t sectorSize : 16;
uint32_t sectorCount : 16;
uint16_t (*read)(uint8_t *buf);
uint16_t (*write)(uint8_t *buf, uint16_t len);
uint32_t (*millis)(void);
void (*flashLock)(void);
void (*flashUnlock)(void);
void (*flashSectorErase)(uint32_t addr);
void (*flashRead)(uint32_t addr, uint8_t *buf, uint32_t len);
void (*flashWrite)(uint32_t addr, uint8_t *buf, uint32_t len);
void (*jumpToAddr)(uint32_t addr);
void (*reset)(void);
struct pack_info pack;
firmware_info_t fw_info;
AT32_MCU_TYPE whoAmI;
bool synecd;
} bl_info_t;
程序跳转
我这里用了usb,需要关闭usb,不然usb硬件还在和电脑连接,cpu又不在了,会出大事。
typedef void (*iapfun)(void);
volatile iapfun jump2app;
void IAP_Load_APP(uint32_t appxaddr)
{
SysTick->CTRL = 0; // stop systick
usbd_disconnect(&usb_core_dev);
crm_periph_clock_enable(CRM_USB_PERIPH_CLOCK, FALSE);
crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, FALSE);
nvic_irq_disable(USBFS_L_CAN1_RX0_IRQn);
__disable_irq();
jump2app = (iapfun) (* (volatile uint32_t *)(appxaddr + 4)); // 用户代码区第二个字为程序开始地址(复位地址)
__set_MSP(*(volatile uint32_t *)appxaddr);
__set_PSP(*(volatile uint32_t *)appxaddr); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
__set_CONTROL(0);
jump2app(); // 跳转到APP.
}
单片机bootloader代码
/*
* @Author: LVGRAPE
* @LastEditors: LVGRAPE
*/
#ifndef __BOOTLOADER_H
#define __BOOTLOADER_H
#include <stdint.h>
#include <stdbool.h>
#include "AT32Models.h"
#define Version_ID1 0x10
#define Version_ID2 0x1C
/**
* @brief
* TOTAL FLASH SIZE: 256Kb
* [Bloader:0-14Kb][FWINFO:14-16Kb][APP:16-252Kb][CONFIG0:252-254Kb][CONFIG2:254-256Kb]
*/
#define FLASH_SECTOR_COUNT 128
#define FLASH_SectorSize (uint32_t)2048
#define FLASH_Base_Addr (uint32_t)0x08000000
#define FLASH_IAP_Size (uint32_t)0x4000 // 0x08004000~0x0800FFFF
#define FLASH_APP_ADDR (uint32_t)(FLASH_Base_Addr | FLASH_IAP_Size)
#define FLASH_TOTAL_SIZE (FLASH_SECTOR_COUNT * FLASH_SectorSize)
#define FLASH_END_ADDR (FLASH_Base_Addr + FLASH_TOTAL_SIZE)
#define FLASH_APP_END_ADDR (FLASH_END_ADDR - FLASH_SectorSize * 2)
#define FLASH_APP_SIZE (FLASH_TOTAL_SIZE - FLASH_SectorSize * 3 - FLASH_IAP_Size)
#define FLASH_FWINFO_ADDR (FLASH_APP_ADDR - FLASH_SectorSize)
#define FLASH_CONFIG_ADDR0 (FLASH_APP_END_ADDR + FLASH_SectorSize)
#define FLASH_CONFIG_ADDR1 (FLASH_CONFIG_ADDR0 + FLASH_SectorSize)
#define FRAME_DATA_SIZE 2048
#define FLASH_FW_MAGIC 0x5A1234A5
#define VESION2INT(MAIN, SUB, BUILD, NUM) (uint32_t)(((MAIN) << 24) | ((SUB) << 16) | ((BUILD) << 8) | (NUM))
#define PID2INT(board, core, product, function) (uint32_t)(((board) << 24) | ((core) << 16) | ((product) << 8) | (function))
#define DATE2INT(YEAR, MONTH, DAY) (uint32_t)(((YEAR) << 16) | ((MONTH) << 8) | (DAY))
enum
{
CMD_SYNC = 0XF4,
CMD_ACK = 0XAF,
CMD_NACK = 0XFC,
CMD_VERSION = 0X01,
CMD_GETID = 0X02,
CMD_WRITE = 0X03,
CMD_READ = 0X04,
CMD_RESET = 0X05,
CMD_JUMP = 0X06,
CMD_ERASE = 0X07,
CMD_W_FW_INFO = 0X08,
CMD_R_FW_INFO = 0X09,
CMD_LOG = 0X0A,
};
typedef union bootloader
{
struct
{
uint32_t infoCrc;//固件信息校验
uint32_t magic;//固件信息标志,固定为0x5A1234A5,代码里写入
uint32_t start_addr;//固件起始地址
uint32_t size;//固件大小
uint32_t FWcrc;//固件校验
uint32_t version;//版本号,格式为:主版本号.子版本号.编译号.序号
uint32_t pid;//产品ID,格式为:主板ID.核心ID.产品ID.功能ID
uint32_t date;//编译日期
uint32_t bootTimes;//启动次数
AT32_MCU_TYPE whoAmI;
char name[256];//固件名称,代码里写入,后面再改也行
};
uint8_t buffer[FLASH_SectorSize];
} firmware_info_t;
struct pack_info
{
union
{
struct
{
uint32_t crc;
uint32_t addr;
uint32_t cmd1 : 8;
uint32_t cmd2 : 8;
uint32_t data_size : 16;
uint8_t data[FRAME_DATA_SIZE];
};
uint8_t buffer[FRAME_DATA_SIZE + 12];
};
uint32_t buffer_size;
};
typedef struct bootloader_info
{
uint32_t version;
uint32_t currentAddr;
uint32_t totalSize;
uint32_t SizeLeft;
uint32_t timeOut;
uint32_t dt;
uint32_t appAddr;
uint32_t appSize;
uint32_t fwInfoAddr;
uint32_t sectorSize : 16;
uint32_t sectorCount : 16;
uint16_t (*read)(uint8_t *buf);
uint16_t (*write)(uint8_t *buf, uint16_t len);
uint32_t (*millis)(void);
void (*flashLock)(void);
void (*flashUnlock)(void);
void (*flashSectorErase)(uint32_t addr);
void (*flashRead)(uint32_t addr, uint8_t *buf, uint32_t len);
void (*flashWrite)(uint32_t addr, uint8_t *buf, uint32_t len);
void (*jumpToAddr)(uint32_t addr);
void (*reset)(void);
struct pack_info pack;
firmware_info_t fw_info;
AT32_MCU_TYPE whoAmI;
bool synecd;
} bl_info_t;
void bl_pack_clear(bl_info_t *bl);
uint32_t bl_pack_recv(bl_info_t *bl);
void bl_pack_send(bl_info_t *bl, uint8_t cmd, uint32_t addr, uint8_t *data, uint16_t data_size);
void bootloader_handle(bl_info_t *bl);
#endif
/*
* @Author: LVGRAPE
* @LastEditors: LVGRAPE
*/
// #include "at32f413.h"
#include <stdbool.h>
#include "systick.h"
#include <string.h>
#include "bootloader.h"
#include "crc_func_def.h"
#include "CRC32.h"
#define SERIAL_BUG 0
#define CRC32_INIT_VALUE 0xFFFFFFFF
#define CRC32_XOR_VALUE 0xFFFFFFFF
uint32_t crc32_cal(const uint8_t *pdata, uint32_t len, uint32_t initial, uint32_t finalXor, bool inputReflected, bool resultReflected)
{
uint32_t crc = initial;
uint32_t temp1 = 0, temp2 = 0, pos = 0;
const uint32_t *pTable = crc32__table;
for (int i = 0; i < len; i++)
{
uint32_t curByte = pdata[i];
if (inputReflected)
{
curByte = Reflect8(pdata[i]);
}
temp1 = (crc ^ (curByte << (32 - 8)));
pos = (temp1 >> (32 - 8)) & 0xFF;
temp2 = (temp1 << 8);
crc = (temp2 ^ pTable[pos]);
}
if (resultReflected)
{
crc = Reflect32(crc);
}
return (crc ^ finalXor);
}
void bl_pack_clear(bl_info_t *bl)
{
memset(bl->pack.buffer, 0, sizeof(bl->pack.buffer));
bl->pack.buffer_size = 0;
}
void bl_pack_send(bl_info_t *bl, uint8_t cmd, uint32_t addr, uint8_t *data, uint16_t data_size)
{
uint32_t crc = 0;
bl_pack_clear(bl);
bl->pack.cmd1 = cmd;
bl->pack.cmd2 = (uint8_t)~cmd;
bl->pack.addr = addr;
memcpy(bl->pack.data, data, data_size);
bl->pack.data_size = data_size;
bl->pack.buffer_size = 12 + bl->pack.data_size;
crc = crc32_cal(bl->pack.buffer + 4, bl->pack.buffer_size - 4, CRC32_INIT_VALUE, CRC32_XOR_VALUE, 1, 1);
bl->pack.crc = crc;
bl->write(bl->pack.buffer, bl->pack.buffer_size);
bl->write((uint8_t *)&crc, 0); /**FIXME USB-CDC BUG! */
#if (SERIAL_BUG)
/**FIXME 长度是64的倍数时,会卡住不发送 */
#endif
}
uint32_t bl_pack_recv(bl_info_t *bl)
{
uint32_t crc = -1;
bl_pack_clear(bl);
bl->pack.buffer_size = bl->read(bl->pack.buffer);
if (bl->pack.buffer_size > 0)
{
uint32_t crcLen = bl->pack.buffer_size - 4;
#if (SERIAL_BUG)
crcLen -= 4;
#endif
crc = crc32_cal(bl->pack.buffer + 4, crcLen, CRC32_INIT_VALUE, CRC32_XOR_VALUE, 1, 1);
if (crc == bl->pack.crc)
{
return 0;
}
}
return crc;
}
void bl_write_handle(bl_info_t *bl)
{
if (bl->pack.addr >= bl->appAddr && bl->pack.addr <= (bl->appAddr + bl->appSize))
{
bl->flashWrite(bl->pack.addr, bl->pack.data, bl->pack.data_size);
bl_pack_send(bl, CMD_ACK, 0, NULL, 0);
}
else
{
bl_pack_send(bl, CMD_NACK, 0, NULL, 51);
}
}
void bl_read_handle(bl_info_t *bl)
{
uint8_t readBuffer[FLASH_SectorSize];
if (bl->pack.addr >= bl->appAddr && bl->pack.addr < (bl->appAddr + bl->appSize))
{
uint32_t sizeRemain = bl->appAddr + bl->appSize - bl->pack.addr;
uint32_t readSize = bl->pack.data[0] | (bl->pack.data[1] << 8) | (bl->pack.data[2] << 16) | (bl->pack.data[3] << 24);
readSize = readSize > sizeRemain ? sizeRemain : readSize;
bl->flashRead(bl->pack.addr, readBuffer, readSize);
bl_pack_send(bl, CMD_ACK, bl->pack.addr, readBuffer, readSize);
}
else
{
bl_pack_send(bl, CMD_NACK, 0, NULL, 41);
}
}
void bl_erase_handle(bl_info_t *bl)
{
if (bl->pack.addr >= bl->appAddr && bl->pack.addr < (bl->appAddr + bl->appSize))
{
uint32_t sizeRemain = bl->appAddr + bl->appSize - bl->pack.addr;
uint32_t eraseSize = 0;
eraseSize = bl->pack.data[0] | (bl->pack.data[1] << 8) | (bl->pack.data[2] << 16) | (bl->pack.data[3] << 24);
eraseSize = eraseSize > sizeRemain ? sizeRemain : eraseSize;
uint32_t endAddr = bl->pack.addr + eraseSize;
bl->flashUnlock();
uint32_t eraseAddr = bl->pack.addr;
for (; eraseAddr < endAddr; eraseAddr += bl->sectorSize)
{
bl_pack_send(bl, CMD_ACK, eraseAddr, (uint8_t *)&endAddr, 4);
bl->flashSectorErase(eraseAddr);
}
bl_pack_send(bl, CMD_ACK, eraseAddr, (uint8_t *)&endAddr, 4);
bl->flashLock();
}
else
{
bl_pack_send(bl, CMD_NACK, 0, NULL, 21);
}
}
void bl_jump_handle(bl_info_t *bl)
{
if (bl->pack.addr >= bl->appAddr && bl->pack.addr < (bl->appAddr + bl->appSize))
{
bl_pack_send(bl, CMD_ACK, bl->pack.addr, NULL, 0);
if (bl->jumpToAddr)
bl->jumpToAddr(bl->pack.addr);
}
else
{
bl_pack_send(bl, CMD_NACK, bl->appAddr, NULL, 31);
}
}
void bl_W_fwInfo_handle(bl_info_t *bl)
{
int err = 0;
memset(&bl->fw_info, 0, sizeof(firmware_info_t));
memcpy(&bl->fw_info, bl->pack.data, bl->pack.data_size);
uint32_t crc = crc32_cal((const uint8_t *)&bl->fw_info + 4, sizeof(firmware_info_t) - 4, CRC32_INIT_VALUE, CRC32_XOR_VALUE, 1, 1);
if (crc != bl->fw_info.infoCrc)
{
err = 11;
goto NackExit;
}
if (bl->fw_info.magic != FLASH_FW_MAGIC)
{
err = 12;
goto NackExit;
}
if (bl->fw_info.size > bl->appSize || bl->fw_info.size == 0)
{
err = 13;
goto NackExit;
}
if (bl->fw_info.start_addr < bl->appAddr || bl->fw_info.start_addr >= (bl->appAddr + bl->appSize))
{
err = 14;
goto NackExit;
}
if (bl->fw_info.whoAmI.ID != bl->whoAmI.ID || bl->fw_info.whoAmI.Serial != bl->whoAmI.Serial)
{
err = 15;
goto NackExit;
}
bl->flashUnlock();
bl->flashSectorErase(bl->fwInfoAddr);
bl->flashWrite(bl->fwInfoAddr, (uint8_t *)&bl->fw_info, sizeof(firmware_info_t));
bl->flashLock();
bl_pack_send(bl, CMD_ACK, 0, NULL, 0);
return;
NackExit:
bl_pack_send(bl, CMD_NACK, 0, NULL, err);
}
void bl_R_fwInfo_handle(bl_info_t *bl)
{
uint16_t dataSize = bl->pack.addr != 0 ? bl->pack.addr : sizeof(firmware_info_t);
bl->flashRead(bl->fwInfoAddr, (uint8_t *)&bl->fw_info, sizeof(firmware_info_t));
bl_pack_send(bl, CMD_ACK, bl->fwInfoAddr, (uint8_t *)&bl->fw_info, dataSize);
}
uint32_t bl_check_fw(bl_info_t *bl)
{
uint32_t crc = 0;
bl->flashRead(bl->fwInfoAddr, (uint8_t *)&bl->fw_info, sizeof(firmware_info_t));
crc = crc32_cal((uint8_t *)&bl->fw_info + 4, sizeof(firmware_info_t) - 4, CRC32_INIT_VALUE, CRC32_XOR_VALUE, 1, 1);
if (bl->fw_info.magic == FLASH_FW_MAGIC && bl->fw_info.size < bl->appSize && crc == bl->fw_info.infoCrc)
{
const uint8_t *fwData = (const uint8_t *)bl->fw_info.start_addr;
if (bl->fw_info.bootTimes == 0)
{
/**First time, check crc*/
crc = crc32_cal(fwData, bl->fw_info.size, CRC32_INIT_VALUE, CRC32_XOR_VALUE, 1, 1);
if (crc == bl->fw_info.FWcrc)
{
// bl_pack_send(bl, CMD_LOG, bl->appAddr, (uint8_t *)"bl->jumpToAddr\r\n", 17);
bl->jumpToAddr(bl->appAddr);
return 0;
}
}
else if (bl->fw_info.bootTimes == 0xFFFFFFFF)
{
// bl_pack_send(bl, CMD_LOG, bl->fwInfoAddr, (uint8_t *)"system failure\r\n", 17);
/**system failure*/
return 0;
}
else
{
bl->jumpToAddr(bl->appAddr);
return 0;
}
}
// bl_pack_send(bl, CMD_LOG, bl->fwInfoAddr, (uint8_t *)"fw crc error\r\n", 15);
return 1;
}
void bootloader_handle(bl_info_t *bl)
{
#if 1
bl->pack.buffer_size = bl->read(bl->pack.buffer);
if (bl->pack.buffer_size != 0)
{
uint32_t crcLen = bl->pack.buffer_size - 4;
uint32_t crc = crc32_cal(bl->pack.buffer + 4, crcLen, CRC32_INIT_VALUE, CRC32_XOR_VALUE, 1, 1);
uint8_t cmd2 = ~bl->pack.cmd2;
if (bl->pack.crc == crc)
{
if (bl->pack.cmd1 == cmd2)
{
if(!bl->synecd)
{
if(bl->pack.cmd1 == CMD_SYNC)
{
bl->synecd = true;
bl_pack_send(bl, CMD_ACK, 0, NULL, 0);
}
else
{
bl_pack_send(bl, CMD_NACK, 0, NULL, 3);
}
}
else
{
/**NOTE SYNC */
switch (bl->pack.cmd1)
{
case CMD_SYNC:
bl->synecd = true;
bl_pack_send(bl, CMD_ACK, 0, NULL, 0);
break;
case CMD_VERSION:
bl_pack_send(bl, CMD_ACK, 0, (uint8_t *)&bl->version, 4);
break;
case CMD_GETID:
bl_pack_send(bl, CMD_ACK, 0, (uint8_t *)&bl->whoAmI, sizeof(bl->whoAmI));
break;
case CMD_WRITE:
bl_write_handle(bl);
break;
case CMD_READ:
bl_read_handle(bl);
break;
case CMD_RESET:
bl_pack_send(bl, CMD_ACK, 0, NULL, 0);
if (bl->reset)
bl->reset();
break;
case CMD_JUMP:
bl_jump_handle(bl);
break;
case CMD_ERASE:
bl_erase_handle(bl);
break;
case CMD_W_FW_INFO:
bl_W_fwInfo_handle(bl);
break;
case CMD_R_FW_INFO:
bl_R_fwInfo_handle(bl);
break;
default:
/** unknown cmd */
bl_pack_send(bl, CMD_NACK, 0, NULL, 1);
break;
}
}
}
else
{
/**NOTE cmd error */
bl_pack_send(bl, CMD_NACK, 0, NULL, 2);
}
}
else
{
/**NOTE crc error */
bl_pack_send(bl, CMD_NACK, 0, NULL, 3);
}
memset(bl->pack.buffer, 0, bl->pack.buffer_size);
bl->pack.buffer_size = 0;
}
#endif
if (bl->synecd == false)
{
if (bl->millis() > (bl->dt + 100))
{
// NOTE IAP timeout. Exit.
bl_check_fw(bl);
bl->dt = bl->millis();
}
}
}
上位机代码
(使用Linux gcc编译,或者cygwin编译):
/*
* @Author: LVGRAPE
* @LastEditors: LVGRAPE
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include "bootloader.h"
#include "AT32Models.h"
#define CRC32_INIT_VALUE 0xFFFFFFFF
#define CRC32_XOR_VALUE 0xFFFFFFFF
uint32_t crc32_cal(const uint8_t *pdata, int32_t len, uint32_t initial, uint32_t finalXor, bool inputReflected, bool resultReflected);
firmware_info_t firmware;
bl_info_t bootloader;
bl_info_t *bl = &bootloader;
uint8_t *firmware_data = NULL;
int f_com = 0;
uint16_t SetSize = 0;
int readout = 0;
uint16_t bl_write(uint8_t *buff, uint16_t len)
{
if (f_com == 0)
{
printf("bl_write error, f_com: 0x%08X\n", f_com);
return 0;
}
uint16_t ret = write(f_com, buff, len);
// tcflush(f_com, TCIOFLUSH);
if (ret != len)
printf("bl_write error, ret:%d\n", ret);
return ret;
}
uint16_t bl_read(uint8_t *buff)
{
if (!f_com)
{
printf("bl_read error, f_com: 0x%08X\n", f_com);
return 0;
}
uint16_t len = 0;
for (;;)
{
if (read(f_com, buff, 1) == 1)
{
buff++;
len++;
}
else
{
return len;
}
}
return len;
}
int firmware_extract(FILE *f, firmware_info_t *i)
{
if (!f)
return -1;
size_t readsize = fread(i, 1, sizeof(firmware_info_t), f);
if (readsize != sizeof(firmware_info_t))
{
printf("firmware_extract error, readsize:%d\n", readsize);
return -1;
}
// printf("readsize:%d\n",readsize);
uint32_t crc = crc32_cal((const uint8_t *)i + 4, sizeof(firmware_info_t) - 4, CRC32_INIT_VALUE, CRC32_XOR_VALUE, 1, 1);
if (crc != i->infoCrc)
{
printf("firmware_extract error, crc: 0x%08X, infoCrc: 0x%08X\n", crc, i->infoCrc);
return -1;
}
printf(" *name : %s\n", i->name);
printf(" *infoCrc : 0x%08X\n", i->infoCrc);
printf(" *magic : 0x%08X\n", i->magic);
printf(" *startAddr: 0x%08X\n", i->start_addr);
printf(" *size : 0x%08X\n", i->size);
printf(" *FWcrc : 0x%08X\n", i->FWcrc);
printf(" *version : 0x%08X\n", i->version);
printf(" *pid : 0x%08X\n", i->pid);
printf(" *date : 0x%08X\n", i->date);
printf(" *Serial : 0x%08X\n", i->whoAmI.Serial);
printf(" *ID : 0x%08X\n", i->whoAmI.ID);
printf(" *Model : 0x%08X\n", i->whoAmI.Model);
printf(" *Flash : 0x%08X\n", i->whoAmI.Flash);
printf(" *Footprint: 0x%08X\n", i->whoAmI.Footprint);
firmware_data = (uint8_t *)malloc(i->size);
if(!firmware_data)
{
printf("firmware_extract error, malloc failed\n");
return -1;
}
readsize = fread(firmware_data, 1, i->size, f);
// FILE *fw = fopen("./write.bin", "wb");
// fwrite(firmware_data, 1, i->size, fw);
// fclose(fw);
if (readsize != i->size)
{
printf("firmware_extract error, readsize:%d/%d\n", readsize, i->size);
return -1;
}
crc = crc32_cal(firmware_data, i->size, CRC32_INIT_VALUE, CRC32_XOR_VALUE, 1, 1);
if (crc != i->FWcrc)
{
printf("firmware_extract error, crc:%x, FWcrc:%x\n", crc, i->FWcrc);
return -1;
}
printf("FWcrc: 0x%08X\n", crc);
return 0;
}
void delay_ms(uint32_t ms)
{
usleep(ms * 1000);
}
int serial_init(int *fcom, char *com, int baudrate)
{
/**get com num */
char linuxCom[12] = "/dev/ttyS";
int comIndex = -1;
if (strncmp(com, "COM", 3) == 0)
{
comIndex = atoi(com + 3) - 1;
if (comIndex < 9)
linuxCom[9] = comIndex + '0';
else if (comIndex < 100)
{
linuxCom[9] = comIndex / 10 + '0';
linuxCom[10] = comIndex % 10 + '0';
}
else
{
printf("com error!\n");
return -1;
}
printf("\ncomIndex = %d\n", comIndex);
printf("com = %s\n", linuxCom);
}
else
{
printf("com error!\n");
return -1;
}
/**get baudrate */
printf("baudrate:%d \n", baudrate);
/**open and init com port*/
*fcom = open(linuxCom, O_RDWR | O_NOCTTY | O_NDELAY);
if (*fcom == -1)
{
printf("com port open error! %s\n", strerror(errno));
return -1;
}
printf("serial open\n");
struct termios options;
tcgetattr(*fcom, &options);
switch (baudrate)
{
case 9600:
cfsetispeed(&options, B9600); // 设置输入波特率为921600
cfsetospeed(&options, B9600); // 设置输出波特率为921600
break;
case 115200:
cfsetispeed(&options, B115200); // 设置输入波特率为921600
cfsetospeed(&options, B115200); // 设置输出波特率为921600
break;
case 921600:
cfsetispeed(&options, B921600); // 设置输入波特率为921600
cfsetospeed(&options, B921600); // 设置输出波特率为921600
break;
default:
cfsetispeed(&options, B921600); // 设置输入波特率为921600
cfsetospeed(&options, B921600); // 设置输出波特率为921600
break;
}
options.c_cflag |= (CLOCAL | CREAD); // 忽略调制解调器控制线,启用接收器
options.c_cflag &= ~PARENB; // 无奇偶校验
options.c_cflag &= ~CSTOPB; // 1位停止位
options.c_cflag &= ~CSIZE; // 清除数据位设置
options.c_cflag |= CS8; // 设置数据位为8位
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 非规范模式,禁止
options.c_oflag &= ~OPOST; // 原始输出
options.c_cc[VTIME] = 1; // 设置超时1
options.c_cc[VMIN] = 1; // 设置最小字符为1
tcsetattr(*fcom, TCSANOW, &options);
printf("serial init done\n");
return 0;
}
int dev_sync(bl_info_t *bl)
{
int sendtry = 0;
printf("\nTry to sync");
while (1)
{
tcflush(f_com, TCIOFLUSH);
bl_pack_send(bl, CMD_SYNC, 0, NULL, 0);
// printf("\nsending:");
// for (int i = 0; i < bl->pack.buffer_size; i++)
// {
// if (i % 16 == 0)
// printf("\n");
// printf("%02X ", bl->pack.buffer[i]);
// }
// printf("\n");
delay_ms(1);
if (bl_pack_recv(bl) == 0 && bl->pack.cmd1 == CMD_ACK)
{
printf("Sync success!\n");
// break;
return 0;
}
else
{
delay_ms(10);
sendtry++;
if (sendtry >= 300)
{
printf("sync timeout! exit!\n");
return -2;
}
}
printf("\nrev: %d", bl->pack.buffer_size);
for (int i = 0; i < bl->pack.buffer_size; i++)
{
if (i % 16 == 0)
printf("\n");
printf("%02X ", bl->pack.buffer[i]);
}
printf("\n");
}
printf("\n");
return -1;
}
int getVersion(bl_info_t *bl)
{
printf("\nget version\n");
int sendtry = 0;
while (1)
{
tcflush(f_com, TCIOFLUSH);
bl_pack_send(bl, CMD_VERSION, 0, NULL, 0);
// printf("\nsending:");
// for (int i = 0; i < bl->pack.buffer_size; i++)
// {
// if (i % 16 == 0)
// printf("\n");
// printf("%02X ", bl->pack.buffer[i]);
// }
// printf("\n");
delay_ms(1);
if (bl_pack_recv(bl) == 0 && bl->pack.cmd1 == CMD_ACK)
{
if (bl->pack.cmd1 == CMD_ACK)
{
printf("get version success\n");
memcpy(&bl->version, bl->pack.data, bl->pack.data_size);
printf("version:0x%08X\n", bl->version);
return 0;
}
}
delay_ms(1);
if (sendtry++ >= 3)
{
printf("get version timeout! exit!\n");
return -1;
}
printf(".");
}
printf("\n");
}
int getId(bl_info_t *bl)
{
printf("\nget id...\n");
int sendtry = 0;
while (1)
{
tcflush(f_com, TCIOFLUSH);
bl_pack_send(bl, CMD_GETID, 0, NULL, 0);
// printf("\nsending:");
// for (int i = 0; i < bl->pack.buffer_size; i++)
// {
// if (i % 16 == 0)
// printf("\n");
// printf("%02X ", bl->pack.buffer[i]);
// }
// printf("\n");
delay_ms(1);
if (bl_pack_recv(bl) == 0 && bl->pack.cmd1 == CMD_ACK)
{
if (bl->pack.cmd1 == CMD_ACK)
{
printf("get id success\n");
memcpy(&bl->whoAmI, bl->pack.data, bl->pack.data_size);
printf(" *Serial : 0x%08X\n", bl->whoAmI.Serial);
printf(" *ID : 0x%08X\n", bl->whoAmI.ID);
printf(" *Model : 0x%08X\n", bl->whoAmI.Model);
printf(" *Flash : 0x%08X\n", bl->whoAmI.Flash);
printf(" *Footprint: 0x%08X\n", bl->whoAmI.Footprint);
printf(" *UID : ");
for (int i = 0; i < sizeof(bl->whoAmI.UID); i++)
{
printf("%02X", bl->whoAmI.UID[i]);
}
printf("\n");
int mcuMatch = 0;
if (bl->whoAmI.Serial != firmware.whoAmI.Serial)
{
printf("whoAmI Serial not match!\n");
mcuMatch++;
}
if (bl->whoAmI.Model != firmware.whoAmI.Model)
{
printf("whoAmI Model not match!\n");
mcuMatch++;
}
if (bl->whoAmI.Flash != firmware.whoAmI.Flash)
{
printf("whoAmI Flash not match!\n");
mcuMatch++;
}
if (mcuMatch != 0)
{
printf("MCU not match!\n");
return -1;
}
printf(" - - - MCU match! - - - \n\n\n");
// memcpy(firmware.whoAmI.UID, bl->whoAmI.UID, sizeof(bl->whoAmI.UID));
return 0;
}
}
delay_ms(1);
if (sendtry++ >= 3)
{
printf("get version timeout! exit!\n");
return -1;
}
printf(".");
}
printf("\n\n");
return -1;
}
int get_fwInfo(bl_info_t *bl)
{
printf("get fwInfo...\n");
int sendtry = 0;
while (1)
{
tcflush(f_com, TCIOFLUSH);
bl_pack_send(bl, CMD_R_FW_INFO, SetSize, NULL, 0);
// printf("\nSending:");
// for (int i = 0; i < bl->pack.buffer_size; i++)
// {
// if (i % 16 == 0)
// printf("\n");
// printf("%02X ", bl->pack.buffer[i]);
// }
// printf("\n");
delay_ms(10);
uint32_t ret = bl_pack_recv(bl);
if (ret == 0)
{
if (bl->pack.cmd1 == CMD_ACK && bl->pack.data_size == sizeof(firmware_info_t))
{
firmware_info_t onchipFW;
printf("get fwInfo success:crc 0x%08X\n", bl->pack.crc);
memcpy(&onchipFW, bl->pack.data, sizeof(firmware_info_t));
uint32_t iCrc = crc32_cal((uint8_t *)&onchipFW + 4, sizeof(firmware_info_t) - 4, CRC32_INIT_VALUE, CRC32_XOR_VALUE, 1, 1);
if (iCrc == onchipFW.infoCrc)
{
int b3, b2, b1, b0;
printf("get onchip fwInfo:\n");
printf("name: %s\n", onchipFW.name);
b3 = onchipFW.version >> 24;
b2 = (onchipFW.version >> 16) & 0xFF;
b1 = (onchipFW.version >> 8) & 0xFF;
b0 = onchipFW.version & 0xFF;
printf("version: V%d.%d.%d.%d\n", b3, b2, b1, b0);
b3 = onchipFW.pid >> 24;
b2 = (onchipFW.pid >> 16) & 0xFF;
b1 = (onchipFW.pid >> 8) & 0xFF;
b0 = onchipFW.pid & 0xFF;
printf("pid: %d,%d,%d,%d\n", b3, b2, b1, b0);
int y, m, d;
y = onchipFW.date >> 16;
m = (onchipFW.date >> 8) & 0xFF;
d = onchipFW.date & 0xFF;
printf("date: %d-%d-%d\n", y, m, d);
printf("bootTimes:%d\n\n", onchipFW.bootTimes);
}
else
{
printf("iCrc error! 0x%08X,%08X\n", iCrc, onchipFW.infoCrc);
printf("onchip fw empty!\n");
}
// for(int i=0;i<bl->pack.data_size;i++)
// {
// if(i%16==0)printf("\n");
// printf("%02X ",bl->pack.data[i]);
// }
return 0;
}
}
printf("\n reving: %d,0x%08X\n", bl->pack.buffer_size, ret);
for (int i = 0; i < bl->pack.buffer_size; i++)
{
if (i % 16 == 0)
printf("\n");
printf("%02X ", bl->pack.buffer[i]);
}
printf("\n");
delay_ms(1);
if (sendtry++ >= 1)
{
printf("get fwInfo timeout! exit!\n");
return -1;
}
printf(".");
}
printf("\n");
return -2;
}
int erase_flash(bl_info_t *bl)
{
printf("\n\nerase flash...\n");
int sendtry = 0;
uint32_t erase_size = firmware.size;
uint32_t erase_addr = firmware.start_addr;
uint32_t sectorCount = erase_size / bl->sectorSize;
sectorCount += ((erase_size % bl->sectorSize) ? 1 : 0);
printf("erase addr: 0x%08X, erase size: %d, sector count: %d %d\n", erase_addr, erase_size, sectorCount, bl->sectorSize);
while (1)
{
tcflush(f_com, TCIOFLUSH);
bl_pack_send(bl, CMD_ERASE, erase_addr, (uint8_t *)&erase_size, 4);
// printf("Sending:");
// for (int i = 0; i < bl->pack.buffer_size; i++)
// {
// if (i % 16 == 0)
// printf("\n");
// printf("%02X ", bl->pack.buffer[i]);
// }
// printf("\n");
uint32_t endAddr = 0;
int waittry = 0;
printf("erasing...\n");
for (int i = 0; i <= sectorCount; i++)
{
printf("=");
}
printf("\n");
while (1)
{
delay_ms(10);
uint32_t ret = bl_pack_recv(bl);
if (ret == 0 && bl->pack.cmd1 == CMD_ACK)
{
endAddr = bl->pack.data[0] | (bl->pack.data[1] << 8) | (bl->pack.data[2] << 16) | (bl->pack.data[3] << 24);
printf("#");
fflush(stdout);
// delay_ms(1);
// printf("erase addr: 0x%08X, endAddr: 0x%08X\n", bl->pack.addr, endAddr);
if (bl->pack.addr >= endAddr)
{
printf("\n");
for (int i = 0; i <= sectorCount; i++)
{
printf("=");
}
printf("\n");
printf("erase success!\n\n");
return 0;
}
waittry = 0;
}
else
{
if (waittry++ > 10)
{
printf("eraser error at 0x%08X\n", bl->pack.addr);
return -1;
}
}
}
if (sendtry++ >= 2)
{
printf("erase timeout! exit!\n");
return -2;
}
}
return -3;
}
int write_firmware(bl_info_t *bl)
{
uint32_t write_already = 0;
uint32_t write_remain = firmware.size;
uint32_t write_addr = firmware.start_addr;
uint32_t write_size = 0;
uint32_t sendtry = 0;
uint32_t stepPercent = 0;
uint32_t stepPercentPre = 0;
uint32_t stepMax = (firmware.size) / bl->sectorSize;
stepMax = stepMax > 100 ? 100 : stepMax;
printf("programming...\n");
for (int i = 0; i <= stepMax; i++)
{
printf("=");
}
printf("\n");
while (1)
{
write_size = write_remain > bl->sectorSize ? bl->sectorSize : write_remain;
bl_pack_send(bl, CMD_WRITE, write_addr, &firmware_data[write_already], write_size);
int ret = bl_pack_recv(bl);
int waitry = 0;
while (ret != 0)
{
delay_ms(1);
ret = bl_pack_recv(bl);
if (waitry++ > 100)
{
printf("write error [%08X] at 0x%08X, crc error\n", ret, write_addr);
return -1;
}
}
delay_ms(1);
if (ret == 0 && bl->pack.cmd1 == CMD_ACK)
{
write_already += write_size;
write_remain -= write_size;
write_addr += write_size;
stepPercent = (write_already * 100) / firmware.size;
if (stepPercent != stepPercentPre)
{
stepPercentPre = stepPercent;
printf(">");
// printf(">%d%%\n",stepPercent);
fflush(stdout);
}
// printf("write addr: 0x%08X, write_size: %d write_remain:%d\n", write_addr, write_size, write_remain);
if (write_remain == 0)
{
printf("\n");
for (int i = 0; i <= stepMax; i++)
{
printf("=");
}
printf("\n");
printf("Done!\n\n");
return 0;
}
}
else
{
printf("write error [%08X] at 0x%08X\n rev: [%d] \n", ret, write_addr, bl->pack.buffer_size);
for (int i = 0; i < bl->pack.buffer_size; i++)
{
printf("0x%02X ", bl->pack.buffer[i]);
}
printf("\n");
if (sendtry++ >= 10)
{
printf("write timeout! exit!\n");
return -1;
}
}
}
return -2;
}
int read_firmware(bl_info_t *bl)
{
uint32_t read_total = 0;
uint32_t read_size = 0;
uint32_t sendtry = 0;
uint32_t read_addr = firmware.start_addr;
uint32_t read_remain = firmware.size;
uint8_t *firmwareRead = malloc(firmware.size);
if(!firmwareRead)
{
printf("malloc error\n");
return -1;
}
uint32_t packCount = firmware.size / bl->sectorSize;
packCount = packCount > 100 ? 100 : packCount;
uint32_t curPack=0,prePack=0;
printf("Verifying...\n");
for (int i = 0; i <= packCount; i++)
{
printf("=");
// fflush(stdout);
}
printf("\n");
while (1)
{
read_size = read_remain > bl->sectorSize ? bl->sectorSize : read_remain;
bl_pack_send(bl, CMD_READ, read_addr, (uint8_t *)&read_size, 4);
int waitting = 0;
while (1) // wait ack
{
delay_ms(2);
int ret = bl_pack_recv(bl);
if (ret == 0 && bl->pack.cmd1 == CMD_ACK)
{
memcpy(&firmwareRead[read_total], bl->pack.data, bl->pack.data_size);
// printf("read addr: 0x%08X, read_size: %d\n", read_addr, read_size);
if (read_size != bl->pack.data_size)
{
printf("read error at 0x%08X! wanted[%d] get[%d]\n", read_addr, read_size, bl->pack.data_size);
}
read_total += read_size;
read_remain -= read_size;
read_addr += read_size;
sendtry = 0;
curPack = read_total*100/firmware.size;
if(curPack != prePack)
{
prePack = curPack;
printf("<");
fflush(stdout);
}
break;
}
else
{
// printf("rev: 0x%08X, [%d]", ret, bl->pack.buffer_size);
// for (int i = 0; i < bl->pack.buffer_size; i++)
// {
// if (i % 32 == 0)
// printf("\n");
// printf("%02X ", bl->pack.buffer[i]);
// }
// printf("\n");
if (waitting++ > 10)
{
printf("read timeout! exit! at: 0x%08X\n", read_addr);
return -2;
}
}
}
if (read_remain == 0)
{
printf("\n");
for (int i = 0; i <= packCount; i++)
{
printf("=");
// fflush(stdout);
}
printf("\n");
printf("done!\n");
break;
}
if (sendtry++ >= 3)
{
printf("read timeout! exit!\n");
return -1;
}
}
if(readout!=0)
{
FILE *f_read = fopen("./verify.bin", "wb");
if (!f_read)
{
printf("open file error!\n");
}
size_t writeSize = fwrite(firmwareRead, 1, firmware.size, f_read);
if (writeSize != firmware.size)
{
printf("write file error! %d,%d\n", writeSize, firmware.size);
}
fclose(f_read);
}
uint32_t crc = crc32_cal(firmwareRead, firmware.size, CRC32_INIT_VALUE, CRC32_XOR_VALUE, 1, 1);
printf("read crc: 0x%08X\n", crc);
if (crc != firmware.FWcrc)
{
printf("crc error! read crc: 0x%08X, firmware crc: 0x%08X\n", crc, firmware.FWcrc);
for (size_t i = 0; i < firmware.size; i++)
{
if (firmware_data[i] != firmwareRead[i])
{
printf("read error at 0x%08X, [%02X] [%02X]\n", i, firmware_data[i], firmwareRead[i]);
return -1;
}
}
return -1;
}
free(firmwareRead);
printf("crc ok!\n");
return 0;
}
int write_fwInfo(bl_info_t *bl)
{
uint32_t sendtry = 0;
printf("\nUpdating firmware info...\n");
while (1)
{
bl_pack_send(bl, CMD_W_FW_INFO, 0, (uint8_t *)&firmware, sizeof(firmware));
int waitting = 0;
while (1) // wait ack
{
// printf("send: [%D]\n", bl->pack.buffer_size);
// for(int i = 0; i < bl->pack.buffer_size; i++)
// {
// if(i % 32 == 0)
// printf("\n");
// printf("%02X ", bl->pack.buffer[i]);
// }
delay_ms(10);
int ret = bl_pack_recv(bl);
if (ret == 0 && bl->pack.cmd1 == CMD_ACK)
{
printf("Done!\n\n");
return 0;
}
else if (ret == 0 && bl->pack.cmd1 == CMD_NACK)
{
printf("nack! error:%d\n", bl->pack.data_size);
break;
}
else
{
// printf("rev: 0x%08X, [%d]", ret, bl->pack.buffer_size);
// for (int i = 0; i < bl->pack.buffer_size; i++)
// {
// if (i % 32 == 0)
// printf("\n");
// printf("%02X ", bl->pack.buffer[i]);
// }
// printf("\n");
if (waitting++ > 10)
{
printf("wait ack on write fw info timeout!\n");
break;
}
}
}
if (sendtry++ >= 2)
{
printf("write fw info timeout! exit!\n");
return -1;
}
}
return 0;
}
int reset(bl_info_t *bl)
{
uint32_t sendtry = 0;
printf("\nResetting...\n");
while (1)
{
bl_pack_send(bl, CMD_RESET, 0, NULL, 0);
int waitting = 0;
while (1) // wait ack
{
delay_ms(10);
int ret = bl_pack_recv(bl);
if (ret == 0 && bl->pack.cmd1 == CMD_ACK)
{
printf("Done!\n\n");
return 0;
}
else if (ret == 0 && bl->pack.cmd1 == CMD_NACK)
{
printf("nack! error:%d\n", bl->pack.data_size);
}
else
{
if (waitting++ > 10)
{
printf("wait ack on reset timeout!\n");
break;
}
}
}
}
if (sendtry++ >= 2)
{
printf("reset timeout! exit!\n");
return -1;
}
}
/**
* @brief
* make -f ./win_iap_tool/makefile
* ./win_iap_tool/win_iap_tool.exe COM1 921600 "./ZINO PREMIUM RT DRONE V4.0.0.0.bin"
* ./win_iap_tool/win_iap_tool.exe COM5 921600 "./ZINO_PREMIUM_ZINO_FC_V4_V1.0.1_20241119.bin"
* ./win_iap_tool/win_iap_tool.exe COM3 921600 "./ZINO_PREMIUM_ZINO_FC_V4_V1.0.1_20241120.bin"
* ./win_iap_tool/win_iap_tool.exe COM5 921600 "./ZINO_DPS_ZINO_POWER_V1.0.1_20241224.bin"
* @param argc 4
* @param argv [com] [baudrate] [firmware]
* @return int
*/
int main(int argc, char *argv[])
{
bootloader.read = bl_read;
bootloader.write = bl_write;
bootloader.sectorSize = FLASH_SectorSize;
// ffmpeg -i ./wav/happy_new_year.wav ./wav/happyNewYear.sbc -ar 8000
//"ls /dev/tty*"可扫描口列表
// gcc ./AromatherapyDiffuser/hardware/W25QXX/loadSbc.c -o loadsbc
// printf("system run \n");
#if 0
/**NOTE 使用 "-"来区分指令,不过没有必要 */
struct
{
char *cmd;
char *param[16];
uint8_t paramCount;
} cmdlist[16] = {0};
uint8_t cmdlistCount = 0;
uint8_t cmdParamCount = 0;
for (int i = 1; i < argc; i++)
{
if (argv[i][0] == '-')
{
cmdlist[cmdlistCount].cmd = argv[i];
cmdlist[cmdlistCount].paramCount = 0;
cmdParamCount = 0;
cmdlistCount++;
}
else
{
if (cmdlistCount != 0)
{
cmdlist[cmdlistCount - 1].param[cmdParamCount] = argv[i];
cmdParamCount++;
cmdlist[cmdlistCount - 1].paramCount = cmdParamCount;
}
}
}
printf("cmdlistCount:%d\n", cmdlistCount);
for (int i = 0; i < cmdlistCount; i++)
{
printf("cmdlist[%d]:%s", i, cmdlist[i].cmd);
if (cmdlist[i].paramCount != 0)
{
for (int j = 0; j < cmdlist[i].paramCount; j++)
{
printf(" %s", cmdlist[i].param[j]);
}
}
printf("\n");
}
#endif
if (argc < 4)
{
printf("Usage:%s [com] [baudrate] [firmware]\n", argv[0]);
printf("Example:\n ./win_iap_tool COM9 921600 \"./ZINO PREMIUM RT DRONE V4.0.0.0.bin\"\n");
return -1;
}
if (argc >= 5)
{
SetSize = atoi(argv[4]);
}
if(argc >= 6)
{
readout = atoi(argv[5]);
}
printf("\n\n * * * * * * ZINO Firmware Burning Tool V2.0.0 * * * * * * \n\n");
/**serial port init */
int baudrate = atoi(argv[2]);
char *com = argv[1];
if (serial_init(&f_com, com, baudrate) != 0)
{
printf("serial init error!\n");
return -1;
}
// 判断文件尾缀是否为.bin
char *fw_file = argv[3];
int fw_file_len = strlen(fw_file);
if (strcmp(fw_file + fw_file_len - 4, ".bin") != 0)
{
printf("bin file error! Only accept *.bin file!\n");
return -1;
}
printf("\nbin file:%s\n", fw_file);
FILE *f_fw = fopen(fw_file, "r");
if (f_fw == NULL)
{
printf("bin file open error! %s\n", strerror(errno));
return -1;
}
printf("firmware extract...\n");
if (firmware_extract(f_fw, &firmware) != 0)
{
printf("firmware extract error!\n");
return -1;
}
size_t sector_size = FLASH_SectorSize;
size_t read_size = 0;
size_t total_write = 0;
size_t total_pack = firmware.size / sector_size + (firmware.size % sector_size ? 1 : 0);
size_t pack_count = 0;
uint32_t write_addr = firmware.start_addr;
uint32_t sector_count = 0;
// printf("total_pack:%d\n", total_pack);
timer_t startTime = time(NULL);
timer_t frameTime = time(NULL);
timer_t frameTimeUsed = time(NULL);
timer_t totalTime = time(NULL);
timer_t totalTimeUsed = time(NULL);
/**NOTE SYNC */
if (dev_sync(bl) != 0)
{
printf("dev_sync error!\n");
return -1;
}
/**NOTE GET VERSION */
if (getVersion(bl) != 0)
{
printf("dev_get_version error!\n");
return -1;
}
/**NOTE GET ID */
if (getId(bl) != 0)
{
printf("dev_get_id error!\n");
return -1;
}
/**NOTE GET fwInfo */
if (get_fwInfo(bl) != 0)
{
printf("dev_get_fwinfo error!\n");
return -1;
}
/**NOTE ERASE FLASH */
if (erase_flash(bl) != 0)
{
printf("erase_flash error!\n");
return -1;
}
/** NOTE WRITE FLASH */
if (write_firmware(bl) != 0)
{
printf("write_firmware error!\n");
return -1;
}
/** NOTE read FLASH */
if (read_firmware(bl) != 0)
{
printf("read_firmware error!\n");
return -1;
}
/**NOTE write fwInfo */
if (write_fwInfo(bl) != 0)
{
printf("write_fwInfo error!\n");
return -1;
}
/**NOTE RESET */
if (reset(bl) != 0)
{
printf("reset error!\n");
return -1;
}
free(firmware_data);
tcflush(f_com, TCIOFLUSH); // 刷新输入输出缓冲区
close(f_com);
return 0;
}
运行结果:
$ make -j16 dl
./UploadTool/win_iap_tool.exe COM3 921600 ZINO_DPS_ZINO_POWER_V1.0.1_20250110.bin
* * * * * * ZINO Firmware Burning Tool V2.0.0 * * * * * *
comIndex = 2
com = /dev/ttyS2
baudrate:921600
serial open
serial init done
bin file:ZINO_DPS_ZINO_POWER_V1.0.1_20250110.bin
firmware extract...
*name : ZINO_DPS_ZINO_POWER_V1.0.1_20250110.bin
*infoCrc : 0x40693BE8
*magic : 0x5A1234A5
*startAddr: 0x08004000
*size : 0x00015EFC
*FWcrc : 0xFF0BC36F
*version : 0x00000001
*pid : 0x01020304
*date : 0x07E80B13
*Serial : 0x00000047
*ID : 0x00030240
*Model : 0x0000000F
*Flash : 0x00000002
*Footprint: 0x00000003
FWcrc: 0xFF0BC36F
Try to sync
rev: 0
Sync success!
get version
get version success
version:0x02000000
get id...
get id success
*Serial : 0x00000047
*ID : 0x00030240
*Model : 0x0000000F
*Flash : 0x00000002
*Footprint: 0x00000003
*UID : 488D3504000064710917D904
- - - MCU match! - - -
get fwInfo...
get fwInfo success:crc 0xF974C5F7
get onchip fwInfo:
name: ZINO_DPS_ZINO_POWER_V1.0.1_20250110.bin
version: V0.0.0.1
pid: 1,2,3,4
date: 2024-11-19
bootTimes:0
erase flash...
erase addr: 0x08004000, erase size: 89852, sector count: 44 2048
erasing...
=============================================
#############################################
=============================================
erase success!
programming...
============================================
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
============================================
Done!
Verifying...
============================================
<<<<<<<<<<<<<<<<rev: 0xFFFFFFFF, [0]
<rev: 0xFFFFFFFF, [0]
<<<<<<<<<<<<<<<<<<<<<<<<<<<
============================================
done!
read crc: 0xFF0BC36F
crc ok!
Updating firmware info...
Done!
Resetting...
Done!