1. Introduction
Previously, we implemented the read and write operations for SPIFLASH. Now, we will continue to add functionality by porting xmodem to achieve the import and export of on-chip mem and SPI FLASH. This allows us to dump the contents of on-chip RAM and FLASH, and also to import and export the contents of SPI FLASH. This enables us to freely perform operations such as downloading and modifying images.
Code can be found at: https://github.com/qinyunti/stm32f429-boot.git
Please open in WeChat client
2. Porting XMODEM
We will continue to use the previously accumulated resources, refer to
https://mp.weixin.qq.com/s/QSYKxND3DTyQZ0JtnSqkzQ XMODEM protocol introduction and efficient, highly portable non-blocking version implementation
Specific code can be found in xmodem.c/h
3. Adding Command Line for Importing and Exporting Memory
Add function declarations in shell_func.c
static void rxmemfunc(uint8_t* param);static void sxmemfunc(uint8_t* param);
Add two command lines in g_shell_cmd_list_ast
{ (uint8_t*)"rxmem", rxmemfunc, (uint8_t*)"rxmem addr[hex] len"}, { (uint8_t*)"sxmem", sxmemfunc, (uint8_t*)"sxmem addr[hex] len"},
Implementation is as follows
static uint8_t rxtx_buf[1029]; static uint32_t getms(void){ return get_ticks();} static uint32_t io_read(uint8_t* buffer, uint32_t len){ return uart_read(1,buffer, len);} static void io_read_flush(void){ uint8_t tmp; while(0 != uart_read(1,&tmp, 1));} static uint32_t io_write(uint8_t* buffer, uint32_t len){ uart_send(1,buffer, len); return len;} static uint32_t mem_read(uint32_t addr, uint8_t* buffer, uint32_t len){ memcpy(buffer, (uint8_t*)addr, len); return len;} static uint32_t mem_write(uint32_t addr, uint8_t* buffer, uint32_t len){ memcpy((uint8_t*)addr, buffer, len); return len;} static void rxmemfunc(uint8_t* param){ uint32_t addr; uint32_t len; int res = 0;#if 0 if(2 == sscanf((const char*)param, "%*s %x %d", &addr, &len))#else char* p =(char*)param; while(1){ /* Skip %*s part */ if((*p > 'z') || (*p < 'a')){ break; }else{ p++; } } long tmp; xatoi(&p, &tmp); addr = tmp; xatoi(&p, &tmp); len = tmp;#endif { xprintf("rxmem to 0x%x %d\r\n",addr,len); xmodem_cfg_st cfg= { .buffer = rxtx_buf, .crccheck = 1, .getms = getms, .io_read = io_read, .io_read_flush = io_read_flush, .io_write = io_write, .start_timeout = 60, .packet_timeout = 1000, .ack_timeout = 1000, .mem_write = mem_write, .addr = addr, .totallen = len, }; xmodem_init_rx(&cfg); while((res = xmodem_rx()) == 0); xprintf("res:%d\r\n",res); }} static void sxmemfunc(uint8_t* param){ uint32_t addr; uint32_t len; int res = 0;#if 0 if(2 == sscanf((const char*)param, "%*s %x %d", &addr, &len))#else char* p =(char*)param; while(1){ /* Skip %*s part */ if((*p > 'z') || (*p < 'a')){ break; }else{ p++; } } long tmp; xatoi(&p, &tmp); addr = tmp; xatoi(&p, &tmp); len = tmp;#endif { xprintf("sxmem to 0x%x %d\r\n",addr,len); xmodem_cfg_st cfg= { .buffer = rxtx_buf, .plen = 1024, .getms = getms, .io_read = io_read, .io_read_flush = io_read_flush, .io_write = io_write, .start_timeout = 60, .packet_timeout = 1000, .ack_timeout = 5000, .mem_read = mem_read, .addr = addr, .totallen = len, }; xmodem_init_tx(&cfg); while((res = xmodem_tx()) == 0); xprintf("res:%d\r\n",res); }}
Please open in WeChat client
Testing
Import a file to 0x90000000 location
rxmem 0x90000000 778028

Then export
sxmem 0x90000000 778028

Compare the imported and exported files
It can be seen that they are identical, except that during export, the last packet is padded with 0x1A

4. Adding Command Line for Importing and Exporting SPI FLASH
Add function declarations in shell_func.c
static void rxspiflashfunc(uint8_t* param);static void sxspiflashfunc(uint8_t* param);
Add two command lines in g_shell_cmd_list_ast
{ (uint8_t*)"rxspiflash", rxspiflashfunc, (uint8_t*)"rxspiflash addr[hex] len"}, { (uint8_t*)"sxspiflash", sxspiflashfunc, (uint8_t*)"sxspiflash addr[hex] len"},
Implementation is as follows
static uint32_t flash_read(uint32_t addr, uint8_t* buffer, uint32_t len){ flash_itf_read(buffer, addr, len); return len;} static uint32_t flash_write(uint32_t addr, uint8_t* buffer, uint32_t len){ flash_itf_write(buffer, addr, len); return len;} static void rxspiflashfunc(uint8_t* param){ uint32_t addr; uint32_t len; int res = 0;#if 0 if(2 == sscanf((const char*)param, "%*s %lx %d", &addr, &len))#else char* p =(char*)param; while(1){ /* Skip %*s part */ if((*p > 'z') || (*p < 'a')){ break; }else{ p++; } } long tmp; xatoi(&p, &tmp); addr = tmp; xatoi(&p, &tmp); len = tmp;#endif { xmodem_cfg_st cfg= { .buffer = rxtx_buf, .crccheck = 1, .getms = getms, .io_read = io_read, .io_read_flush = io_read_flush, .io_write = io_write, .start_timeout = 60, .packet_timeout = 1000, .ack_timeout = 1000, .mem_write = flash_write, .addr = addr, .totallen = len, }; xmodem_init_rx(&cfg); while((res = xmodem_rx()) == 0); xprintf("res:%d\r\n",res); }} static void sxspiflashfunc(uint8_t* param){ uint32_t addr; uint32_t len; int res = 0; #if 0 if(2 == sscanf((const char*)param, "%*s %lx %d", &addr, &len)) #else char* p =(char*)param; while(1){ /* Skip %*s part */ if((*p > 'z') || (*p < 'a')){ break; }else{ p++; } } long tmp; xatoi(&p, &tmp); addr = tmp; xatoi(&p, &tmp); len = tmp; #endif { xmodem_cfg_st cfg= { .buffer = rxtx_buf, .plen = 1024, .getms = getms, .io_read = io_read, .io_read_flush = io_read_flush, .io_write = io_write, .start_timeout = 60, .packet_timeout = 1000, .ack_timeout = 1000, .mem_read = flash_read, .addr = addr, .totallen = len, }; xmodem_init_tx(&cfg); while((res = xmodem_tx()) == 0); xprintf("res:%d\r\n",res); }}
Testing
Import a file to spiflash 0 location
rxspiflash 0 11797

Then export
sxspiflash 0 11797

Comparing the import and export, except for the last padding difference in the xmodem packet, everything else is identical

5. Conclusion
Thanks to the resources we have accumulated, we can quickly port xmodem to achieve the import and export of on-chip mem and SPI FLASH. With this capability, we can conveniently import and export on-chip mem for debugging and easily import and export SPIFLASH for programming images and other functionalities.