简介
在上一篇帖子([IAR] Flash Loader 下载过程解析)中已经介绍了IAR flash 程序下载的过程,其中flah 上内容的跟新是通过C-SPY,将flash 下载算法加载到RAM 中调用flashloader 的下载算法完成,flash 的编程。
上述流程为flashloader 下载算法的主要工作流程,flashloader 下载算法中主要依赖如下flash 写入和擦除的函数。
以下是flashloader 中其他接口功能说明
IAR 针对 flashloader 的制作,也提供了标准的实现模板,我们使用标准模板的基础上实现对应的flash 下载算法就可以实现一个基本功能的flash 下载算法了。IAR 的\arm\src\flashloader安装路径下包含部分flash loader 的示例工程,我们可以基于此模板进行修改,默认的flash loader 程序是不能进行串口打印输出的,我们再次gd32 的flash loader 工程上进行修改,添加串口打印功能方便我们理解flashloader 的工作过程,从以上的函数接口功能描述可知,FlashInit函数是第一个被调用的函数,我们可以在这个函数里添加串口的初始话配置处理。
FlashInit 接口功能描述如下
#if USE_ARGC_ARGV uint32_t FlashInit(void *base_of_flash, uint32_t image_size, uint32_t link_address, uint32_t flags, int argc, char const *argv[]) #else uint32_t FlashInit(void *base_of_flash, uint32_t image_size, uint32_t link_address, uint32_t flags) #endif { uint32_t temp = 0; parallelism = 1; /* enable GPIO clock */ RCU_AHB1EN |= 0x01u << 1; /* enable USART clock */ RCU_APB2EN |= 0x01u <<4; GPIO_CTL(GPIOB) &= ~(0x03u << (2*6)); GPIO_CTL(GPIOB) |= (2 << (2*6)); GPIO_PUD(GPIOB) &= ~(0x03u << (2*6)); GPIO_PUD(GPIOB) |= (1u << (2*6)); GPIO_OMODE(GPIOB) &= ~(0x01u << 6); GPIO_OSPD(GPIOB) &= ~(0x03u << (2*6)); GPIO_OSPD(GPIOB) |= (0x01u << (2*6)); GPIO_AFSEL0(GPIOB) &= ~(0xf << (4*6)); GPIO_AFSEL0(GPIOB) |= (0x7 << (4*6)); /* config uart0 */ uint32_t uclk = 0U, intdiv = 0U, fradiv = 0U, udiv = 0U; uclk = rcu_clock_freq_get(CK_APB2); if(USART_CTL0(USART0) & USART_CTL0_OVSMOD) { /* when oversampling by 8, configure the value of USART_BAUD */ udiv = ((2U * uclk) + 115200 / 2U) / 115200; intdiv = udiv & 0xfff0U; fradiv = (udiv >> 1U) & 0x7U; USART_BAUD(USART0) = ((USART_BAUD_FRADIV | USART_BAUD_INTDIV) & (intdiv | fradiv)); } else { /* when oversampling by 16, configure the value of USART_BAUD */ udiv = (uclk + 115200 / 2U) / 115200; intdiv = udiv & 0xfff0U; fradiv = udiv & 0xfU; USART_BAUD(USART0) = ((USART_BAUD_FRADIV | USART_BAUD_INTDIV) & (intdiv | fradiv)); } USART_CTL0(USART0) &= ~(0x01u << 10); USART_CTL0(USART0) &= ~(0x01u << 12); USART_CTL1(USART0) &= ~(0x03u << 12); USART_CTL0(USART0) |= (0x01u << 3); USART_CTL0(USART0) |= (0x01u << 13); FMC_WS = 0x00000000; temp = FMC_CTL; temp &= ~(0x3u << 8); temp |= (parallelism << 8); FMC_CTL = temp; return 0; }
参考GD32F4 的flash 编程接口实现flashwrite/flasherase 接口。对应实现如下
FlashWrite 接口功能描述如下
uint32_t FlashWrite(void *block_start, uint32_t offset_into_block, uint32_t count, char const *buffer) { uint8_t * dst = (uint8_t *)((unsigned char *)block_start + offset_into_block); uint8_t * src = (uint8_t *)buffer; mini_printf("flash write dst %p %d %d.\r\n",dst,offset_into_block,count); FMC_CTL |= 0x01u; FMC_STAT = 0x1d2; for ( ; count; count -= 8) { while (FMC_STAT & (0x01u<<16)); *((uint64_t *)dst) = *((uint64_t *)src); src += 8; dst += 8; } } while (FMC_STAT & (0x01u<<16)); FMC_CTL &= ~0x01; if(FMC_STAT & 0x1d2) return 1; return 0; }
FlashErase 接口功能描述如下
uint32_t FlashErase(void *block_start, uint32_t block_size) { uint32_t offset = (uint32_t)block_start; uint32_t sector_num = 0; mini_printf("flash erase %x.\r\n",offset); if(offset >= 0x08000000 && offset <= 0x08003fff) { //sector_num = 0; sector_num = 0x00u << 3; } else if(offset >= 0x08004000 && offset <= 0x08007fff) { //sector_num = 1; sector_num = 0x01u << 3; } else if(offset >= 0x08008000 && offset <= 0x0800bfff) { //sector_num = 2; sector_num = 0x02u << 3; } else if(offset >= 0x0800c000 && offset <= 0x0800ffff) { //sector_num = 3; sector_num = 0x03u << 3; } else if(offset >= 0x08010000 && offset <= 0x0801ffff) { //sector_num = 4; sector_num = 0x04u << 3; } else if(offset >= 0x08020000 && offset <= 0x0803ffff) { //sector_num = 5; sector_num = 0x05u << 3; } else if(offset >= 0x08040000 && offset <= 0x0805ffff) { //sector_num = 6; sector_num = 0x06u << 3; } else if(offset >= 0x08060000 && offset <= 0x0807ffff) { //sector_num = 7; sector_num = 0x07u << 3; } else if(offset >= 0x08080000 && offset <= 0x0809ffff) { //sector_num = 8; sector_num = 0x08u << 3; } else if(offset >= 0x080a0000 && offset <= 0x080bffff) { //sector_num = 9; sector_num = 0x09u << 3; } else if(offset >= 0x080c0000 && offset <= 0x080dffff) { //sector_num = 10; sector_num = 10u << 3; } else if(offset >= 0x080e0000 && offset <= 0x080fffff) { //sector_num = 11; sector_num = 11u << 3; } else if(offset >= 0x08100000 && offset <= 0x08103fff) { //sector_num = 12; sector_num = 0x10u << 3; } else if(offset >= 0x08104000 && offset <= 0x08107fff) { //sector_num = 13; sector_num = 0x11u << 3; } else if(offset >= 0x08108000 && offset <= 0x0810Bfff) { //sector_num = 14; sector_num = 0x12u << 3; } else if(offset >= 0x0810C000 && offset <= 0x0810Ffff) { //sector_num = 15; sector_num = 0x13u << 3; } else if(offset >= 0x08110000 && offset <= 0x0811Ffff) { //sector_num = 16; sector_num = 0x14u << 3; } else if(offset >= 0x08120000 && offset <= 0x0813Ffff) { //sector_num = 17; sector_num = 0x15u << 3; } else if(offset >= 0x08140000 && offset <= 0x0815Ffff) { //sector_num = 18; sector_num = 0x16u << 3; } else if(offset >= 0x08160000 && offset <= 0x0817Ffff) { //sector_num = 19; sector_num = 0x17u << 3; } else if(offset >= 0x08180000 && offset <= 0x0819Ffff) { //sector_num = 20; sector_num = 0x18u << 3; } else if(offset >= 0x081A0000 && offset <= 0x081BFfff) { //sector_num = 21; sector_num = 0x19u << 3; } else if(offset >= 0x081C0000 && offset <= 0x081DFfff) { //sector_num = 22; sector_num = 0x1au << 3; } else if(offset >= 0x081E0000 && offset <= 0x081FFfff) { //sector_num = 23; sector_num = 0x1bu << 3; } else if(offset >= 0x08200000 && offset <= 0x0823Ffff) { //sector_num = 24; sector_num = 0xcu << 3; } else if(offset >= 0x08240000 && offset <= 0x0827Ffff) { //sector_num = 25; sector_num = 0xdu << 3; } else if(offset >= 0x08280000 && offset <= 0x082BFfff) { //sector_num = 26; sector_num = 0xeu << 3; } else if(offset >= 0x082C0000 && offset <= 0x082FFfff) { //sector_num = 27; sector_num = 0xfu << 3; } else { return 1; } while (FMC_STAT & (0x01u<<16)); FMC_CTL |= ((sector_num) | (0x01<<1)); FMC_CTL |= (0x01u<<16); while (FMC_STAT & (0x01u<<16)); FMC_CTL &= ~(0x1f<<3 | 0x01<<1); if(FMC_STAT & 0x1d2) return 1; return 0; }
因为在FlashInit 函数中已经完成了flash 的初始化处理,在flash 的write 和 erase 函数里添加了打印处理,我们使用本地编译的flashloader 程序,下载过程中对应的log 也按照预期的打印输出了。
只要添加以上三个函数即可完成基本的flashloader 功能,至此已经完成flashloader 下载算法的编写并可以在IAR环境下使用。