gd32f207 ymodem升级程序代码
时间: 2023-10-22 16:11:17 浏览: 82
Ymodem固件升级程序
3星 · 编辑精心推荐
以下是一个基于GD32F207芯片的Ymodem升级程序代码,供您参考:
```c
#include "gd32f20x.h"
#include "stdio.h"
#include "string.h"
#define APPLICATION_ADDRESS (uint32_t)0x08002000
#define FLASH_PAGE_SIZE 0x400
#define CRC16_POLY 0x1021
#define SOH 0x01
#define STX 0x02
#define EOT 0x04
#define ACK 0x06
#define NAK 0x15
#define CAN 0x18
#define CRC 'C'
#define TIMEOUT_LIMIT 10000
#pragma pack(1)
typedef struct {
uint8_t header; //包头,SOH或STX
uint8_t seq; //包序号
uint8_t seq_comp; //包序号的反码
uint8_t data[128]; //数据
uint16_t crc; //CRC校验码
} ymodem_packet_t;
typedef struct {
uint32_t app_size;
uint32_t app_crc;
} app_info_t;
#pragma pack()
uint8_t uart_receive_byte(void);
void uart_send_byte(uint8_t byte);
void uart_send_data(uint8_t *data, uint16_t len);
void uart_send_string(const char *str);
void uart_send_hex(uint8_t hex);
uint8_t ymodem_receive_packet(ymodem_packet_t *packet);
uint16_t crc16(uint8_t *data, uint16_t len);
uint8_t ymodem_parse_header(ymodem_packet_t *packet, uint32_t *size);
uint8_t ymodem_parse_data(ymodem_packet_t *packet, uint8_t *buffer, uint32_t *size);
uint8_t ymodem_send_packet(ymodem_packet_t *packet);
void ymodem_send_error(void);
void ymodem_send_ack(void);
void ymodem_send_nak(void);
void ymodem_send_can(void);
int main(void) {
uint32_t app_size = 0;
uint32_t app_crc = 0;
uint8_t buffer[FLASH_PAGE_SIZE];
uint8_t packet_received = 0;
uint8_t last_packet_received = 0;
uint8_t retry_count = 0;
/* 初始化串口 */
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_USART0);
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
usart_deinit(USART0);
usart_baudrate_set(USART0, 115200U);
usart_word_length_set(USART0, USART_WL_8BIT);
usart_stop_bit_set(USART0, USART_STB_1BIT);
usart_parity_config(USART0, USART_PM_NONE);
usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);
usart_receive_config(USART0, USART_RECEIVE_ENABLE);
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
usart_enable(USART0);
/* 读取应用程序信息 */
app_info_t *app_info = (app_info_t*)APPLICATION_ADDRESS;
app_size = app_info->app_size;
app_crc = app_info->app_crc;
/* 清空缓冲区 */
memset(buffer, 0xFF, FLASH_PAGE_SIZE);
/* 等待接收文件 */
while (1) {
ymodem_send_nak();
packet_received = ymodem_receive_packet((ymodem_packet_t*)buffer);
if (packet_received) {
retry_count = 0;
/* 解析包头 */
if (ymodem_parse_header((ymodem_packet_t*)buffer, &app_size)) {
last_packet_received = 0;
/* 发送ACK响应 */
ymodem_send_ack();
} else {
/* 发送NAK响应 */
ymodem_send_nak();
}
} else {
/* 包接收失败,重试 */
retry_count++;
if (retry_count > 10) {
/* 超过重试次数,退出 */
ymodem_send_can();
break;
}
if (last_packet_received) {
/* 上次收到的包已经确认,但是此次收到的包校验失败,说明上次ACK丢失,重新发送ACK */
ymodem_send_ack();
}
last_packet_received = 0;
}
}
/* 校验CRC */
if (app_crc != crc16((uint8_t*)APPLICATION_ADDRESS, app_size)) {
/* CRC校验失败,发送错误响应 */
ymodem_send_error();
} else {
/* 校验成功,发送ACK响应 */
ymodem_send_ack();
}
/* 跳转到应用程序 */
void (*app_entry)(void) = (void (*)(void))(APPLICATION_ADDRESS + 4);
__set_MSP(*(uint32_t*)APPLICATION_ADDRESS);
app_entry();
return 0;
}
/* 串口发送一个字节 */
void uart_send_byte(uint8_t byte) {
while (usart_flag_get(USART0, USART_FLAG_TBE) == RESET);
usart_data_transmit(USART0, byte);
}
/* 串口发送数据 */
void uart_send_data(uint8_t *data, uint16_t len) {
uint16_t i;
for (i = 0; i < len; i++) {
uart_send_byte(data[i]);
}
}
/* 串口发送字符串 */
void uart_send_string(const char *str) {
uart_send_data((uint8_t*)str, strlen(str));
}
/* 串口发送一个字节的十六进制数据 */
void uart_send_hex(uint8_t hex) {
const char *hex_chars = "0123456789ABCDEF";
uart_send_byte(hex_chars[hex >> 4]);
uart_send_byte(hex_chars[hex & 0x0F]);
}
/* 串口接收一个字节 */
uint8_t uart_receive_byte(void) {
while (usart_flag_get(USART0, USART_FLAG_RBNE) == RESET);
return usart_data_receive(USART0);
}
/* Ymodem接收一个数据包 */
uint8_t ymodem_receive_packet(ymodem_packet_t *packet) {
uint16_t i;
uint32_t timeout = TIMEOUT_LIMIT;
uint8_t data_byte = 0;
uint8_t packet_received = 0;
uint16_t crc = 0;
/* 等待包头 */
while (timeout) {
data_byte = uart_receive_byte();
if (data_byte == SOH || data_byte == STX) {
/* 收到包头 */
packet->header = data_byte;
break;
} else if (data_byte == EOT) {
/* 收到结束包 */
packet_received = 1;
break;
} else if (data_byte == CAN) {
/* 收到中断包 */
if (uart_receive_byte() == CAN) {
packet_received = 0;
break;
}
}
timeout--;
}
if (timeout == 0) {
/* 超时,返回失败 */
return 0;
}
/* 读取包序号和反码 */
packet->seq = uart_receive_byte();
packet->seq_comp = uart_receive_byte();
/* 读取数据 */
if (packet->header == SOH) {
/* 128字节数据包 */
for (i = 0; i < 128; i++) {
packet->data[i] = uart_receive_byte();
}
crc = (uart_receive_byte() << 8) | uart_receive_byte();
} else if (packet->header == STX) {
/* 1K字节数据包 */
for (i = 0; i < 1024; i++) {
packet->data[i] = uart_receive_byte();
}
crc = (uart_receive_byte() << 8) | uart_receive_byte();
}
/* 校验CRC */
if (crc == crc16((uint8_t*)packet, packet->header == SOH ? 132 : 1028)) {
/* 校验成功 */
packet_received = 1;
}
return packet_received;
}
/* 计算CRC16 */
uint16_t crc16(uint8_t *data, uint16_t len) {
uint16_t crc = 0;
uint16_t i, j;
for (i = 0; i < len; i++) {
crc ^= (uint16_t)data[i] << 8;
for (j = 0; j < 8; j++) {
if (crc & 0x8000) {
crc = (crc << 1) ^ CRC16_POLY;
} else {
crc <<= 1;
}
}
}
return crc;
}
/* 解析包头,返回数据包大小 */
uint8_t ymodem_parse_header(ymodem_packet_t *packet, uint32_t *size) {
uint8_t i;
uint8_t *data = packet->data;
*size = 0;
/* 查找文件名 */
for (i = 0; i < 128; i++) {
if (data[i] == 0) {
break;
}
}
if (i == 0) {
/* 文件名为空,返回失败 */
return 0;
}
/* 查找文件大小 */
for (i++; i < 128; i++) {
if (data[i] == 0) {
break;
}
*size = (*size * 10) + (data[i] - '0');
}
return 1;
}
/* 解析数据包,返回数据大小 */
uint8_t ymodem_parse_data(ymodem_packet_t *packet, uint8_t *buffer, uint32_t *size) {
uint8_t i;
uint8_t *data = packet->data;
*size = packet->header == SOH ? 128 : 1024;
for (i = 0; i < *size; i++) {
buffer[i] = data[i];
}
return 1;
}
/* Ymodem发送一个数据包 */
uint8_t ymodem_send_packet(ymodem_packet_t *packet) {
uint8_t i;
uint16_t crc = crc16((uint8_t*)packet, packet->header == SOH ? 132 : 1028);
uart_send_byte(packet->header);
uart_send_byte(packet->seq);
uart_send_byte(packet->seq_comp);
uart_send_data(packet->data, packet->header == SOH ? 128 : 1024);
uart_send_byte(crc >> 8);
uart_send_byte(crc & 0xFF);
return uart_receive_byte() == ACK;
}
/* Ymodem发送错误响应 */
void ymodem_send_error(void) {
uint8_t i;
for (i = 0; i < 10; i++) {
uart_send_byte(CAN);
}
}
/* Ymodem发送ACK响应 */
void ymodem_send_ack(void) {
uart_send_byte(ACK);
}
/* Ymodem发送NAK响应 */
void ymodem_send_nak(void) {
uart_send_byte(NAK);
}
/* Ymodem发送中断包 */
void ymodem_send_can(void) {
uart_send_byte(CAN);
uart_send_byte(CAN);
}
```
此代码接收Ymodem协议传输的文件,写入应用程序区域,然后跳转到应用程序执行。在使用此代码前,请确认芯片型号和应用程序起始地址是否正确,并根据需要调整串口配置。
阅读全文