GD32f103C8T6 IAP 升级教程
参考stm32的IAP升级原理
IAP测试源码
GD32和stm32的内核都是一样的,又因为IAP升级主要涉及升级的路径之和内核先关,所以gd32和stm32升级IAP升级是一样的。
0.升级原理
GD32的内部(FLASH)地址起始于0x08000000,一般情况下,程序就从此地址开始写入,此外GD32是基于Cortex-M3内核的微控制器,其内部通过一张“中断向量表”来响应中断,程序启动后,将首先从“中断向量表”取出复位中断向量执行复位中断程序完成启动,而这张“中断向量表”的起始地址是0x08000004,当中断来临,GD32的内部硬件机制亦会自动将PC指针定位到“中断向量表”处,并根据中断源取出对应的中断向量执行中断服务程序。在上图中,GD32在复位后,先从0x08000004地址取出复位中断向量的地址,并跳转到复位中断服务程序,如图标号①所示:在复位中断服务程序执行完之后,会跳转到我们的main函数,如图标号②所示;而我们的main函数一般都是一个死循环,在main函数执行过程中,如果收到中断请求(发生中断),此时GD32强制将PC指针指向中断向量表处,如图标号③所示;然后根据中断源进入相应的中断服务程序,如图标号④所示;在执行完中断服务程序以后,程序再次返回main函数执行,如图⑤所示。
当加入IAP程序之后,程序运行流程如图下所示:
在上面所示流程图中,GD32复位后,还是从0x08000004地址取出复位中断向量的地址并跳转到复位中断服务程序,在运行完复位中断服务程序之后跳转到IAP的main函数,如图标号①所示;在执行IAP以后(即将新的APP代码写入GD32的FLASH,灰底部分。新程序的复位中断向量起始地址0x08000004+N+M),跳转至新写入程序的复位向量表,取出新程序的复位中断向量的地址,并跳转执行新程序的复位中断服务程序,随后跳转至新程序的main函数,如图标号②和③所示,同样main函数为一个死循环,并且注意到此时GD32的FLASH,在不同位置上,共有两个中断向量表。在main函数执行过程中,如果CPU得到一个中断请求,PC指针仍强制跳转到地址0x08000004中断向量处,而不是新程序的中断向量处,如图④所示;程序再根据我们设置的中断向量表偏移量,跳转到对应中断源新的中断服务程序中,如图标号⑤所示;在执行完中断服务程序后,程序返回main函数继续运行,如标号⑥所示
1.升级条件/环境
gd32f103c8t6 ROM 地址范围ROM 地址范围: 0x800 0000~0x800 FFFF 合计64K
扇区大小 1024Byte
falsh 空间分配设置
boot loader 分配30K空间 flash 0x8000000-0x80077ff user bin 分配34k空间 flash 0x8007800-0x800ffff
2.bin程序
app程序功能是 LED0间隔1s闪烁,每秒打印app is run
1.设置flash地址和flash大小
2.添加生成bin文件地址
注意:下边命令中涉及到的路径需要和实际路径向匹配,涉及3个路径
- fromelf.exe 文件路径(一般都和我一样的)
- GD32F103C8T6.bin 文件路径 保存bin文件路径
- GD32F103C8T6.axf mkd生成axf的文件路径
C:\Keil_v5\ARM\ARMCC\bin\fromelf.exe --bin -o GD32F103C8T6.bin .\Objects\GD32F103C8T6.axf
3.修改中断偏移地址
2.bootload 程序
使用串口的中断+空闲中断方式接收数据,然后使用按键作为触发动作写入bin文件内容到flash,
最后跳转至APP程序;
1.中断接收程序
#ifndef __GD32_BSP_UART_H__
#define __GD32_BSP_UART_H__
#include "stdint.h"
#define CACHE_NUM 1024*10
extern volatile uint16_t rxcount ;
extern volatile uint8_t idle_or_full;
extern uint8_t rxbuffer[CACHE_NUM];
void usart_base_init(void);
void enable_uart_interrupt(void);
#endif
#include "gd32f10x.h"
#include "stdio.h"
#include "bsp_uart.h"
uint8_t rxbuffer[CACHE_NUM];
volatile uint16_t rxcount = 0;
volatile uint8_t idle_or_full=0;
int fputc(int ch, FILE *f)
{
usart_data_transmit(USART0, (uint8_t)ch);
int cnt=1000;
while(RESET == usart_flag_get(USART0, USART_FLAG_TBE) &&cnt--);
return ch;
}
void usart_base_init(void)
{
rcu_periph_clock_enable(RCU_USART0);
#if defined USART0_REMAP
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_AF);
gpio_pin_remap_config(GPIO_USART0_REMAP, ENABLE);
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
#else
rcu_periph_clock_enable(RCU_GPIOA);
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);
#endif
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);
}
void enable_uart_interrupt(void)
{
nvic_irq_enable(USART0_IRQn, 1, 1);
usart_interrupt_flag_clear(USART0, USART_INT_RBNE);
usart_interrupt_flag_clear(USART0, USART_INT_IDLE);
usart_interrupt_enable(USART0, USART_INT_RBNE);
usart_interrupt_enable(USART0, USART_INT_IDLE);
}
void USART0_IRQHandler(void)
{
if(RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE))
{
rxbuffer[rxcount++] = usart_data_receive(USART0);
}
else if(RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE))
{
usart_data_receive(USART0);
idle_or_full=1;
}
}
2.flash跳转程序
#ifndef __GD32_FLASH_H__
#define __GD32_FLASH_H__
#include "stdint.h"
#include "stdio.h"
void write_flash(uint32_t write_addr, uint32_t *data, int len);
void read_4Btye(uint32_t read_addr, uint32_t *data, uint32_t len);
#endif
#include "gd32f10x.h"
#include <stdio.h>
#include "bsp_flash.h"
#define FMC_PAGE_SIZE ((uint16_t)0x400U)
void read_4Btye(uint32_t read_addr, uint32_t *data, uint32_t len)
{
int dest_addr;
dest_addr = read_addr & 0xfffffffc;
dest_addr += read_addr & 0x03 > 0 ? 4 : 0;
int real_len = len >> 2;
uint32_t *addr = (uint32_t*)dest_addr;
for(int i = 0; i < real_len; i++)
{
*(data + i) = *(addr + i);
}
}
int check_ease(int start_addr )
{
uint32_t *addr = (uint32_t*)start_addr;
for(int i = 0; i<FMC_PAGE_SIZE >> 2; i++)
{
if(*(addr + i) != 0xffffffff)
{
return 1;
}
}
return 0;
}
void ease_flash(uint32_t write_addr, int page_num)
{
int i = 0;
uint32_t page_offset = write_addr & (FMC_PAGE_SIZE - 1);
page_offset = page_offset >> 2;
uint32_t start_addr = write_addr & (0xffffffff - FMC_PAGE_SIZE + 1);
uint32_t *addr = (uint32_t*)start_addr;
uint32_t *buff = (uint32_t*)malloc(FMC_PAGE_SIZE);
if(page_offset)
{
for( i = 0; i < page_offset; i++)
{
buff[i] = *(addr + i);
}
}
uint32_t erase_counter;
fmc_unlock();
fmc_flag_clear(FMC_FLAG_BANK0_END);
fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
for(erase_counter = 0; erase_counter < page_num; erase_counter++)
{
if(check_ease(start_addr + FMC_PAGE_SIZE * erase_counter))
{
fmc_page_erase(start_addr + FMC_PAGE_SIZE * erase_counter);
fmc_flag_clear(FMC_FLAG_BANK0_END);
fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
}
}
if(page_offset)
{
for( i = 0; i < page_offset; i++)
{
fmc_word_program(start_addr + (i * 4), *(buff + i));
fmc_flag_clear(FMC_FLAG_BANK0_END);
fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
}
}
fmc_lock();
free(buff);
}
void write_flash(uint32_t write_addr, uint32_t *data, int len)
{
int dest_addr;
dest_addr = write_addr & 0xfffffffc;
dest_addr += write_addr & 0x03 > 0 ? 4 : 0;
uint32_t page_num = len / FMC_PAGE_SIZE;
page_num += len % FMC_PAGE_SIZE ? 1 : 0;
ease_flash(dest_addr, page_num);
int len_4Byte = len >> 2;
fmc_unlock();
for(int i = 0; i < len_4Byte; i++)
{
fmc_word_program(dest_addr + i * 4, *(data + i));
fmc_flag_clear(FMC_FLAG_BANK0_END);
fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
}
fmc_lock();
}
3.APP程序跳转
#ifndef _IAP_
#define _IAP_
#include "gd32f10x.h"
#include "stdint.h"
#define FLASH_APP1_ADDR 0x08007800
typedef void (*iapfun)(void);
void MSR_MSP(uint32_t addr);
void iap_load_app(uint32_t appxaddr);
#endif
#include "bsp_iap_bootloader.h"
__asm void MSR_MSP(uint32_t addr)
{
MSR MSP, r0
BX r14
}
iapfun jump2app;
void iap_load_app(uint32_t appxaddr)
{
if(((*(uint32_t*)appxaddr)&0x2FFE0000)==0x20000000)
{
jump2app=(iapfun)*(uint32_t*)(appxaddr+4);
MSR_MSP(*(uint32_t*)appxaddr);
jump2app();
}
}
4.主函数
#include "gd32f10x.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "string.h"
#include "bsp_uart.h"
#include "bsp_exti.h"
#include "gd32f103c_sys.h"
#include "bsp_flash.h"
#include "bsp_iap_bootloader.h"
#define LED0 PBout(13)
#define LED1 PBout(14)
#define LED2 PBout(15)
#define LED3 PAout(8)
int main(void)
{
int bin_size;
systick_config();
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
rcu_periph_clock_enable(RCU_GPIOB);
gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
usart_base_init();
enable_uart_interrupt();
exit_gpio_init();
input_exti_init();
while (1)
{
LED2 = !LED2;
delay_1ms(50);
if (idle_or_full)
{
printf("read len = %d:", rxcount);
for (int i = 0; i < rxcount; i++)
{
printf("%02x ", (int)rxbuffer[i]);
}
printf("\r\n");
idle_or_full = 0;
bin_size = rxcount;
rxcount = 0;
}
if(exti_flag)
{
exti_flag=0;
write_flash(FLASH_APP1_ADDR,(uint32_t*)rxbuffer,bin_size);
printf("wirte app\r\n");
if(((*(uint32_t*)(FLASH_APP1_ADDR+4))&0xFF000000)==FLASH_BASE)
{
iap_load_app(FLASH_APP1_ADDR);
}
printf("update app\r\n");
}
}
}
其他辅助:
文件发送工具XCOM:
测试结果
|