1、python 上位机
# 导入模块
import threading
import time
import serial
import serial.tools.list_ports
import binascii
# 自定义变量
port = "COM6" # 端口号,根据自己实际情况输入,可以在设备管理器查看
bps = 115200 # 串口波特率,根据自己实际情况输入
timeout = 5 # 超时时间,None:永远等待操作,0为立即返回请求结果,其他值为等待超时时间(单位为秒)
rxdata = '' # 接收的数据
recv_ack = False
def calculate_crc(txbuf):
crc = 0xFFFF # 初始 CRC 值
length = len(txbuf)
for i in range(0, length, 2):
data = txbuf[i:i+2] # 每次取两个字节
value = int.from_bytes(data, byteorder='little') # 将两个字节转换为整数
crc = crc + value
# 将 CRC 转换为字节序列并返回
return crc & 0xffff
# 扫描端口
def check_uart_port():
port_list = list(serial.tools.list_ports.comports())
# print(port_list)
if len(port_list) == 0:
print('can not fine uart port')
return False
else:
for i in range(0,len(port_list)):
print(port_list[i])
return True
# 打开串口
def open_uart(port, bps, timeout):
try:
# 打开串口,并返回串口对象
uart = serial.Serial(port, bps, timeout=timeout)
return uart
except Exception as result:
print("can not open uart")
print(result)
return False
# 发送数据
def uart_send_data(uart, txbuf):
# len = uart.write(txbuf.encode('utf-8')) # 写数据
len = uart.write(txbuf) # 写数据
return len
# 接收数据
def uart_receive_data(uart):
global recv_ack
if uart.in_waiting:
# rxdata = uart.read(uart.in_waiting).decode("utf-8") # 以字符串接收
rxdata = uart.read().hex() # 以16进制(hex)接收
recv_ack = True
# print(rxdata) # 打印数据
# if (rxdata == 0x11):
# return -1
# return 0
# 关闭串口
def close_uart(uart):
uart.close()
# 创建一个线程用来等待串口接收数据
class myThread (threading.Thread): # 继承父类threading.Thread
def __init__(self, uart):
threading.Thread.__init__(self)
self.uart = uart
self.running = True
def run(self): # 把要执行的代码写到run函数里面 线程在创建后会直接运行run函数
while self.running:
# print("thread_uart_receive")
uart_receive_data(self.uart) # 接收数据
# time.sleep(0.01)
def stop(self):
self.running = False # 设置标志为 False,表示线程应该退出
# 主函数
def main():
# 扫描端口
global recv_ack
result = check_uart_port()
total_len=0
total_time=0
index = 0
head = 'C'
if(result == False):
return
# 打开串口
result = open_uart(port, bps, timeout)
if (result == False):
return
else:
uart1 = result
# 创建一个线程用来接收串口数据
thread_uart = myThread(uart1)
thread_uart.start()
file_path = 'xxx.bin' # 本地二进制文件路径,请替换为实际路径
chunk_size = 200
start_time = int(time.time() * 1000)
with open(file_path, 'rb') as file:
while True:
milliseconds = int(time.time() * 1000)
txbuf = file.read(chunk_size)
if not txbuf: # 文件读取结束
break
pack_len = len(txbuf)
if pack_len < chunk_size: # 最后一包不够100字节,用0xaa补齐
txbuf += bytes([0xaa] * (chunk_size - pack_len))
uart_send_data(uart1, head.encode())
uart_send_data(uart1, pack_len.to_bytes(1, byteorder='big'))
inverted_pack_len = pack_len ^ 0xFF
uart_send_data(uart1, inverted_pack_len.to_bytes(1, byteorder='big'))
send_len = uart_send_data(uart1, txbuf)
crc = calculate_crc(txbuf)
uart_send_data(uart1, crc.to_bytes(2, byteorder='big'))
recv_ack = False
print('CRC:', crc)
index = index+1
total_len = total_len+pack_len
total_time = total_time+(milliseconds-start_time)
start_time = milliseconds
if total_time != 0:
rate = total_len * 1000 / total_time
else:
rate = 0
# print(f"{index} pack len:{pack_len} {rate} B/S")
print(f"{index} pack len:{pack_len} {rate:.2f} B/S")
time.sleep(0.05)
while True:
if recv_ack:
break
# print("wait ack.")
time.sleep(0.01)
print(f"total_len:{total_len} total_time:{total_time/1000}")
thread_uart.stop()
thread_uart.join() # 等待子线程结束
# 启动主函数
main()
2、 boot loader 程序
upgrade_protocol.c
#include "upgrade_protocol.h"
#include "delay.h"
#include "usart.h"
#define FRAME_HEAD_LEN 3
#define FRAME_TAIL_LEN 2
#define FRAME_BODY_LEN 200
#define FRAME_HEAD 'C'
// #define FRAME_HEAD 0x43
enum frame_statu_t{
FRAME_READY,
FRAME_READ_LEN1,
FRAME_READ_LEN2,
FRAME_READ_BODY,
FRAME_READ_CRC_H,
FRAME_READ_CRC_L,
};
static uint8_t frame_len;
static uint16_t frame_crc;
static uint8_t frame_body_buf[FRAME_BODY_LEN];
static enum frame_statu_t frame_status=FRAME_READY;
static uint32_t frame_idx=0;
static uint16_t get_crc(uint16_t *data, uint32_t len){
uint16_t crc = 0xFFFF;
for (uint32_t i = 0; i < len; i++){
crc += data[i];
}
return crc;
}
uint32_t get_frame_data_on_stream(uint8_t * src, uint32_t len, response_ack_t respon){
// uint32_t idx=0;
for (uint32_t i = 0; i < len; i++) {
if(src[i]==FRAME_HEAD && frame_status==FRAME_READY) {
frame_status = FRAME_READ_LEN1;
// printf("get FRAME_READ_LEN1\n");
}else if (frame_status == FRAME_READ_LEN1) {
frame_len = src[i];
frame_status = FRAME_READ_LEN2;
// printf("get FRAME_READ_LEN2\n");
}else if (frame_status == FRAME_READ_LEN2)
{
uint8_t temp = src[i]^ 0xFF;
if(frame_len == temp){
frame_status = FRAME_READ_BODY;
frame_idx = 0;
// printf("get FRAME_READ_BODY\n");
}else{
frame_status = FRAME_READY;
// printf("get FRAME_READY\n");
}
}else if(frame_status == FRAME_READ_BODY){
if(frame_idx < FRAME_BODY_LEN){
frame_body_buf[frame_idx] = src[i];
frame_idx++;
}else if(frame_idx == FRAME_BODY_LEN){
frame_status = FRAME_READ_CRC_H;
frame_crc = src[i];
frame_crc <<= 8;
// printf("get FRAME_READ_CRC_H\n");
}
}else if(frame_status == FRAME_READ_CRC_H){
uint16_t crc = src[i];
frame_crc |= crc;
crc = get_crc((uint16_t*)frame_body_buf, sizeof(frame_body_buf)/2);
// printf("get CRC\n");
if(frame_crc==crc){
// 1帧数据接收完成
respon(frame_body_buf, frame_len, FRAME_BODY_LEN);
frame_status = FRAME_READY;
}else{
frame_status = FRAME_READY;
}
}
}
return 0;
}
upgrade_protocol.h
#ifndef __UPGRADE_PROTOCOL_H__
#define __UPGRADE_PROTOCOL_H__
#include "stdio.h"
typedef void (*response_ack_t)(uint8_t * buf, uint32_t len, uint32_t len_max);
uint32_t get_frame_data_on_stream(uint8_t * src, uint32_t len, response_ack_t respon);
#endif
common.c
#include "common.h"
uint32_t FLASH_PagesMask(__IO uint32_t Size)
{
uint32_t pagenumber = 0x0;
uint32_t size = Size;
if ((size % PAGE_SIZE) != 0)
{
pagenumber = (size / PAGE_SIZE) + 1;
}
else
{
pagenumber = size / PAGE_SIZE;
}
return pagenumber;
}
void Jump_To_Aprom(void){
pFunction aprom;
uint32_t JumpAddress;
if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000) {
/* Jump to user application */
JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
aprom = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
printf("Jump To APROM.\r\n");
USART_Cmd(USART1, DISABLE);
aprom();
}
}
common.h
#ifndef _COMMON_H
#define _COMMON_H
#include "stdio.h"
#include "string.h"
#include "stm32f10x.h"
#if defined (STM32F10X_MD) || defined (STM32F10X_MD_VL)
#define PAGE_SIZE (0x400) /* 1 Kbyte */
#define FLASH_SIZE (0x20000) /* 128 KBytes */
#elif defined STM32F10X_CL
#define PAGE_SIZE (0x800) /* 2 Kbytes */
#define FLASH_SIZE (0x40000) /* 256 KBytes */
#elif defined STM32F10X_HD || defined (STM32F10X_HD_VL)
#define PAGE_SIZE (0x800) /* 2 Kbytes */
#define FLASH_SIZE (0x80000) /* 512 KBytes */
#elif defined STM32F10X_XL
#define PAGE_SIZE (0x800) /* 2 Kbytes */
#define FLASH_SIZE (0x100000) /* 1 MByte */
#else
#error "Please select first the STM32 device to be used (in stm32f10x.h)"
#endif
#define ApplicationAddress 0x8003000
typedef void (*pFunction)(void);
uint32_t FLASH_PagesMask(__IO uint32_t Size);
void Jump_To_Aprom(void);
#endif
ldrom.h
#ifndef __LDROM_H__
#define __LDROM_H__
typedef void (*pFunction)(void);
#endif
main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "ldrom.h"
#include "upgrade_protocol.h"
#include "stm32f10x_flash.h"
#include "common.h"
#define FRAME_RESPONSE_ACK 0x11
static void KEY_Init(void);
static void recv_one_frame_response(uint8_t *src, uint32_t len, uint32_t len_max);
static void EraseFlash(void);
int main(void)
{
uint8_t buf[100];
uint32_t len;
delay_init();
KEY_Init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uart2_init(921600);
struct ring_buf * uart_rx_rb = uart_init(115200);
printf("LDROM Start!\r\n");
if (GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3) == 0x00)
{
printf("\r\n======================================================================");
printf("\r\n= Upgrade =");
printf("\r\n======================================================================");
printf("\r\n\r\n");
// Main_Menu ();
}else{
USART_Cmd(USART1, DISABLE);
Jump_To_Aprom();
}
FLASH_Unlock(); /* FLASH解锁 */
EraseFlash();
while(1)
{
len = ring_buf_get(uart_rx_rb, buf, sizeof(buf));
if(len){
// uart2_send_data(buf, len);
get_frame_data_on_stream(buf, len, recv_one_frame_response);
// uart2_send_data(buf, len);
}
}
}
static void EraseFlash(void){
uint32_t program_size_max = 0x2800; // 10K
uint32_t NbrOfPage = 0;
uint32_t EraseCounter = 0x0;
FLASH_Status FLASHStatus = FLASH_COMPLETE;
uint16_t PageSize = PAGE_SIZE;
uint32_t FlashDestination = ApplicationAddress;
//计算需要擦除Flash的页
NbrOfPage = FLASH_PagesMask(program_size_max);
//擦除Flash
for (EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++){
FLASHStatus = FLASH_ErasePage(FlashDestination + (PageSize * EraseCounter));
}
}
static void recv_one_frame_response(uint8_t *src, uint32_t len, uint32_t len_max){
static int frame_num=0;
static int total_len=0;
static uint32_t FlashDestination = ApplicationAddress;
static uint8_t write_flash_err = 0;
uint32_t RamSource = (uint32_t)src;
uint8_t buf[1];
buf[0] = FRAME_RESPONSE_ACK;
uart1_send_data(buf, sizeof(buf));
if(write_flash_err) return;
total_len += len;
frame_num++;
for (uint32_t i = 0; i < len; i+=4) {
FLASH_ProgramWord(FlashDestination, *(uint32_t*)RamSource);
if (*(uint32_t*)FlashDestination != *(uint32_t*)RamSource) {
printf("write flash err.\n");
write_flash_err = 1;
break;
}
FlashDestination += 4;
RamSource += 4;
}
printf("frame_num:%d total_len:%d\n",frame_num, total_len);
if(len < len_max){
Jump_To_Aprom();
}
}
static void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_Init(GPIOE, &GPIO_InitStructure);
}
usart.c
#include "sys.h"
#include "usart.h"
#include <stdint.h>
#if 0
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//
USART1->DR = (u8) ch;
return ch;
}
#endif
uint32_t uart1_send_data(uint8_t * data, uint32_t len){
for (int idx=0; idx < len; idx++){
while((USART1->SR&0X40)==0);
USART1->DR = ((u8*) data)[idx];
}
return len;
}
uint32_t uart2_send_data(uint8_t * data, uint32_t len){
for (int idx=0; idx < len; idx++){
while((USART2->SR&0X40)==0);
USART2->DR = ((u8*) data)[idx];
}
return len;
}
int _write(int file, char *ptr, int len)
{
// for (int idx=0; idx < len; idx++){
// while((USART1->SR&0X40)==0);
// USART1->DR = ((u8*) ptr)[idx];
// }
uart2_send_data((uint8_t*)ptr, len);
return len;
}
#if EN_USART1_RX //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
static u8 uart_rx_buf[USART_REC_LEN];
static struct ring_buf uart_rx_rb;
static struct ring_buf * uart_buf_init(void){
ring_buf_init(&uart_rx_rb, sizeof(uart_rx_buf), uart_rx_buf);
return &uart_rx_rb;
}
struct ring_buf * uart_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(USART1, ENABLE); //使能串口1
return uart_buf_init();
}
void uart2_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
//USART2_TX GPIOA.2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.2
//USART2_RX GPIOA.3初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.3
//Usart1 NVIC 配置
// NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
// NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Tx; //收发模式
USART_Init(USART2, &USART_InitStructure); //初始化串口2
// USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(USART2, ENABLE); //使能串口2
}
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
res = USART_ReceiveData(USART1); //读取接收到的数据
if(ring_buf_space_get(&uart_rx_rb)>0){
ring_buf_put(&uart_rx_rb, &res, 1);
}
}
}
#endif
usart.h
#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "sys.h"
#include "ring_buffer.h"
// #define USART_REC_LEN 200
#define USART_REC_LEN 1024
#define EN_USART1_RX 1
extern u8 USART_RX_BUF[USART_REC_LEN];
extern u16 USART_RX_STA;
struct ring_buf * uart_init(u32 bound);
uint32_t uart1_send_data(uint8_t * data, uint32_t len);
uint32_t uart2_send_data(uint8_t * data, uint32_t len);
void uart2_init(u32 bound);
#endif
2693

被折叠的 条评论
为什么被折叠?



