Mastering Linux on MCU Series Part 16: New Boot Design for Loading Linux (3) – Implementing XMODEM for Importing and Exporting Memory and SPI FLASH

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

Mastering Linux on MCU Series Part 16: New Boot Design for Loading Linux (3) - Implementing XMODEM for Importing and Exporting Memory and SPI FLASH

Then export

sxmem 0x90000000 778028

Mastering Linux on MCU Series Part 16: New Boot Design for Loading Linux (3) - Implementing XMODEM for Importing and Exporting Memory and SPI FLASH

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

Mastering Linux on MCU Series Part 16: New Boot Design for Loading Linux (3) - Implementing XMODEM for Importing and Exporting Memory and SPI FLASH

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

Mastering Linux on MCU Series Part 16: New Boot Design for Loading Linux (3) - Implementing XMODEM for Importing and Exporting Memory and SPI FLASH

Then export

sxspiflash 0 11797

Mastering Linux on MCU Series Part 16: New Boot Design for Loading Linux (3) - Implementing XMODEM for Importing and Exporting Memory and SPI FLASH

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

Mastering Linux on MCU Series Part 16: New Boot Design for Loading Linux (3) - Implementing XMODEM for Importing and Exporting Memory and SPI FLASH

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.

Leave a Comment