完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
前言:网络上有关TFTP远程升级MCU的资料基本上都是MCU作为TFTP服务器,PC作为客户端。从PC发送升级的bin文件给MCU进行升级。
本文将使用MCU作为TFTP的客户端,PC作为TFTP服务端,MCU联网进入升级模式后,主动向服务器请求下载文件,进而实现远程升级IAP功能。 有关MCU作为TFTP服务端的升级过程(HAL库),可以参考下面的链接 在lwip官方的源代码中,目前最新稳定版本为lwip-2.1.0,但该版本中并未包含tftp作为客户端的例子。在lwip的开发master分支中,官方提交了有关tftp作为客户端的代码,我们可以对此加以利用。下载包含有tftp客户端源码的lwip源码 使用上文提到的TFTP作为服务端的升级代码(包含按键升级的功能,该功能需要自行添加),打开HAL_LWIP_TFTP_TEST.ioc文件,进行如下设置 编译,解决重定义的错误,移除导致重定义的多余文件。 将上文提到的lwip代码中的src文件复制到工程的 Midderware->ThirdParty->LWIP 中,提示重名选择覆盖即可。 复制最新版lwip文件夹中的contribexamplestftp 中的 tftp_example.c和tftp_example.h到工程的Bsp文件夹下 在工程中新增tftp.c,tftp_example.c 注释掉main.c中关于tftp服务器初始化的代码,将 if(tftp_init(&tftpContext)==ERR_OK) { printf("TFTP初始化成功 rn"); } 修改为以下代码并注释 //初始化TFTP服务器 if(tftp_init_server(&tftpContext)==ERR_OK) { printf("TFTP初始化成功 rn"); } 在main.c中上面的代码下面增加 //初始化TFTP客户端 tftp_example_init_client(); 修改mytftpserverif.h为以下形式 修改mytftpserverif.c为 #include "mytftpserverif.h" #include #include #include "main.h" #include "flash_if.h" #include "stdlib.h" #include "string.h" /******************从tftp_example.c中复制的********************/ /* Define a base directory for TFTP access * ATTENTION: This code does NOT check for sandboxing, * i.e. '..' in paths is not checked! */ #ifndef LWIP_TFTP_EXAMPLE_BASE_DIR #define LWIP_TFTP_EXAMPLE_BASE_DIR "" #endif /* Define this to a file to get via tftp client */ #ifndef LWIP_TFTP_EXAMPLE_CLIENT_FILENAME #define LWIP_TFTP_EXAMPLE_CLIENT_FILENAME "LED.bin" #endif /* Define this to a server IP string */ #ifndef LWIP_TFTP_EXAMPLE_CLIENT_REMOTEIP #define LWIP_TFTP_EXAMPLE_CLIENT_REMOTEIP "192.168.137.1" #endif /******************从tftp_example.c中复制的********************/ __packed typedef struct { uint8_t InitFlat; uint8_t W_R_Mode; //读写模式 1写 0读 uint32_t Flash_Addr ; }Iap_FlashCont; static Iap_FlashCont Iapflashcont ; static void * OpenFile(const char* fname, const char* mode, u8_t write); static void Close_File(void* handle); /******************从tftp_example.c中复制的********************/ static void Tftp_Error(void* handle, int err, const char* msg, int size); /******************从tftp_example.c中复制的********************/ static int Read_File(void* handle, void* buf, int bytes); static int Write_File(void* handle, struct pbuf* p); const struct tftp_context tftpContext={ //TFTP SERVER/CLIENT 对接接口 OpenFile, Close_File, Read_File, Write_File, /******************新增加的********************/ Tftp_Error, // For TFTP client only /******************新增加的********************/ }; /******************从tftp_example.c中复制的,部分有修改********************/ static char full_filename[256]; static void * tftp_open_file(const char* fname, u8_t is_write) { snprintf(full_filename, sizeof(full_filename), "%s%s", LWIP_TFTP_EXAMPLE_BASE_DIR, fname); full_filename[sizeof(full_filename)-1] = 0; printf("打开文件 %s rn",fname); Iapflashcont.W_R_Mode = is_write ; Iapflashcont.W_R_Mode ? printf("写文件rn") : printf("读文件rn"); if (Iapflashcont.W_R_Mode == 1) { FLASH_If_Init(); //解锁 Iapflashcont.Flash_Addr = USER_FLASH_FIRST_PAGE_ADDRESS ; //FLASH起始地址 printf("开始擦除Flash 时间较长 rn"); if( FLASH_If_Erase(USER_FLASH_FIRST_PAGE_ADDRESS) == 0 ) //擦除用户区FLASH数据 { Iapflashcont.InitFlat =1 ; //标记初始化完成 printf("Write File Init Succes rn"); } // return (void*)fopen(full_filename, "wb"); return (Iapflashcont.InitFlat) ? (&Iapflashcont) : NULL ;//如果初始化成功 返回有效句柄 } else { return (void*)fopen(full_filename, "rb"); } } /******************从tftp_example.c中复制的,部分有修改********************/ /** * 打开文件 返回文件句柄 * @param const char* fname 文件名 * @param const char* mode * @param u8_t write 模式 1写 0读 * @returns 文件句柄 */ static void * OpenFile(const char* fname, const char* mode, u8_t write) { printf("打开文件 %s rn",fname); printf("打开模式 %s rn",mode); Iapflashcont.W_R_Mode = write ; Iapflashcont.W_R_Mode ? printf("写文件rn") : printf("读文件rn"); if(Iapflashcont.W_R_Mode == 1) { FLASH_If_Init(); //解锁 Iapflashcont.Flash_Addr = USER_FLASH_FIRST_PAGE_ADDRESS ; //FLASH起始地址 printf("开始擦除Flash 时间较长 rn"); if( FLASH_If_Erase(USER_FLASH_FIRST_PAGE_ADDRESS) == 0 ) //擦除用户区FLASH数据 { Iapflashcont.InitFlat =1 ; //标记初始化完成 printf("Write File Init Succes rn"); } } //如果为读文件模式 else if(memcmp(fname,"flash.bin",strlen("flash.bin"))==0) //可以读内部FLASH { Iapflashcont.InitFlat =1 ; //标记初始化完成 printf("Read File Init Succes rn"); Iapflashcont.Flash_Addr = FLASH_BASE ; //FLASH起始地址 } return (Iapflashcont.InitFlat) ? (&Iapflashcont) : NULL ; //如果初始化成功 返回有效句柄 } /** * 关闭文件句柄 * @param None * @param None * @param None * @returns None */ static void Close_File(void* handle) { Iap_FlashCont * Filehandle = (Iap_FlashCont *) handle ; FLASH_If_UnInit(); //FLASH上锁 Filehandle->InitFlat = 0 ; printf("关闭文件rn"); if(Filehandle->W_R_Mode) //如果之前是写文件 { typedef void (*pFunction)(void); pFunction Jump_To_Application; uint32_t JumpAddress; /* Check if valid stack address (RAM address) then jump to user application */ if (((*(__IO uint32_t*)USER_FLASH_FIRST_PAGE_ADDRESS) & 0x2FFE0000 ) == 0x20000000) { printf("正常运行中! rn"); /* 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(); /* do nothing */ while(1); } } } /** * 读取文件数据 * @param handle 文件句柄 * @param *buf 保存数据的缓存 * @param bytes 读取的数据长度 * @returns 返回读取数据长度 小于0则错误 */ static int Read_File(void* handle, void* buf, int bytes) { Iap_FlashCont * Filehandle = (Iap_FlashCont *) handle ; printf("读取文件数据 读取长度: %ld rn",bytes); if(!Filehandle->InitFlat) //未初始化 { return ERR_MEM ; } uint16_t Count ; for( Count = 0 ; (Count < bytes)&&(Filehandle->Flash_Addr<=FLASH_END) ; Count++ ,Filehandle->Flash_Addr++ ) { ((uint8_t *)buf)[Count] = *((__IO uint8_t *) Filehandle->Flash_Addr); } return Count; } /** * 写文件数据 * @param handle 文件句柄 * @param struct pbuf* p 数据缓存结构体 里面的数据缓存全为实际需要写入的数据 * @returns 小于0为错误 */ static int Write_File(void* handle, struct pbuf* p) { uint16_t Count ; Iap_FlashCont * Filehandle = (Iap_FlashCont *) handle ; printf("写文件数据 数据长度 %ld rn",p->len); if(!Filehandle->InitFlat) { printf("写文件 没有初始化 rn"); return ERR_MEM ; } Count = p->len/4 +((p->len%4)>0); //得到要写入的数据 printf("开始写FLASH 地址 :0X%08X rn",Filehandle->Flash_Addr); if( FLASH_If_Write((__IO uint32_t*)&Filehandle->Flash_Addr,(uint32_t *)p->payload,Count) == 0 ) { printf("写FLASH成功 下一次地址 :0X%08X rn",Filehandle->Flash_Addr); return ERR_OK; } else { printf("写FLASH 失败 出错地址 : 0X%08X rn",Filehandle->Flash_Addr); } return ERR_MEM; } /******************从tftp_example.c中复制的********************/ /* For TFTP client only */ static void Tftp_Error(void* handle, int err, const char* msg, int size) { char message[100]; LWIP_UNUSED_ARG(handle); memset(message, 0, sizeof(message)); MEMCPY(message, msg, LWIP_MIN(sizeof(message)-1, (size_t)size)); printf("TFTP error: %d (%s)", err, message); } /******************从tftp_example.c中复制的********************/ /******************从tftp_example.c中复制的********************/ void tftp_example_init_client(void) { void *f; err_t err; ip_addr_t srv; int ret = ipaddr_aton(LWIP_TFTP_EXAMPLE_CLIENT_REMOTEIP, &srv); LWIP_ASSERT("ipaddr_aton failed", ret == 1); err = tftp_init_client(&tftpContext); LWIP_ASSERT("tftp_init_client failed", err == ERR_OK); f = tftp_open_file(LWIP_TFTP_EXAMPLE_CLIENT_FILENAME, 1); LWIP_ASSERT("failed to create file", f != NULL); err = tftp_get(f, &srv, TFTP_PORT, LWIP_TFTP_EXAMPLE_CLIENT_FILENAME, TFTP_MODE_OCTET); LWIP_ASSERT("tftp_get failed", err == ERR_OK); } /******************从tftp_example.c中复制的********************/ 编译,提示重定义问题,我们将tftp_example.c排除在编译文件之外即可 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1683 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1582 浏览 1 评论
1013 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
703 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1627 浏览 2 评论
1892浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
675浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
538浏览 3评论
557浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
526浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-4 01:19 , Processed in 0.999065 second(s), Total 79, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号