stm32 以太网 LWIP TFTP IAP 远程升级

一.综述
本文是基于STM32F107的LWIP协议栈通过TFTP的文件传输协议进行IAP程序升级。本例采用的PHY层芯片是DP83848,相当于物理层,STM32F107自带的MAC层相当于数据链路层,而LWIP协议栈提供的就是网络层、传输层的功能,应用层是需要我们自己根据自己想要的功能去实现的。升级程序由bootloader和APP两部分组成。将stm32 flash划分为两个分区,bootloader和APP区,bootloader存放升级引导程序,可以根据具体的Code大小确定bootloader的扇区,APP就是用户程序即需要升级的程序代码,APP存放的地址紧接bootloader的末地址之后。如果空间允许并且安全性要求高的话,可以将flash划分为三个分区,分别为bootloader、app和backups区。增加一个备份区,存放原运行程序,对原有运行程序进行拷贝,如果升级失败则运行备份程序,至于以系统不会瘫痪。如图:
stm32 以太网 LWIP TFTP IAP 远程升级_第1张图片
二.Bootloader
作用是引导升级启动。
相关重点程序设置:

//设置APP用户程序起始地址
 #define USER_FLASH_FIRST_PAGE_ADDRESS  0x8003000
//设置擦除的flash结束扇区地址
 #define USER_FLASH_LAST_PAGE_ADDRESS   0x801FFFF 
//设置堆栈指针
__set_MSP(*(__IO uint32_t*) USER_FLASH_FIRST_PAGE_ADDRESS);
//复位中断,跳转到APP运行
 Jump_To_Application();

三.APP用户程序

1.设置向量表偏移地址
#define VECT_TAB_OFFSET  0x3000

2.设置flash程序起始地址 0x8003000

这里写图片描述
3.编译产生bin文件
这里写图片描述
四.相关代码:
下面来分析相关代码:
Main函数是相关外设初始化,主要是应用程序跳转程序:

if (((*(__IO uint32_t*)USER_FLASH_FIRST_PAGE_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
    {  
     // __disable_irq(); /* disable interrupts. */
			/* disable and clean up all interrupts. */
    {
        int i;
        for(i = 0; i < 8; i++)
        {
           /* disable interrupts. */
          NVIC->ICER[i] = 0xFFFFFFFF;
           /* clean up interrupts flags. */
          NVIC->ICPR[i] = 0xFFFFFFFF;
        }
    }
      /* Jump to user application */
      JumpAddress = *(__IO uint32_t*) (USER_FLASH_FIRST_PAGE_ADDRESS + 4); 
      Jump_To_Application = (pFunction) JumpAddress;
      /* Initialize user application's Stack Pointer */
      __set_MSP(*(__IO uint32_t*) USER_FLASH_FIRST_PAGE_ADDRESS);
      Jump_To_Application();
}

在LWIP初始化后创建TFTP服务器,TFTP是简单文件传送协议,采用的UDP协议,默认端口号为69。创建TFTP服务器,创建一个UDP PCB,且绑定69端口,最后指定该UDP PCB的数据接收回调函数。

void IAP_tftpd_init(void)
{
  err_t err;
  unsigned port = 69; 
  /* 69 is the port used for TFTP protocol initial transaction */
  /* create a new UDP PCB structure  */
  UDPpcb = udp_new();
  if (!UDPpcb)
  {
    /* Error creating PCB. Out of Memory  */
    return ;
  }
  /* Bind this PCB to port 69  */
  err = udp_bind(UDPpcb, IP_ADDR_ANY, port);
  if (err == ERR_OK)
  {
    /* Initialize receive callback function  */
    udp_recv(UDPpcb,tftp_recv_callback, NULL);
  } 
}

接下来在回调函数中根据TFTP协议进行协议解释、数据处理以及写入flash的过程,写入flash之前须解锁flash-擦除flash扇区-写入flash。如下:

int IAP_tftp_write(struct udp_pcb *upcb, struct ip_addr *to, int to_port)
{
  tftp_connection_args *args = NULL;
  /* This function is called from a callback,
  * therefore interrupts are disabled,
  * therefore we can use regular malloc   */
  args = mem_malloc(sizeof *args);
  if (!args)
  {
    IAP_tftp_cleanup_wr(upcb, args);
    return 0;
  }
  args->op = TFTP_WRQ;
  args->to_ip.addr = to->addr;
  args->to_port = to_port;
  /* the block # used as a positive response to a WRQ is _always_ 0 */
  args->block = 0;
  args->tot_bytes = 0;
  /* set callback for receives on this UDP PCB (Protocol Control Block) */
  udp_recv(upcb, IAP_wrq_recv_callback, args);
  total_count =0;
  /* init flash */
  FLASH_Unlock();
  /* erase user flash area */
  FLASH_Erase(USER_FLASH_FIRST_PAGE_ADDRESS);
  Flash_Write_Address = USER_FLASH_FIRST_PAGE_ADDRESS;    
  /* initiate the write transaction by sending the first ack */
  IAP_tftp_send_ack_packet(upcb, to, to_port, args->block);
  return 0;
}

需要注意的是bootloader需要关闭中断,不能关总中断,最好是循环分次关闭。(不关闭中断程序跑飞或者运行异常)。
最后实现如下:
stm32 以太网 LWIP TFTP IAP 远程升级_第2张图片
更多技术文章浏览请关注:

百家号:
https://author.baidu.com/home?context=%7B%22app_id%22%3A%221646108714303504%22%7D&wfr=bjh

头条号:
https://www.toutiao.com/c/user/8115738721/#mid=1646025109246987

你可能感兴趣的:(单片机/MCU/ARM)