目录
- 沁恒 CH32V208(一): CH32V208WBU6 评估板上手报告和Win10环境配置
- 沁恒 CH32V208(二): CH32V208的储存结构, 启动模式和时钟
- 沁恒 CH32V208(三): CH32V208 Ubuntu22.04 Makefile VSCode环境配置
- 沁恒 CH32V208(四): CH32V208 网络DHCP示例代码分析
- 沁恒 CH32V208(五): CH32V208 运行FreeRTOS示例的说明
硬件部分
- CH32V208WBU6 评估板
- WCH-LinkE 或 WCH-Link
硬件环境前面几节相同, 不再详细说明. 本节网络测试需要准备支持DHCP的有线网口, 五类/六类网线.
软件部分
本节以沁恒的网络示例项目为例进行说明.
示例代码位于 CH32V20xEVT 压缩包的 EVT/EXAM/ETH/DHCP 目录.
对应 GCC 环境的项目代码位于 https://github.com/IOsetting/ch32v208-template/tree/main/Examples/ETH/DHCP
编译和烧录
这里只介绍 GCC & Makefile 环境的编译和烧录. 参考上一节进行 GCC 环境的配置
- 修改 Makefile 中的
USE_NET_LIB
选项, 设置为USE_NET_LIB ?= y
, 打开这个选项, 在编译时会包含 NetLib 库 - 清空 User 目录, 将 Examples/ETH/DHCP 目录下的文件复制到 User 目录, 运行
make
编译项目 - 连接好 WCH-Link 和 CH32V208 评估板, 运行
make flash
烧录
运行示例
除了使用评估板的网口连接网线, 还需要将评估板的串口输出连接到 WCH-Link, 在PC端使用串口工具, 波特率115200打开 /dev/ttyACM0 观察输出
启动阶段会打印系统时钟, MAC地址
22:02:27.934 DHCP Test
SystemClk:120000000
net version:15
mac addr:38 3b 26 88 3f 30
22:02:28.037 WCHNET_LibInit Success
接入网线后, 会提示
22:02:29.693 PHY Link Success
等待几秒DHCP获得IP后, 显示网络信息
22:02:33.934 DHCP Success
IPAddr = 192.168.1.222
GWIPAddr = 192.168.1.1
IPAddr = 255.255.255.0
DNS1: 192.168.1.1
DNS2: 0.0.0.0
WCH22:02:33.938 NET_SocketCreat 0
此时, 通过PC端可以 ping 通这个IP地址.
代码分析
网络库 NetLib
实现部分是闭源的, 沁恒只提供了一部分外部调用的接口. 结构如下
NetLib
├── eth_driver.c
├── eth_driver.h
├── libwchnet.a
└── wchnet.h
对于用户的项目, 还需要外加一个 net_config.h 文件, 用于定义网络配置.
工作机制
流程图
流程说明
如上图所示, main 函数中的网络功能主要是两个入口, 一个是 TIM2 的初始化, 给 NetLib 提供系统 tick, 另一个是 ETH_LibInit 之后的主循环
int main(void)
{
u8 i;
Delay_Init();
USART_Printf_Init(115200); // 串口初始化
printf("DHCP Test\r\n");
printf("SystemClk:%ld\r\n",SystemCoreClock);
printf("net version:%x\n",WCHNET_GetVer());
if( WCHNET_LIB_VER != WCHNET_GetVer() ){
printf("version error.\n"); // 检查 wchnet.h 的版本(WCHNET_LIB_VER)和 libwchnet.a 中的版本是否一致
}
WCHNET_GetMacAddr(MACAddr); // 从芯片内部FLASH读取MAC地址, 芯片自带MAC地址
printf("mac addr:");
for(i = 0; i < 6; i++)
printf("%x ",MACAddr[i]);
printf("\n");
// 以上都是显示内容, 和网络功能DHCP没什么关系, 以下是必须的步骤
TIM2_Init(); // 初始化 TIM2, 用于每隔10ms调用 WCHNET_TimeIsr(WCHNETTIMERPERIOD), LocalTime增长
WCHNET_DHCPSetHostname("WCHNET"); // 设置本机 host name, 用于DHCP
i = ETH_LibInit(IPAddr, GWIPAddr, IPMask, MACAddr); // 初始化 Netlib
mStopIfError(i); // 检查初始化是否成功
if(i == WCHNET_ERR_SUCCESS)
{
printf("WCHNET_LibInit Success\r\n");
}
WCHNET_DHCPStart(WCHNET_DHCPCallBack); // 启动 DHCP
while(1)
{
WCHNET_MainTask(); // 需要重复执行的网络任务
if(WCHNET_QueryGlobalInt()) // 如果存在网络中断, 调用网络中断处理函数
{
WCHNET_HandleGlobalInt();
}
}
}
NetLib 的系统 Tick
首先是创建一个间隔10ms的定时器
void TIM2_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = {0};
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / 1000000 - 1;
TIM_TimeBaseStructure.TIM_Prescaler = WCHNETTIMERPERIOD * 1000 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2, ENABLE);
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
NVIC_SetPriority(TIM2_IRQn, 0x80);
NVIC_EnableIRQ(TIM2_IRQn);
}
在中断中调用 WCHNET_Ti