简介
在上一篇(【IAR】 基于GD32F427的flashloader下载算法实现)我们已经实现了个可以更新flash的flashloader 算法程序,我们在此基础上继续修改代码支持IAR(C-SPY) 传递参数给到flashloader 来控制flashloader,实现IAR 和 flashloader的交互功能。
IAR IDE 可以在该路径下添加参数,我们可以在此处添加参数,C-SPY 会将参数写入RAM中,然后调用flashloader 的接口函数时把地址传递到函数,从而完成IDE 和 flashloader 的参数传递过程。
如果flashloader 支持多种下载参数配置,我们即可通过此处来设置参数,本次试验使用的开发板GD32VF427 的flash 的编程方式支持1/2/4/8字节的写入方式,我们可以通过--x8/--x16/--x32 的参数来配置编程的字节默认使用8byte的写入方式。同时为了查看运行中的内存状态添加--dumpram 参数来dump 内存信息,用于查看flash loader 运行期间的信息,在IAR 中添加参数配置如下。
在IAR 端我们已经配置好了参数,我们继续修改flashloader 程序,在初始化时加入参数的解析处理,对应修改如下。
#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; uint8_t memdump = 0; parallelism = 3; #ifdef USE_ARGC_ARGV for(int i = 0; i < argc; i++) { /* Parallelism flag*/ if(strcmp("--x8", argv[i]) == 0) { parallelism = 0; } else if (strcmp("--x16", argv[i]) == 0) { parallelism = 1; } else if (strcmp("--x32", argv[i]) == 0) { parallelism = 2; } else if(strcmp("--dumpram",argv[i]) == 0) { memdump = 1; } } #endif #ifdef DEBUG_MESS /* 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); mini_printf("\r\nuart init ok.\r\n"); mini_printf("CLK info\r\n"); mini_printf("sys rate %d\r\n",rcu_clock_freq_get(CK_SYS)); mini_printf("AHB rate %d\r\n",rcu_clock_freq_get(CK_AHB)); mini_printf("APB1 rate %d\r\n",rcu_clock_freq_get(CK_APB1)); mini_printf("APB2 rate %d\r\n",rcu_clock_freq_get(CK_APB2)); if(argc > 0) mini_printf("Argc %d\r\n",argc); for(temp = 0;temp < argc;temp++) mini_printf("Argv[%d] = %s %p\r\n",temp,argv[temp],&argv[temp]); if(memdump) { trace_byte_stream((uint8_t *)0x20000000,0x18000,0); } #endif FMC_WS = 0x00000000; temp = FMC_CTL; temp &= ~(0x3u << 8); temp |= (parallelism << 8); FMC_CTL = temp; return 0; }
添加参数的解析处理,同时在flash write 的时候根据配置的参数大小进行写入处理。
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("[FlashWrite] flash write dst %p %d %d.\r\n",dst,offset_into_block,count); FMC_CTL |= 0x01u; FMC_STAT = 0x1d2; for ( ; count; count -= 8) { switch (parallelism) { case 0: while (FMC_STAT & (0x01u<<16)); *dst++ = *src++; while (FMC_STAT & (0x01u<<16)); *dst++ = *src++; while (FMC_STAT & (0x01u<<16)); *dst++ = *src++; while (FMC_STAT & (0x01u<<16)); *dst++ = *src++; while (FMC_STAT & (0x01u<<16)); *dst++ = *src++; while (FMC_STAT & (0x01u<<16)); *dst++ = *src++; while (FMC_STAT & (0x01u<<16)); *dst++ = *src++; while (FMC_STAT & (0x01u<<16)); *dst++ = *src++; break; case 1: while (FMC_STAT & (0x01u<<16)); *((uint16_t *)dst) = *((uint16_t *)src); src += 2; dst += 2; while (FMC_STAT & (0x01u<<16)); *((uint16_t *)dst) = *((uint16_t *)src); src += 2; dst += 2; while (FMC_STAT & (0x01u<<16)); *((uint16_t *)dst) = *((uint16_t *)src); src += 2; dst += 2; while (FMC_STAT & (0x01u<<16)); *((uint16_t *)dst) = *((uint16_t *)src); src += 2; dst += 2; break; case 2: while (FMC_STAT & (0x01u<<16)); *((uint32_t *)dst) = *((uint32_t *)src); src += 4; dst += 4; while (FMC_STAT & (0x01u<<16)); *((uint32_t *)dst) = *((uint32_t *)src); src += 4; dst += 4; break; default: while (FMC_STAT & (0x01u<<16)); *((uint64_t *)dst) = *((uint64_t *)src); src += 8; dst += 8; break; } } while (FMC_STAT & (0x01u<<16)); FMC_CTL &= ~0x01; if(FMC_STAT & 0x1d2) return 1; return 0; }
使用新修改的flash loader 程序运行时可以将传入的参数进行打印,打印发现跟预期的一致 --x32 --dumpram 参数C-SPY 已经正确传递给flashloader 下载算法,并且也将内存数据dump 至串口。
Flash loader 调试信息解析
在IAR 的工程目录下创建flash0.trace 文件,C-SPY 会把flashloader 的下载过程log 写入到flash0.trace中。
创建后生成的log文件如下,从中获取flashlloader 的信息及下载过程。
661.477: File generated Wed Feb 19 18:42:32 2025 0.000: Pass 1 of 1 0.000: Starting fragment-style flashloader pass. 0.000: Device: E:\gd32_gitee\gd32f427v_start\GD32F4xx_Demo_Suites_V2.6.1\GD32427V_START_Demo_Suites\Projects\02_GPIO_Key_Polling_mode\EWARM\flashloader\FlashGD32F4xxxK.flash 0.000: Flash loader: E:\gd32_gitee\gd32f427v_start\GD32F4xx_Demo_Suites_V2.6.1\GD32427V_START_Demo_Suites\Projects\02_GPIO_Key_Polling_mode\EWARM/flashloader/FlashGd32f4xx.out 2.391: FlashInitEntry is at 0x2000'0f0c 2.391: FlashWriteEntry is at 0x2000'0f14 2.391: FlashEraseWriteEntry is at 0x2000'0f1c 2.391: FlashBreak is at 0x2000'0ef2 2.391: FlashBufferStart is at 0x2000'1000 2.391: FlashBufferEnd is at 0x2001'6f90 2.391: theFlashParams is at 0x2001'6f94 2.391: FlashPreInitEntry not found 2.391: FlashChecksumEntry not found 2.391: FlashSignoffEntry not found 2.391: page size is 4 (0x4) 2.391: filler is 0xff 2.391: buffer size is 90000 (0x1'5f90) 2.391: Base of flash at 0x800'0000 2.391: SimpleCode records (after offset): 2.391: Record 0: @ 0x800'0000 [81172 (0x1'3d14) bytes] 0x800'0000 - 0x801'3d13 [a0 7e 01 20 ... ] 2.391: Record 1: @ 0x801'3d14 [443112 (0x6'c2e8) bytes] 0x801'3d14 - 0x807'fffb [ff ff ff ff ... ] 2.391: Record 2: @ 0x807'fffc [4 (0x4) bytes] 0x807'fffc - 0x807'ffff [58 3d ae 4b ] 2.391: ->init : base @ 0x800'0000, image size 0x8'0000 2.422: Args: (argc = 2) 2.422: --x32 2.422: --dumpram 2.422: Store TargetParams to 0x2001'6f94 2.428: Setting PC to 0x2000'0f0c (FlashInitEntry) 47.216: timing(init): 0.8125 (CPU) 44.7780 (elapsed) 47.216: Load TargetParams from 0x2001'6f94 47.222: Transaction list: 47.222: Transaction 0: @ 0x800'0000 + 0x0 (0x1'0000=65536 bytes) 4 packet(s). 47.222: Will erase 4 block(s): 47.222: 0: 0x800'0000 (0x4000 bytes) 47.222: 1: 0x800'4000 (0x4000 bytes) 47.222: 2: 0x800'8000 (0x4000 bytes) 47.222: 3: 0x800'c000 (0x4000 bytes) 47.222: Transaction 1: @ 0x801'0000 + 0x0 (0x1'0000=65536 bytes) 1 packet(s). 47.222: Will erase 1 block(s): 47.222: 0: 0x801'0000 (0x1'0000 bytes) 47.222: Transaction 2: @ 0x802'0000 + 0x0 (0x1'5f90=90000 bytes) 1 packet(s). 47.222: Will erase 1 block(s): 47.222: 0: 0x802'0000 (0x2'0000 bytes) 47.222: Transaction 3: @ 0x802'0000 + 0x1'5f90 (0xa070=41072 bytes) 1 packet(s). 47.222: Transaction 4: @ 0x804'0000 + 0x0 (0x1'5f90=90000 bytes) 1 packet(s). 47.222: Will erase 1 block(s): 47.222: 0: 0x804'0000 (0x2'0000 bytes) 47.222: Transaction 5: @ 0x804'0000 + 0x1'5f90 (0xa070=41072 bytes) 1 packet(s). 47.222: Transaction 6: @ 0x806'0000 + 0x0 (0x1'5f90=90000 bytes) 1 packet(s). 47.222: Will erase 1 block(s): 47.222: 0: 0x806'0000 (0x2'0000 bytes) 47.222: Transaction 7: @ 0x806'0000 + 0x1'5f90 (0xa070=41072 bytes) 1 packet(s). 47.226: ->multi_erase: 4 blocks (0x20 bytes in buffer) [00 00 00 08 ... ] 47.233: Store TargetParams to 0x2001'6f94 47.239: Setting PC to 0x2000'0f1c (FlashEraseWriteEntry) 47.796: timing(erase): 0.0312 (CPU) 0.5470 (elapsed) 47.796: Load TargetParams from 0x2001'6f94 47.802: ->write : @ 0x800'0000 (0x1'0000 bytes, offset 0x0 into block @ 0x800'0000) [a0 7e 01 20 ... ] 47.802: Writing 0x1'0000 bytes to FlashBuffer @ 0x2000'1000 49.342: Store TargetParams to 0x2001'6f94 49.348: Setting PC to 0x2000'0f14 (FlashWriteEntry) 50.276: timing(write): 0.0625 (CPU) 0.9180 (elapsed) 50.276: Load TargetParams from 0x2001'6f94 50.282: ->multi_erase: 1 blocks (0x8 bytes in buffer) [00 00 01 08 ... ] 50.288: Store TargetParams to 0x2001'6f94 50.294: Setting PC to 0x2000'0f1c (FlashEraseWriteEntry) 50.519: timing(erase): 0.0000 (CPU) 0.2150 (elapsed) 50.519: Load TargetParams from 0x2001'6f94 50.525: ->write : @ 0x801'0000 (0x1'0000 bytes, offset 0x0 into block @ 0x801'0000) [ff f7 fe bf ... ] 50.525: Writing 0x1'0000 bytes to FlashBuffer @ 0x2000'1000 52.065: Store TargetParams to 0x2001'6f94 52.071: Setting PC to 0x2000'0f14 (FlashWriteEntry) 52.821: timing(write): 0.0000 (CPU) 0.7390 (elapsed) 52.821: Load TargetParams from 0x2001'6f94 52.827: ->multi_erase: 1 blocks (0x8 bytes in buffer) [00 00 02 08 ... ] 52.833: Store TargetParams to 0x2001'6f94 52.839: Setting PC to 0x2000'0f1c (FlashEraseWriteEntry) 53.013: timing(erase): 0.0156 (CPU) 0.1640 (elapsed) 53.013: Load TargetParams from 0x2001'6f94 53.019: ->write : @ 0x802'0000 (0x1'5f90 bytes, offset 0x0 into block @ 0x802'0000) [ff ff ff ff ... ] 53.019: Writing 0x1'5f90 bytes to FlashBuffer @ 0x2000'1000 55.136: Store TargetParams to 0x2001'6f94 55.142: Setting PC to 0x2000'0f14 (FlashWriteEntry) 56.070: timing(write): 0.0625 (CPU) 0.9180 (elapsed) 56.070: Load TargetParams from 0x2001'6f94 56.076: ->write : @ 0x803'5f90 (0xa070 bytes, offset 0x1'5f90 into block @ 0x802'0000) [ff ff ff ff ... ] 56.076: Writing 0xa070 bytes to FlashBuffer @ 0x2000'1000 57.048: Store TargetParams to 0x2001'6f94 57.055: Setting PC to 0x2000'0f14 (FlashWriteEntry) 57.537: timing(write): 0.0156 (CPU) 0.4720 (elapsed) 57.537: Load TargetParams from 0x2001'6f94 57.543: ->multi_erase: 1 blocks (0x8 bytes in buffer) [00 00 04 08 ... ] 57.549: Store TargetParams to 0x2001'6f94 57.555: Setting PC to 0x2000'0f1c (FlashEraseWriteEntry) 57.728: timing(erase): 0.0000 (CPU) 0.1630 (elapsed) 57.728: Load TargetParams from 0x2001'6f94 57.734: ->write : @ 0x804'0000 (0x1'5f90 bytes, offset 0x0 into block @ 0x804'0000) [ff ff ff ff ... ] 57.734: Writing 0x1'5f90 bytes to FlashBuffer @ 0x2000'1000 59.853: Store TargetParams to 0x2001'6f94 59.859: Setting PC to 0x2000'0f14 (FlashWriteEntry) 60.788: timing(write): 0.0625 (CPU) 0.9190 (elapsed) 60.788: Load TargetParams from 0x2001'6f94 60.794: ->write : @ 0x805'5f90 (0xa070 bytes, offset 0x1'5f90 into block @ 0x804'0000) [ff ff ff ff ... ] 60.794: Writing 0xa070 bytes to FlashBuffer @ 0x2000'1000 61.762: Store TargetParams to 0x2001'6f94 61.768: Setting PC to 0x2000'0f14 (FlashWriteEntry) 62.250: timing(write): 0.0312 (CPU) 0.4720 (elapsed) 62.250: Load TargetParams from 0x2001'6f94 62.256: ->multi_erase: 1 blocks (0x8 bytes in buffer) [00 00 06 08 ... ] 62.262: Store TargetParams to 0x2001'6f94 62.268: Setting PC to 0x2000'0f1c (FlashEraseWriteEntry) 62.525: timing(erase): 0.0156 (CPU) 0.2470 (elapsed) 62.525: Load TargetParams from 0x2001'6f94 62.531: ->write : @ 0x806'0000 (0x1'5f90 bytes, offset 0x0 into block @ 0x806'0000) [ff ff ff ff ... ] 62.531: Writing 0x1'5f90 bytes to FlashBuffer @ 0x2000'1000 64.645: Store TargetParams to 0x2001'6f94 64.651: Setting PC to 0x2000'0f14 (FlashWriteEntry) 65.580: timing(write): 0.0312 (CPU) 0.9190 (elapsed) 65.580: Load TargetParams from 0x2001'6f94 65.586: ->write : @ 0x807'5f90 (0xa070 bytes, offset 0x1'5f90 into block @ 0x806'0000) [ff ff ff ff ... ] 65.586: Writing 0xa070 bytes to FlashBuffer @ 0x2000'1000 66.554: Store TargetParams to 0x2001'6f94 66.560: Setting PC to 0x2000'0f14 (FlashWriteEntry) 67.041: timing(write): 0.0312 (CPU) 0.4710 (elapsed) 67.041: Load TargetParams from 0x2001'6f94 67.095: Duration: 1.83 (CPU) 67.10 (elapsed) 67.095: of which on target: 1.1719 (CPU) 51.9420 (elapsed) 67.095: Flash loading pass finished
从这段log 也可以看出在调用flashinit 前C-SPY 将参数先写入到0x20016f94 这个地址,然后设置PC指针到flashinit 函数处执行初始化处理,前面我们已经dump 了内存的数据,我们去查看对应的内存地址发现该地址的数据和传递的参数信息,从地址上看并不是完全匹配值。
查看IAR 的手册发现0x20016f94 存放的是参事结构体,加上这个结构的大小后地址就是吻合的0x20016f94 + 0x14(sizeof(FlashParamsHolder)) = 0x20016fa8 就合上述内存的数据匹配上了。
此处的用法相当于边长的结构体,将固定长度的固定在前面,后面跟上argc argv的字符串来获取参数信息,这些不需要我么来解析,传递到flashinit 函数的时候我们只需要根据参数来处理即可,不需要做额外的特殊处理。