嵌入式GD32F4学习笔记

嵌入式主机通过串口 ISP 升级程序


备注:该升级程序方法是单片机给单片机升级程序,因此,在升级程序前必须在主机当中写入待下载的程序。该方法比较方便无需通过电脑下载,适合户外携带维护和批量下载的情况。
由于使用 ISP 上位机升级程序需要借助电脑,在实际生产过程中会带来不便。因此实现了一种嵌入式 ISP 主机用于对目标 MCU 的程序进行升级。嵌入式主机根据 ISP 协议通过串口与 BootLoader 进行通信,从而实现对目标 MCU 程序的升级。
BOOTLOAD引导模式:
在这里插入图片描述
BOOT1接地情况下:
在这里插入图片描述

硬件连接:
在这里插入图片描述

串口初始化


串口初始化:

/*!
 \brief configure COM port
 \param[in] com: COM on the board
 \arg EVAL_COM1: COM1 on the board
 \arg EVAL_COM2: COM2 on the board
 \param[out] none
 \retval none
*/
void gd_eval_com_init(uint32_t com)
{
 uint32_t com_id = 0U;
 if(EVAL_COM1 == com){
 com_id = 0U;
 }else if(EVAL_COM2 == com){
 com_id = 1U;
 }
 /* enable GPIO clock */
 rcu_periph_clock_enable(COM_GPIO_CLK[com_id]);
 /* enable USART clock */
 rcu_periph_clock_enable(COM_CLK[com_id]);
 /* connect port to USARTx_Tx */
 gpio_init(COM_GPIO_PORT[com_id], GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, 
COM_TX_PIN[com_id]);
 /* connect port to USARTx_Rx */
 gpio_init(COM_GPIO_PORT[com_id], GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, 
COM_RX_PIN[com_id]);
 /* USART configure */
 usart_deinit(com);
 usart_parity_config(com, USART_PM_EVEN);
 usart_word_length_set(com, USART_WL_9BIT);
 usart_baudrate_set(com, 57600U);
 usart_receive_config(com, USART_RECEIVE_ENABLE);
 usart_transmit_config(com, USART_TRANSMIT_ENABLE);
 usart_enable(com);
}

控制管脚配置

/* enable the clock */
rcu_periph_clock_enable(RCU_GPIOA);
/* configure BOOT0_CTL port */
gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
gpio_bit_reset(GPIOA, GPIO_PIN_0);
/* configure NRST_CTL port */
gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
gpio_bit_set(GPIOA, GPIO_PIN_1);

升级程序


待下载 bin2 在下载之前存储到嵌入式主机 0x08004000 地址处,格式为 bin2=bin 文件大小(4
字节)+bin1 文件。可根据需要将 bin 文件存储在其他位置,bin 格式也可以自由设置。
升级主程序流程图:
在这里插入图片描述

升级步骤


1.将目标MCU Boot0拉高

void boot0_high(void)
{
 gpio_bit_set(GPIOA, GPIO_PIN_0);
 /* pull up the target reset pin */
 gpio_bit_reset(GPIOA, GPIO_PIN_1);
 gpio_bit_set(GPIOA, GPIO_PIN_1);
 /* wait for the target to reset */
 delay_1ms(300);
}

2.发送握手命令,当嵌入式主机收到0x79,说明握手成功。

ErrStatus usart_handshake(void)
{
	 uint16_t count = 0;
	 while(count++<10)
	 {
		 usart_data_transmit(USART0, 0x7F);
		 while(RESET == usart_flag_get(USART0, USART_FLAG_TC));
		 while((ERROR == ack_flag) && (timeout--))
		 {
		 }
		 if(0 != timeout)
		 {
			 ack_flag = ERROR;
			 return SUCCESS;
		 }
	 }
 return ERROR;
}

3.发送页擦除命令
首先根据 GD32F4xx flash 结构以及 bin 文件的大小索引需要擦除的扇区。

static uint32_t f4_get_sector_number(uint32_t bin_size)
{
 uint32_t sector_size[32] = {16, 16, 16, 16, 64, 128, 128, 128, 128, 128, 128, 128, 
 16, 16, 16, 16, 64, 128, 128, 128, 128, 128, 128, 128, 
256, 256, 256, 256, 256, 256, 256};
 uint32_t i,j;
 uint32_t sector_number = 0;
uint32_t sector_address;
 sector_address = 0x08000000 + bin_size;
 for(i=0; i<31; i++){
 uint32_t start_address = 0x08000000;
 uint32_t end_address = 0x08000000;
 for(j=0; j<=i; j++){
 start_address += sector_size[j] * 1024;
 end_address += sector_size[j] * 1024;
 }
 start_address -= sector_size[i] * 1024;
 end_address -= 1;
 if(sector_address>=start_address && sector_address<=end_address){
 sector_number = i;
 break;
 }
 }
 return sector_number;
}

4.执行擦除命令

ErrStatus usart_send_erase_command(void)
{
 uint32_t bin_size;
 uint16_t sector_number = 0;
 uint32_t i, temp;
/* extend erase command */
 buffer_cmd[0] = 0x44;
buffer_cmd[1] = 0xFF - buffer_cmd[0];
/* get the bin size */
 bin_size = *(uint32_t *)(0x8004000);
 bin_size = bin_size;
 sector_number = f4_get_sector_number(bin_size);
 usart_buffer_send(buffer_cmd, 2);
 if(SUCCESS != wait_ack()){
 return ERROR;
 }
 buffer_cmd[0] = (sector_number>>8) & 0xff;
 buffer_cmd[1] = sector_number & 0xff;
 for(i=0; i<sector_number+1; i++){
 temp = 2+2*i;
 buffer_cmd[temp] = (i>>8) & 0xff;
 buffer_cmd[temp+1] = i & 0xff;
 }
 
 buffer_cmd[temp+2] = data_xor(buffer_cmd, temp+2);
 usart_buffer_send(buffer_cmd, temp+3);
 if(SUCCESS != wait_ack()){
 return ERROR;
 }
 return SUCCESS;
}

4.发生编程指令
根据bin文件大小发送命令
4.1 bin文件大小等于252字节

/*!
 \brief send the program command
 \param[in] pro_addr: the address of the target to be programmed
 \param[in] bin_addr: the address where stored the bin file
 \param[in] pro_size: the size to be programmed
 \param[out] none
 \retval ErrStatus
*/
ErrStatus usart_send_program_command(uint32_t pro_addr, uint32_t bin_addr, uint32_t pro_size)
{
 uint8_t i;
 
 buffer_cmd[0] = USART_CMD_PROGRAM;
 buffer_cmd[1] = 0xFF - buffer_cmd[0];
 
 usart_buffer_send(buffer_cmd, 2);
 
 if(SUCCESS != wait_ack()){
 return ERROR;
 }
 buffer_cmd[0] = (uint8_t)((pro_addr >> 24) & 0xff);
 buffer_cmd[1] = (uint8_t)((pro_addr >> 16) & 0xff);
 buffer_cmd[2] = (uint8_t)((pro_addr >> 8) & 0xff);
 buffer_cmd[3] = (uint8_t)(pro_addr & 0xff);
 buffer_cmd[4] = data_xor(buffer_cmd, 4);
 
 usart_buffer_send(buffer_cmd, 5);
 if(SUCCESS != wait_ack()){
 return ERROR;
 }
 memset(buffer_cmd, 0, sizeof(buffer_cmd));
 buffer_cmd[0] = pro_size-1;
 for(i=0; i<pro_size; i=i+4){
 *((uint32_t *)&buffer_cmd[1+i]) = *(uint32_t *)(bin_addr+4+i);
 }
 buffer_cmd[pro_size + 1] = data_xor(buffer_cmd, pro_size + 1);
 usart_buffer_send(buffer_cmd, pro_size + 2);
 if(SUCCESS != wait_ack()){
 return ERROR;
 }
 memset(buffer_cmd, 0, sizeof(buffer_cmd));
return SUCCESS;
}

4.2 bin文件大252字节
由于 BootLoader 存储空间有限,当 bin 文件大于 252 字节时,需要对 bin 文件进行拆包。

/*!
 \brief send the program command
 \param[in] pro_addr: the address of the target to be programmed
 \param[in] bin_addr: the address where stored the bin file
 \param[out] none
\retval ErrStatus
*/
ErrStatus usart_program_bin(uint32_t pro_addr, uint32_t bin_addr)
{
 uint32_t bin_size;
 uint32_t i;
 uint32_t pack_num, pack_size, res_size;
 /* 4 bytes aligned */
 pack_size = 252;
 
 bin_size = (*(uint32_t *)(bin_addr));
 pack_num = bin_size/pack_size;
 res_size = bin_size % pack_size;
 /* Unpacking the bin and then program to the flash of the target MCU */
 for(i=0; i<pack_num; i++){
 usart_send_program_command(pro_addr + i*pack_size, bin_addr + i*pack_size, 
pack_size);
 }
 if(0 != res_size){
 usart_send_program_command(pro_addr + pack_num*pack_size, bin_addr + 
pack_num*pack_size, res_size);
 }
 return SUCCESS;
}

5.将目标 MCU 的 BOOT0 拉低,并对其进行复位。
将bin文件全部烧入完毕之后,需要将BOOT0拉低,并复位,就可以看到更新之后的功能程序了。

void boot0_low(void)
{
 gpio_bit_reset(GPIOA, GPIO_PIN_0);
 /* pull down the target reset pin */
 gpio_bit_reset(GPIOA, GPIO_PIN_1);
 gpio_bit_set(GPIOA, GPIO_PIN_1);
 /* wait for the target to reset */
 delay_1ms(300);
}

GD32F4系列ISP 串口下载就完成了。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

u011304256

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

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

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

打赏作者

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

抵扣说明:

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

余额充值