stm32 IAP 功能,自定义协议,使用 Python 脚本下发固件

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

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



您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yyyang88

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值