单芯片解决方案,开启全新体验——W55MH32 高性能以太网单片机
W55MH32是WIZnet重磅推出的高性能以太网单片机,它为用户带来前所未有的集成化体验。这颗芯片将强大的组件集于一身,具体来说,一颗W55MH32内置高性能Arm® Cortex-M3核心,其主频最高可达216MHz;配备1024KB FLASH与96KB SRAM,满足存储与数据处理需求;集成TOE引擎,包含WIZnet全硬件TCP/IP协议栈、内置MAC以及PHY,拥有独立的32KB以太网收发缓存,可供8个独立硬件socket使用。如此配置,真正实现了All-in-One解决方案,为开发者提供极大便利。
在封装规格上,W55MH32提供了两种选择:QFN100和QFN68。
W55MH32L采用QFN100封装版本,尺寸为12x12mm,其资源丰富,专为各种复杂工控场景设计。它拥有66个GPIO、3个ADC、12通道DMA、17个定时器、2个I2C、5个串口、2个SPI接口(其中1个带I2S接口复用)、1个CAN、1个USB2.0以及1个SDIO接口。如此丰富的外设资源,能够轻松应对工业控制中多样化的连接需求,无论是与各类传感器、执行器的通信,还是对复杂工业协议的支持,都能游刃有余,成为复杂工控领域的理想选择。同系列还有QFN68封装的W55MH32Q版本,该版本体积更小,仅为8x8mm,成本低,适合集成度高的网关模组等场景,软件使用方法一致。更多信息和资料请进入http://www.w5500.com/网站或者私信获取。
此外,本W55MH32支持硬件加密算法单元,WIZnet还推出TOE+SSL应用,涵盖TCP SSL、HTTP SSL以及 MQTT SSL等,为网络通信安全再添保障。
为助力开发者快速上手与深入开发,基于W55MH32L这颗芯片,WIZnet精心打造了配套开发板。开发板集成WIZ-Link芯片,借助一根USB C口数据线,就能轻松实现调试、下载以及串口打印日志等功能。开发板将所有外设全部引出,拓展功能也大幅提升,便于开发者全面评估芯片性能。
若您想获取芯片和开发板的更多详细信息,包括产品特性、技术参数以及价格等,欢迎访问官方网页:http://www.w5500.com/,我们期待与您共同探索W55MH32的无限可能。

第十四章 W55MH32 TFTP示例
本篇文章,我们将详细介绍如何在W55MH32芯片上面实现TFTP协议。并通过实战例程,为大家讲解如何使用TFTP客户端模式向服务器获取文本文件。
该例程用到的其他网络协议,例如DHCP请参考相关章节。有关W55MH32的初始化过程,也请参考Network Install章节,这里将不再赘述。
1 TFTP协议简介
TFTP(TrivialFileTransferProtocol)协议是一种轻量级的文件传输协议,它通常用于需要快速、简单的文件交换场景,尤其是在网络设备启动和配置过程中。与FTP(文件传输协议)不同,TFTP设计得非常简单,仅提供基本的文件读写功能,并且使用UDP作为传输层协议,因而不具备TCP的复杂性和重传机制。
2 TFTP协议特点
简单性:TFTP协议设计简单,它的报头格式简洁,操作命令种类少,这使得实现起来相对容易,对资源的需求也较低。
轻量级:TFTP协议不需要复杂的连接建立和管理过程,开销小,因此适合在一些对性能要求不高、资源有限的环境中使用。
基于UDP:TFTP使用UDP作为传输层协议,利用了UDP的快速传输和无连接特性,从而能够快速地传输数据。不过,这也意味着TFTP本身不提供可靠的传输保证,需要在应用层实现可靠性机制。
端口固定:TFTP使用固定的端口69来监听客户端的请求。数据传输使用的端口是动态分配的,每次传输会在此基础上选择一个临时端口。
数据块大小限制:每个数据报文最多只能传输512字节的数据,如果文件较大,会分多次传输,每次发送一个512字节的数据块。最后一个数据块可能小于512字节,表示文件的结束。
3 TFTP协议应用场景
接下来,我们了解下在W55MH32上,可以使用TFTP协议完成哪些操作及应用呢?
固件升级:对于路由器、交换机等网络设备,TFTP协议常用于将固件传输到这些设备以进行固件更新。TFTP协议能够确保固件文件快速、准确地传输到目标设备。
配置文件传输:TFTP协议也常用于管理网络设备的配置文件。将配置文件传输到网络设备以进行配置更新,或者从网络设备下载配置文件进行备份或分析。
IOT设备固件升级:TFTP协议因其简单性和高效性,成为IOT设备固件升级的一种常用协议。
4 TFTP协议基本工作流程
请求发送:客户端向服务器发送读请求(RRQ,Read Request)或写请求(WRQ,Write Request)。这些请求包含了要读取或写入的文件名以及传输模式(如二进制或ASCII码)。
建立连接:服务器接收到客户端的请求后,根据请求中的文件名和传输模式,打开相应的文件(对于写请求)或准备发送文件数据(对于读请求),并向客户端发送确认信息,从而建立连接。
数据传输:在写请求的情况下,客户端开始发送文件数据到服务器,服务器接收并写入文件。数据以数据块的形式发送,每个数据块的大小通常为512字节(但可以根据网络状况调整)。
在读请求的情况下,服务器开始发送文件数据到客户端,客户端接收并保存文件。同样,数据也是以数据块的形式发送的。
回应与确认:每当客户端或服务器发送一个数据块后,接收方会发送一个回应包(ACK,Acknowledgment)来确认接收到了该数据块。这个回应包包含了接收到的数据块的编号,以确保数据的顺序和完整性。
继续传输或结束:根据回应包,发送方会继续发送下一个数据块,直到整个文件传输完成。如果传输过程中出现错误,服务器会向客户端发送错误信息包(ERROR),中断传输过程。
关闭连接:文件传输完成后,客户端和服务器会关闭连接。
5 TFTP协议报文解析
常见的操作码:
1:读请求(RRQ),用于请求读取服务器上的文件。
2:写请求(WRQ),用于请求向服务器上写入文件。
3:数据(DATA),用于传输文件数据。
4:回应(ACK),用于确认接收到的数据块。
5:错误信息(ERROR),用于报告传输过程中发生的错误。
常见操作码的报文格式如下:
| 报文类型 | 报文格式 | 操作码 | 其他关键字段及说明 |
| 读请求(RRQ) | 总长可变,由2字节操作码、可变长文件名(以1字节0结尾)、可变长传输模式(以1字节 0结尾)组成 | 1 |
文件名:明确要读取的文件名称 传输模式:“netascii”表示ASCI码模式,“octet”表示二进制模式 |
| 写请求(WRQ) | 总长可变,由2字节操作码、可变长文件名(以1字节0结尾)、可变长传输模式(以1字节 0结尾)组成 | 2 |
文件名:明确要读取的文件名称 传输模式:“netascii”表示ASCII码模式,“octet”表示二进制模式 |
| 数据(DATA) | 由2字节操作码、2字节数据块编号、最多512字节数据组成 | 3 |
数据块编号:从1开始,用于标识数据块顺序 数据:实际传输的文件内容 |
| 确认(ACK) | 由2字节操作码和2字节确认的数据块编号组成 | 4 | 数据块编号:与接收到的数据块编号一致,用于确认接收 |
| 错误(ERROR) | 由2字节操作码、2字节错误码、可变长错误信息(以 1字节0结尾)组成 | 5 |
错误码:明确错误类型 错误信息:具体描述错误情况 |
报文示例:
客户端读请求报文:
|报文解析|
Trivial File Transfer Protocol
Opcode: Read Request (1) (操作码为01,读请求报文)
Source File: tftp_test_file.txt (明确要读取的文件名为tftp_test_file.txt)
Type: octet (传输模式为octet)
Option: timeout = 5
|报文原文|
00 01 74 66 74 70 5f 74 65 73 74 5f 66 69 6c 65 2e 74 78 74 00 6f 63 74 65 74 00 74 69 6d 65 6f 75 74 00 35 00
服务器响应报文:
|报文解析|
Trivial File Transfer Protocol
Opcode: Option Acknowledgement (6) (操作码为06,扩展操作码)
[Destination File: tftp_test_file.txt]
[Read Request in frame 125]
Option: timeout = 5
|报文原文|
00 06 74 69 6d 65 6f 75 74 00 35 00
客户端响应报文:
|报文解析|
Trivial File Transfer Protocol
Opcode: Acknowledgement (4) (操作码为04,回应报文)
[Destination File: tftp_test_file.txt]
[Read Request in frame 125]
Block: 0 (数据块标号为00 00)
[Full Block Number: 0]
|报文原文|
00 04 00 00
服务器响应报文:
|报文解析|
Trivial File Transfer Protocol
Opcode: Data Packet (3) (操作码为03,数据报文)
[Destination File: tftp_test_file.txt]
[Read Request in frame 125]
Block: 1 (数据块标号为00 01)
[Full Block Number: 1]
Data (36 bytes)
Data: 736461666173646661736466617364666666666666666641617364666173666166736466 (数据)
[Length: 36]
|报文原文|
00 03 00 01 73 64 61 66 61 73 64 66 61 73 64 66 61 73 64 66 66 66 66 66 66 66 66 41 61 73 64 66 61 73 66 61 66 73 64 66
客户端响应报文:
|报文解析|
Trivial File Transfer Protocol
Opcode: Acknowledgement (4) (操作码为04,回应报文)
[Destination File: tftp_test_file.txt]
[Read Request in frame 125]
Block: 1 (数据块标号为00 01)
[Full Block Number: 1]
|报文原文|
00 04 00 01
6实现过程
接下来,我们在W55MH32上实现TFTP协议读取文件。
注意:测试实例需要PC端和W55MH32处于同一网段。
在主函数中调用do_tftp_client()函数不断检查和处理 TFTP客户端的状态,并根据读取的结果(成功或失败)进入相应的处理状态。
1. do_tftp_client(SOCKET_ID, ethernet_buf);
do_tftp_client()函数如下:
void do_tftp_client(uint8_t sn, uint8_t *buff)
{
uint32_t tftp_server_ip = inet_addr(TFTP_SERVER_IP);
uint8_t tftp_read_file_name[] = TFTP_SERVER_FILE_NAME;
TFTP_init(sn, buff);
while (1)
{
if (tftp_read_flag == 0)
{
printf("tftp server ip: %s, file name: %srn", TFTP_SERVER_IP, TFTP_SERVER_FILE_NAME);
printf("send requestrn");
TFTP_read_request(tftp_server_ip, TFTP_SERVER_FILE_NAME);
tftp_read_flag = 1;
}
else
{
tftp_state = TFTP_run();
if (tftp_state == TFTP_SUCCESS)
{
printf("tftp read success, file name: %srn", tftp_read_file_name);
while (1)
{
// 成功后进入死循环
}
}
else if (tftp_state == TFTP_FAIL)
{
printf("tftp read fail, file name: %srn", tftp_read_file_name);
while (1)
{
// 失败后进入死循环
}
}
}
}
}
进入do_tftp_client()函数后开始进行TFTP客户端处理,步骤如下:
步骤一:TFTP初始化
调用TFTP_init()函数对TFTP客户端进行初始化,参数sn和buff分别是socket号,socket缓存。
void TFTP_init(uint8_t socket, uint8_t *buf)
{
init_tftp();
g_tftp_socket = open_tftp_socket(socket);
g_tftp_rcv_buf = buf;
}
static void init_tftp(void)
{
g_filename[0] = 0;
set_server_ip(0);
set_server_port(0);
set_local_port(0);
set_tftp_state(STATE_NONE);
set_block_number(0);
// timeout flag
g_resend_flag = 0;
tftp_retry_cnt = tftp_time_cnt = 0;
g_progress_state = TFTP_PROGRESS;
}
步骤二:发送 TFTP读请求
当tftp_read_flag为 0时,表示尚未发送读取请求。此时,打印 TFTP服务器的 IP地址和要读取的文件名,然后调用TFTP_read_request()函数向服务器发送读取请求。发送请求后,将tftp_read_flag设置为 1,表示已发送请求。
void TFTP_read_request(uint32_t server_ip, uint8_t *filename)
{
set_server_ip(server_ip);
#ifdef __TFTP_DEBUG__
DBG_PRINT(INFO_DBG, "[%s] Set Tftp Server : %xrn", __func__, server_ip);
#endif
g_progress_state = TFTP_PROGRESS;
send_tftp_rrq(filename, (uint8_t *)TRANS_BINARY, &default_tftp_opt, 1);
}
步骤三:运行 TFTP协议并处理结果
当 tftp_read_flag为 1时调用 TFTP_run()函数处理 TFTP协议操作,依据其返回的 tftp_state判断结果:若为 TFTP_SUCCESS则打印成功信息并进入无限循环,若为 TFTP_FAIL则打印失败信息并进入无限循环。
TFTP_run()函数如下:
int TFTP_run(void)
{
int len;
uint16_t from_port;
uint32_t from_ip;
/* Timeout Process */
if (g_resend_flag)
{
if (tftp_time_cnt >= g_timeout)
{
switch (get_tftp_state())
{
case STATE_WRQ:
break;
case STATE_RRQ:
send_tftp_rrq(g_filename, (uint8_t *)TRANS_BINARY, &default_tftp_opt, 1);
break;
case STATE_OACK:
case STATE_DATA:
send_tftp_ack(get_block_number());
break;
case STATE_ACK:
break;
default:
break;
}
tftp_time_cnt = 0;
tftp_retry_cnt++;
if (tftp_retry_cnt >= 5)
{
init_tftp();
g_progress_state = TFTP_FAIL;
}
}
}
/* Receive Packet Process */
len = recv_udp_packet(g_tftp_socket, g_tftp_rcv_buf, MAX_MTU_SIZE, &from_ip, &from_port);
if (len < 0)
{
#ifdef __TFTP_DEBUG__
DBG_PRINT(ERROR_DBG, "[%s] recv_udp_packet errorrn", __func__);
#endif
return g_progress_state;
}
recv_tftp_packet(g_tftp_rcv_buf, len, from_ip, from_port);
return g_progress_state;
}
在处理接收到的TFTP数据包时,首先调用recv_tftp_packet()函数。
recv_tftp_packet()函数如下:
static void recv_tftp_packet(uint8_t *packet, uint32_t packet_len, uint32_t from_ip, uint16_t from_port)
{
uint16_t opcode;
/* Verify Server IP */
if (from_ip != get_server_ip())
{
#ifdef __TFTP_DEBUG__
DBG_PRINT(ERROR_DBG, "[%s] Server IP faultsrn", __func__);
DBG_PRINT(ERROR_DBG, "from IP : %08x, Server IP : %08xrn", from_ip, get_server_ip());
#endif
return;
}
opcode = ntohs(*((uint16_t *)packet));
/* Set Server Port */
if ((get_tftp_state() == STATE_WRQ) || (get_tftp_state() == STATE_RRQ))
{
set_server_port(from_port);
#ifdef __TFTP_DEBUG__
DBG_PRINT(INFO_DBG, "[%s] Set Server Port : %drn", __func__, from_port);
#endif
}
switch (opcode)
{
case TFTP_RRQ: /* When Server */
recv_tftp_rrq(packet, packet_len);
break;
case TFTP_WRQ: /* When Server */
recv_tftp_wrq(packet, packet_len);
break;
case TFTP_DATA:
recv_tftp_data(packet, packet_len);
break;
case TFTP_ACK:
recv_tftp_ack(packet, packet_len);
break;
case TFTP_OACK:
recv_tftp_oack(packet, packet_len);
break;
case TFTP_ERROR:
recv_tftp_error(packet, packet_len);
break;
default:
// Unknown Message
break;
}
}
进入该函数后,第一步验证接收到的数据包的源IP地址,只有当它与服务器IP地址一致时才继续处理,若不一致则直接返回。接着,从数据包中获取操作码(opcode)。根据获取到的操作码,调用相应的处理函数:如果是TFTP读请求(RRQ),则调用 recv_tftp_rrq()函数;若是写请求(WRQ),则调用recv_tftp_wrq()函数;对于接收到的数据数据包,调用 recv_tftp_data()函数;确认数据包则由recv_tftp_ack()函数处理;OACK数据包由recv_tftp_oack()函数处理;若遇到错误数据包,调用recv_tftp_error()函数来解析错误代码和错误信息。最后,返回g_progress_state,以此表示当前TFTP操作的状态。
7运行结果
烧录例程运行后,首先进行了PHY链路检测,然后是DHCP获取网络地址结果,最后打印服务器IP和文本名称,读取文本内容,如下图所示:

8总结
本文讲解了如何在 W55MH32芯片上实现 TFTP协议,通过实战例程详细展示了使用 TFTP客户端模式从服务器获取文本文件的过程,涵盖 TFTP初始化、发送读请求、运行协议并处理结果等核心步骤。文章还对 TFTP协议的简介、特点、应用场景、基本工作流程和报文解析进行了分析,帮助读者理解其在文件传输中的实际应用价值。
下一篇文章将聚焦 SNMP协议,解析其核心原理及在网络管理中的应用,同时讲解如何在相关设备上实现 SNMP功能,敬请期待!
WIZnet是一家无晶圆厂半导体公司,成立于 1998年。产品包括互联网处理器 iMCU™,它采用 TOE(TCP/IP卸载引擎)技术,基于独特的专利全硬连线 TCP/IP。iMCU™面向各种应用中的嵌入式互联网设备。
WIZnet在全球拥有 70多家分销商,在香港、韩国、美国设有办事处,提供技术支持和产品营销。
香港办事处管理的区域包括:澳大利亚、印度、土耳其、亚洲(韩国和日本除外)。
审核编辑 黄宇
-
以太网
+关注
关注
41文章
5923浏览量
179522 -
TFTP
+关注
关注
0文章
24浏览量
14760
发布评论请先 登录
W55MH32高性能以太网单片机开发课件 第十四章 ADC(上篇)
第十四章 ADC(下篇)
第二章 W55MH32 DHCP示例
第五章 W55MH32 UDP示例
第九章 W55MH32 HTTP Server示例
第十章 W55MH32 SNTP示例
第十一章 W55MH32 SMTP示例
第十二章 W55MH32 NetBIOS示例
第十三章 W55MH32 UPnP端口转发示例
第十五章 W55MH32 SNMP示例
第十六章 W55MH32 PING示例
第十七章 W55MH32 ARP示例
第十八章 W55MH32 FTP_Server示例
第二十六章 W55MH32 上位机搜索和配置示例

第十四章 W55MH32 TFTP示例
评论