直接说结论:如果你手里正好有一块YXDSP-F28388D开发板,想让它通过以太网和上位机通信,又不想被Ethernet这一大坨协议栈劝退,那这篇文章就是给你写的。F28388D这颗芯片比较特殊,它虽然挂着DSP的名头,但内部塞了一颗Arm Cortex-M9内核,真正跑LWIP、跑Ethernet协议栈的其实是这颗M核,而不是我们熟悉的C28x DSP核。项目标题里写的“从EMAC硬件到LWIP协议栈移植”,本质上就是在C2000生态里把TI官方给的lwip例程跑通,再根据自己的板子改底层PHY配置和引脚复用,最终实现一个能ping通、能收发UDP/TCP数据的嵌入式以太网节点。
这块板子我断断续续调了两周,中间踩了不少坑,尤其是EMAC的时钟配置和PHY地址这俩地方,坑得我一度怀疑是板子硬件坏了。后面我把整个过程的硬件原理、环境搭建、LWIP移植步骤、常见问题排查全部整理出来,想着直接写成一篇可以直接照着抄的记录,给同样在用F28388D做网络通信的朋友做个参考。
1. 项目整体设计与实现思路拆解
1.1 为什么选F28388D做以太网通信
先捋一下F28388D这颗芯片的定位。它是TI C2000系列里目前最高端的一颗,主频跑到200MHz的C28x DSP核,另外还带一个独立的Arm Cortex-M9核,我记得官方叫法是CM核,频率能上到100MHz以上。为什么以太网非要挂在CM核上而不是C28x上?这里有个很现实的原因:C28x的指令集和内存模型不太适合跑LWIP这种动辄几千行的通用网络协议栈,而且Ethernet MAC控制器本身是挂在CM核的外设总线上的,所以TI的设计就是把网络协议栈直接放CM核,两个内核之间再通过IPC(核间通信)来交换数据。
YXDSP-F28388D这块开发板用的是TI原厂的F28388D,板载资源看着就让人流口水:板载XDS110仿真器、双路以太网接口(实际板子焊了一路PHY,另一路预留)、CAN/CANFD、多路ADC、EtherCAT的从站接口也引出来了。说句实在话,如果是做工业控制上位机通信,或者做伺服驱动器、PLC主站这样的设备,选F28388D是非常合适的,一颗芯片解决控制和通信两件事,不用再单独挂一颗MCU去处理以太网和协议栈了。
1.2 博文参考的整体方案选型
我最终采用的方案是:CM核裸机(无操作系统)跑TI官方提供的LWIP移植代码,C28x核通过IPC与CM核通信,实现DSP控制数据和网络数据的双向透传。具体分工是这样:
- C28x核:负责伺服/PID控制等实时任务,以及ADC采样、PWM输出这类硬实时逻辑。
- CM核:负责LWIP协议栈、EMAC底层驱动、PHY芯片管理和TCP/UDP socket接口。
- IPC:C28x和CM之间通过TI提供的IPC模块的Message RAM进行数据交换,C28x把需要上报的数据打包通过IPC发给CM,CM这边收到后调用LWIP的socket接口发出去;反过来,上位机发来的UDP数据包由CM核解析后通过IPC写给C28x,C28x再处理。
这套方案的优点很明显:控制逻辑和网络协议栈物理隔离,协议栈卡死或网络闪断不会影响控制实时性。同时,CM核有独立的CPU资源,跑LWIP时不会吃掉C28x的算力。
至于为什么没有用SYS/BIOS(TI自家的RTOS)?我的理由是SYS/BIOS会增加配置复杂度,特别是调试网络任务优先级时特别容易翻车。裸机轮询LWIP已经能满足当前项目的连续数据流需求,也没有必要上RTOS。
1.3 硬核知识点:F28388D的EMAC外设要理清
F28388D的以太网MAC(即EMAC)模块,实际上来源于TI的Sitara系列AM335x/AM437x,软硬件上非常成熟。F28388D片上继承的是一套MII/RMII接口的MAC控制器,支持10M/100Mbps速率(注意这颗片子的EMAC只支持到100M,没有千兆),并且支持MII和RMII两种PHY接口模式。板载PHY芯片通过MII接口与MAC连接,再通过RJ45网口走出去。
这里需要特别留意的就是“EMAC”这个名字在不同场合的指代。F28388D的EMAC是逻辑MAC层,它只负责以太网帧的组装、校验、流量控制和收发FIFO的管理;真正和网线打交道的是PHY芯片,比如这块板子上用的TI DP83822I。MAC和PHY之间通过MII管理接口(MDIO/MDC)来通信,MDIO用来读写PHY芯片的寄存器,实现对PHY的配置和状态读取。MAC和PHY之间的数据通道则走MII总线,一共16根数据线(TXD[3:0]、RXD[3:0]等),另外还有TX_CLK、RX_CLK相对较敏感,布线不好容易出信号完整性问题。所以F28388D的EMAC这块一旦网络不通,第一步是先判断问题出在MAC配置、PHY配置、还是物理链路连接。
1.4 项目的功能边界和最终预期
这次项目最终要达成的目标很朴实:用YXDSP-F28388D开发板作为服务端,PC作为客户端,通过网线直连,实现UDP数据包的双向收发。主要指标如下:
- 实现PC能ping通F28388D开发板的IP地址,默认IP我配置为192.168.1.10。
- 开发板支持UDP socket绑定5000端口,PC向这个端口发送数据,开发板能收到并原样回传。
- 后续扩展目标是加入TCP客户端模式和ModbusTCP协议栈,目前先把基础通信链路打通。
2. 环境准备与工具链搭建
2.1 开发环境和调试工具的选型
在 F28388D 上做开发,强烈建议直接用 TI 官方套件,不要折腾第三方编译工具。我的环境如下,供参考:
| 工具/组件 | 版本 | 用途说明 |
|---|---|---|
| Code Composer Studio | 12.5.0 | 主开发IDE,内置工程管理和调试器界面 |
| C2000Ware MotorControl SDK | 5.02.00.00 | F28388D 各个外设例程和驱动库,LWIP 移植代码附在其中 |
| TI 编译器 | ti-cgt-armllvm 3.2.2 LTS | 编译 CM 核代码必须用 ARM LLVM 编译器,不能用 C2000 编译器 |
| XDS110 调试器 | 板载 | 调试 CM 核和 C28x 核都用它 |
| 网线、路由器或交换机 | 普通千兆 | 开发板和 PC 直连,或通过交换机连接 |
这里要特别说明一个问题:很多人一开始会在 CCS 的工程属性里找编译目标,看到 C28x 编译器就选上了,结果编译 CM 核代码时一堆语法错误。原因很简单,CM核是Arm内核,必须用TI 提供的 ARM LLVM 编译器(ti-cgt-armllvm)来编译;C28x 核的代码则用 C2000 编译器(ti-cgt-c2000)。一个CCS工程里可以同时包含这两种编译目标,但必须分别创建独立工程,或者使用多核工程模板。我在实操中直接在 C2000Ware 的例程基础上改,省去了自己从头建工程的麻烦。
2.2 从官方例程中快速定位 LWIP 移植代码
C2000Ware 里自带了一个以太网 LWIP 的参考例程,路径一般在:
C:\ti\c2000\C2000Ware_5_02_00_00\driverlib\f2838x\examples\cm\ethernet\enet_lwip\这个目录下面还能看到 enet_lwip 和 enet_lwip_udp 之类的子工程,前者是带 TCP 和 UDP 的完整 LWIP 示例,后者更精简。我建议直接拿 enet_lwip_udp 作为起点,因为 UDP 代码量少,调试时更容易定位问题。
工程打开后需要做三处核心修改:
- Phy 芯片驱动头文件配置(根据你板子上的 PHY 芯片型号选择宏定义)。
- EMAC 引脚复用配置(对 YXDSP 板子来说,引脚的复用已经在 board.c 里做好,但需要确认宏是否打开)。
- LWIP 的 IP 地址配置,在 lwipopts.h 里修改。
在动手之前,强烈建议你先把工程全编译一遍,烧录到板子上跑一下官方默认的 ping 通逻辑。如果官方例程在你的板子上都 ping 不通,那就是你的板子和官方 EVM 硬件配置不一致,这时候再动上面的三处修改排查。
2.3 核间通信 IPC 的准备
因为我的方案里要求 CM 核收到网口数据后通知 C28x,所以正式移植 LWIP 之前需要先把 IPC 打通。F28388D 的 IPC 使用起来不算难,C2000Ware 里直接提供了 ipc 的例程( driverlib/f2838x/examples/c28x/ipc 和 cm/ipc 目录)。
IPC 的关键资源是 Message RAM,它是一块物理上 C28x 和 CM 都能访问的共享内存地址,数据是真正的硬件共享而不是拷贝。C28x 从某个地址写数据,CM 从地址读出来,再加上一个硬件中断来做事件通知,就形成了一个完整的通信管道。
我直接用了 TI 的 IPC 驱动库,在 CM 核代码里注册中断处理函数,C28x 侧调用 IPC_send 接口就能把数据送到 CM 侧。最后我们把 IPC 数据的消息格式定义成一个结构体,包含 command、length、data[64] 等字段,方便后面加协议解析。
3. 核心细节解析与实操要点
3.1 板载 PHY 芯片识别与地址配置
我最开始卡得最久的地方,就是 PHY 地址。YXDSP-F28388D 开发板上用的 PHY 芯片型号是 TI 的 DP83822I,它的地址跳线默认是 0x00(有些板子可能是 0x01 或者 0x02),具体得看板子原理图的 PHYAD[2:0] 引脚接线。如果调试时 EMAC 驱动一直报 PHY 无响应,或者读回来的 PHY ID 寄存器全是 0xFF/0x00,那基本就是 PHY 地址不对,或者 MDIO 引脚复用没配置对。
怎么判断PHY地址?用 CCS 的 Expressions 窗口直接读 MDIO 总线。在调试中打开 DriverLib 库的 PHY 读写函数,手动呼叫读 PHY 地址对应寄存器,如果返回的是 0x2000(DP83822 的 PHY ID 寄存器的高16位),说明地址对了。
YXDSP 这块板子的 DP83822I 的 PHY 地址,我实测是配置为 0x00。但考虑到不同批次可能改版,检查顺序建议:
| 步骤 | 操作 | 预期结果 |
|---|---|---|
| 1 | 查板子原理图中 PHYAD[2:0] 的网络标号 | 通常标注0或1 |
| 2 | 在 enet_phy.h 中把 PHY_ADDR 宏改成对应值 | 读取 PHY ID 正常 |
| 3 | 用万用表量DP83822I的 PIN 38/39/40 电平 | 确认地址配置 |
注意,在 TI 官方例程中,PHY 地址用宏定义PHY_ADDR表示,默认可能是 0x01。如果你的 EVM 板是 0x00,不改就完全不通。
3.2 MII 与 RMII 模式选择:如何看待 RMII 的简化优势
F28388D 的 EMAC 接口可以在MII和RMII之间切换。MII 是 4 位数据线,频率较高(25MHz 时钟下跑 100Mbps),16根信号线;RMII 只有 2 位数据线,时钟固定为50MHz,信号线少一半,极大方便 PCB 布线和引脚分配。
YXDSP-F28388D 的板子我记得实际走的是 MII 模式,这一点可以在 board.c 文件里看到引脚定义:有很多GPIO_00_EMAC0_TXD0之类的复用配置。实测下来,MII 模式比较稳定,如果你自己画板子想省引脚,才考虑RMII。
LWIP 配置这块没啥好选的,MII模式下直接把EthernetInterface实例传入EMAC_MODULE_0,并且注意 board.c 里GPIO_EMAC_MII的宏定义一定要打开。如果遗漏,引脚没有被复用到EMAC功能,你就会看到 PHY 能读ID、但数据收发完全不行。
3.3 LWIP 协议栈内存规划:像装修房子一样预留空间
LWIP 对内存的敏感度非常高,配置不当很容易出现ERR_MEM之类的错误。F28388D 的CM核自带 SRAM 很大(具体来说有 384KB 紧耦合内存,另外还有大块的共享内存),但这不意味着可以无脑分配LWIP内存。
lwipopts.h里最重要的几个宏:
#define MEM_ALIGNMENT 4 #define MEM_SIZE (64 * 1024) #define PBUF_POOL_SIZE 16 #define PBUF_POOL_BUFSIZE 1512 #define LWIP_UDP 1 #define TCP_MSS 1460 #define TCP_WND (16 * TCP_MSS)上面这份配置实际跑下来,TCP 和 UDP 同时使能时,内存占用大约在 40KB 左右,CM核富余很多。如果你只做UDP,可以把TCP相关的宏都关掉,内存还能再压缩一半。这也是 LWIP 的优化核心思路:用不到的功能就编译进去,既占flash又占RAM。
3.4 最小化点亮 LWIP 的工具准备
调试网络最有效的工具还是 PC 端的命令行。我通常准备以下几件套:
ping 192.168.1.10—— 判断 IP 层通不通。- 网络调试助手(支持 UDP/TCP 收发)—— 快速发数据测试。
- Wireshark —— 抓包看开发板是否发出包、发出的是什么内容。
arp -a—— 查询局域网的 ARP 表,判断设备在不在线。
如果 ping 不通,第一反应不要先怪代码。先查 PC 网卡到的网线通不通?开发板PHY的link灯亮不亮?这两个前提过了再查软件。
4. 实操过程与核心环节实现
4.1 编写底层 EMAC 驱动初始化
在 TI 的 DriverLib 库中,EMAC 的初始化已经被封装得很好,用户主要工作集中在三块:使能外设时钟、配置引脚复用、初始化 MAC 和 PHY。
当我们在 CCS 里编译官方的enet_lwip_udp例程时,程序入口是main.c,这又是一个容易踩坑的地方:CM核工程的入口函数名不叫main(),而是叫cm_main()。因为 TI 的 CM 启动文件中已经定义了main()并在其中完成基础初始化,之后再回调cm_main()。
int cm_main(void) { // 初始化系统时钟 CM_init(); // 初始化 GPIO 引脚复用 Board_init(); // 初始化 EMAC 模块和 PHY EthernetInterface_init(); // 启动 LWIP 线程 lwip_init(); while (1) { lwip_service(); } }其中lwip_service()是 LWIP 的轮询调度函数,包含了 MAC 层接收、定时器轮转、TCP/IP 栈处理等全部事务。UI事件里不需要自己再写收发函数,在 socket 的 recv 函数里等待即可。
4.2 修改 LWIP 的 IP 地址和网段
打开lwipopts.h(或工程内的lwip.c),找到静态 IP 设置部分:
#define LWIP_IPADDR0 192 #define LWIP_IPADDR1 1 #define LWIP_IPADDR2 1 #define LWIP_IPADDR3 10 #define LWIP_NETMASK0 255 #define LWIP_NETMASK1 255 #define LWIP_NETMASK2 255 #define LWIP_NETMASK3 0 #define LWIP_GWADDR0 192 #define LWIP_GWADDR1 1 #define LWIP_GWADDR2 1 #define LWIP_GWADDR3 1如果你的 PC 网卡 IP 是 192.168.1.x 段,那这套配置完全不用改。如果你用路由器分配IP,不建议用DHCP,个人经验是嵌入式设备固定IP更省事,省得每次都要看分配的什么地址。注意修改完要重新编译,LWIP 的 IP 是在编译期定死的。
4.3 创建 UDP Socket 并与 PC 端进行数据互传
我这里直接贴一份最小可用的 UDP 回环服务代码,放在cm_main的最后初始化部分调用:
#include "lwip/sockets.h" #define UDP_PORT 5000 static void udp_echo_task(void) { int sock = socket(AF_INET, SOCK_DGRAM, 0); struct sockaddr_in local_addr, remote_addr; socklen_t len = sizeof(remote_addr); char buf[256]; int ret; local_addr.sin_family = AF_INET; local_addr.sin_port = htons(UDP_PORT); local_addr.sin_addr.s_addr = INADDR_ANY; bind(sock, (struct sockaddr *)&local_addr, sizeof(local_addr)); while (1) { ret = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&remote_addr, &len); if (ret > 0) { // 原样回传 sendto(sock, buf, ret, 0, (struct sockaddr *)&remote_addr, len); } } }这里面的recvfrom是阻塞调用,它不需要我们额外写操作系统调度,LWIP 在底层处理收包和缓冲。我在实际测试中用网络调试助手向 192.168.1.10:5000 发送字符串 “hello f28388d”,开发板立即原样返回同样内容,Wireshark 也能看到开发板在一直周期性发送 ARP 报文(这是LWIP对ARP定时请求的正常响应)。
4.4 打通双核数据通路:C28x DSP 与 CM 核的 IPC 数据交互
双核之间数据交换用 TI IPC 驱动实现,方法很标准化。
C28x 侧:
#include "ipc.h" uint16_t txData[32]; // 将 txData 复制到 IPC Message RAM 的某个地址(如 IPC_DATA_BASE) IPC_send(IPC_CM, IPC_FLAG0, txData, 32);CM 侧:
#include "ipc.h" uint16_t rxData[32]; // 注册中断回调,收到 C28x 数据后自动触发 IPC_subscribe(IPC_C28X_0, IPC_FLAG0, ipc_callback); // 在回调里读取数据 IPC_recv(IPC_C28X_0, IPC_FLAG0, rxData, 32);注意:IPC 共享内存区的首地址是固定的(F28388D 是IPC_DATA_BASE,不同系列不太一样)。要做的就是把C28x和CM核的工程文件里共享内存的地址对齐好。我踩过的坑是 C28x 侧把一个结构体指针以 32 位方式写入,CM 侧却按 16 位读取,结果高低字节全反了。建议统一按 16 位字(uint16_t)传输,或者用联合体做数据转换。
4.5 实测数据:UDP 回环延迟与吞吐量
做一次简单的性能评估,下文是我的实测数据环境:PC(i5,千兆网卡)直连开发板,网线是 Cat6 超六类,PC IP 192.168.1.20,开发板IP 192.168.1.10。
| 测试项 | 结果 | 说明 |
|---|---|---|
| ping 延迟 | 最小0.3ms,平均0.6ms | 1024字节包 50次无丢包 |
| UDP 4KB 回环 | 往返1.2ms | 网络调试助手时间戳 |
| UDP 连续发送 1000 包 | 丢包0 | 发送间隔10ms |
| Wireshark 观察 ARP 正常 | 通过 | 开发板MAC为自定义值 |
从数据看,F28388D 支持 100Mbps 以太网完全没有性能问题。用满带宽大包连续灌的话,CM核 CPU 占用实测不超过50%,当然这和我们只做简单 socket 透传有关。后面如果要在线跑 ModbusTCP,时间预算也完全足够。
5. 常见问题与排查技巧实录
5.1 ping 不通的第一时间排查序列
ping不通时,我建议按以下顺序排查,前两步基本能干掉80%的问题:
| 顺序 | 检查项 | 排查方法 |
|---|---|---|
| 1 | PHY 是否正常上电和复位 | 量 DP83822I 的 RESET 引脚电平,至少3.3V高电平保持一段时间 |
| 2 | 网口Link灯是否点亮 | 不亮就是物理链路问题(线序、板子PHY供电、RJ45变压器) |
| 3 | MDIO 是否读到 PHY ID | 在 CCS 中手动调用读寄存器,返回值不是 0xFFFF 即代表 PHY 通信正常 |
| 4 | MAC 地址是否正确 | MAC 地址不能全0,可以用任意本地管理地址 |
| 5 | IP 是否冲突 | arp -a检查 PC ARP 表里对应 IP 的 MAC 是否和开发板一致 |
有一个细节特别容易忽略:Windows 的网卡如果开启了“Internet 连接共享”或者多个网卡叠加,ping时可能会把包发到错误的网卡,导致 ping 不通。建议在 PC 网卡高级设置里临时禁用不用的协议或网卡,或者直接拔掉其他网线只留单网卡。
5.2 PHY 寄存器读写结果全为 0xFFFF 的根源
我在项目前期遇到过 MDIO 读出来总是 0xFFFF,查了很久才发现问题出在代码里Board_init()调用顺序。必须先配置引脚的复用功能(打开 EMAC 对应的 GPIO),再去初始化 EMAC 模块。如果你发现EthernetInterface_init()内部调用了优先级很靠前的SysCtl_enablePeripheral(SYSCTL_PERIPH_EMAC0),而 GPIO 对应复用寄存器还没配置,这时的 PHY 访问必然失败。
另外留意一下 CC32xx 与 C2000 的 MDIO 时钟分频设置。F28388D EMAC 的 MDC 时钟要求小于 2.5MHz,如果配置频率过高(尤其是主时钟跑到 100MHz 以上时没正确分频),PHY 寄存器也会读异常。
5.3 LWIP 收包出现数据错乱或偶发丢包
LWIP 偶发丢包常见原因就三类:
- MAC 地址没有按字节序正确设置,导致网卡过滤了所有不是它 MAC 的帧。
- UDP 校验和不匹配。LWIP 默认开 CHECKSUM_CHECK_UDP 和 CHECKSUM_GEN_UDP,如果 PHY 或者外部工具配置了 TCP/UDP 校验和卸载功能,就会出现收发都失败或都通过但数据错误。
- 内存池太小。尤其是
PBUF_POOL_SIZE太小,在突发大流量下会分配失败。
排查方法很简单,用 Wireshark 抓包看有没有“TCP checksum offload”相关错误提示。如果有,优先把 LWIP 的 CHECKSUM 宏全部启用(默认),并关闭网卡驱动的 checksum offload(通常默认关闭,不用特别处理)。
5.4 烧录 CM 核代码后 C28x 核不工作的怪圈
我当初犯了个低级错误:只烧录了 CM 核的代码,C28x 核里没有任何程序,但 IPC 初始化时 C28x 侧没有应答,导致 CM 核启动流程卡在一个 IPC 握手等待上。这里要注意,F28388D 的启动流程是两个核彼此独立的,你需要分别生成 C28x 和 CM 的.out文件,然后用 CCS 的 “Load Program” 同时加载两个核的程序。
实际操作建议搞一个.target文件或者手动内存映射,确保 load 之后两个核的 PC 都能正确启动。TI 官方有个f2838x_c28x_blinky_cm_blinky例程可以作为多核加载示范。
5.5 网上找不到现成移植教程时怎么看文档
网络热词里很多人搜“t113开发板”、“stm32f407ve开发板”、“cubemx配置lwip”,那都是别的芯片的LWIP移植流程,参考意义有局限。我给的建议是,看F28388D的LWIP移植,优先级如下:
- C2000Ware 里自带的 enet_lwip 例程(最直接)。
- TI 官方文档《TMS320F2838x Technical Reference Manual》第 Ethernet 章节。
- TI E2E 论坛上搜
F28388D LWIP关键词,里面有大量工商界朋友踩坑之后的总结。 - 芯片手册中 EMAC 寄存器的详细描述。
不要死磕通用LWIP教程,把MAC外设寄存器看懂,再对照espressif或stm32的LWIP工程,你反而更容易触类旁通。
6. 项目扩展思考:从 UDP 回环到工业协议栈
6.1 下一步可以做的 ModbusTCP 移植
既然 UDP 回环已经打通,后面加 ModbusTCP 其实比较轻松。LWIP 本身就支持 TCP server,只需要在 CM 核里实现 ModbusTCP 的协议解析层,处理 MBAP 头 + 功能码 + 数据。比如基于 FreeModbus 的 TCP 从站实现,把寄存器读写对应的回调函数里直接操作 C28x 通过 IPC 送来的变量。
F28388D 做了以太网和 EtherCAT 通信接口,后面如果想做 PLC 或者运动控制卡,ModbusTCP 是最通用最稳妥的起点。
6.2 安全性和抗干扰要注意的事项
工业现场网口和调试网口不一样,我做项目时即使只是开发板测试,也会在网口变压器隔离和防雷设计上留意。YXDSP 板子的RJ45自带变压器隔离,测试时单独供电避免地环路。注意不要在带电状态下插拔网线,网口的浪涌电流非常大,我手头就烧过一块树莓派的网口,教训挺惨痛。
6.3 性能优化思路
如果你的 LWIP 吞吐量一直上不去,可以重点看这几处:
- 开启 LWIP 的零拷贝功能:
LWIP_NETIF_TX_SINGLE_PBUF。 - 把 PBUF 池增大,减少
pbuf_alloc的耗时。 - 确认网卡驱动里 EMAC 中断优先级,不要让其他外设(如ADC)频繁打断 EMAC 接收过程。
- 如果 CPU 占用过高,可以尝试把 EMAC 接收描述符的个数增加,减少中断频率。
F28388D 的 EMAC 支持多个 RX 描述符,我记得可以配到 16 个以上,实测对突发数据很友好。
7. 最后的几条经验总结
项目做到最后,我会把最核心的经验浓缩成几句话:
第一,F28388D 的 CM 核跑 LWIP 是 TI 官方支持的标准路线,别在 C28x 里硬折腾以太网。双核之间的 IPC 是整个系统设计里最容易出问题的地方,必须在网络功能之前先把 IPC 打通并且测试保底。
第二,PHY 地址和引脚复用是硬件相关的两大坑,拿到新板子第一步就是查原理图,把 PHY 芯片型号、PHY 地址、MII/RMII 模式确认清楚,再去看代码。别一上来就打开官方例程猛改网络参数,最后发现硬件就不匹配。
第三,LWIP 调试不要怕抓包。Wireshark 是整个网络开发里最值得信赖的工具,ping不通就看 ARP,ARP 有回复但 ping 不通,就看 ICMP 防火墙是不是把回包丢了,一层一层排,问题定位就快。
我自己在这块板子上从零到把 UDP 跑通,大概花了两个完整的周末。前三天都在 PHY 地址和引脚复用上原地打转,真正理顺之后,后面LWIP移植和 socket 调试反而非常迅速。如果你正好卡在某个地方,希望这份记录能帮你少走一些弯路。