本篇目标:在之前的硬件基础上,修改ST官方移植lwip的工程,使PC机能ping通stm32
材料准备:
跟着文件路径打开其中一个工程,先选择不带操作系统的练习测试
文件路径:STM32F4x7_ETH_LwIP_V1.1.1 -> Project -> Standalone -> tcp_echo_server -> MDK-ARM -> Project.uvproj
先编译一下,出现3个Warning,其中两个是变量定义未使用,不影响暂且不管,还有一个是ethernetif.c文件最后没有空白行,手动添加一行,再次编译~
消除所有错误警告~成功开始的第一步~
从main函数开始理解并修改(英文为官方注释,中文为修改注释):
int main(void)
{
/*!< At this stage the microcontroller clock setting is already configured to
168 MHz, this is done through SystemInit() function which is called from
startup file (startup_stm32f4xx.s) before to branch to application main.
To reconfigure the default setting of SystemInit() function, refer to
system_stm32f4xx.c file
*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
#ifdef SERIAL_DEBUG
DebugComPort_Init();
#endif
/*Initialize LCD and Leds */
//LCD_LED_Init(); //硬件没有LCD,也暂时不用LED,将函数注释掉
/* configure ethernet (GPIOs, clocks, MAC, DMA) */
ETH_BSP_Config(); //MAC-PHY配置函数,主要理解修改函数
/* Initilaize the LwIP stack */
LwIP_Init(); //lwip初始化函数
/* tcp echo server Init */
//tcp_echoserver_init(); //tcp服务器建立函数,暂时只建立ping工程,将函数注释掉
/* Infinite loop */
while (1)
{
/* check if any packet received */
if (ETH_CheckFrameReceived())
{
/* process received ethernet packet*/
LwIP_Pkt_Handle();
}
/* handle periodic timers for LwIP*/
LwIP_Periodic_Handle(LocalTime);
}
}
main函数中有两个修改:
其次进入主要配置函数 ETH_BSP_Config() :
接着看 ETH_GPIO_Config() 函数:
由于官方移植lwip用的是MII接口,而之前搭建的硬件接口是RMII,所以需要修改相关宏定义和 GPIO口的复用
void ETH_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOs clocks */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|
RCC_AHB1Periph_GPIOB|
RCC_AHB1Periph_GPIOC,
ENABLE); //我们只用到了A,B,C三种引脚,所以修改成只使能A,B,C三个的时钟
/* Enable SYSCFG clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //使能SYSCFG外设时钟
/* Configure MCO (PA8) */
//配置PA8(做为MCO功能)输出时钟信号
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* MII/RMII Media interface selection --------------------------------------*/
#ifdef MII_MODE
#ifdef PHY_CLOCK_MCO
RCC_MCO1Config(RCC_MCO1Source_HSE, RCC_MCO1Div_1); //在PA8引脚上输出25MHZ的时钟信号
#endif /* PHY_CLOCK_MCO */
SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_MII); //与PHY芯片通讯选择MII模式
#elif defined RMII_MODE //这里要修改宏定义,注释MII_MODE,取消注释RMII_MODE,选择RMII接口模式与PHY芯片进行通讯
RCC_MCO1Config(RCC_MCO1Source_PLLCLK,RCC_MCO1Div_2); //添加时钟函数,在PA8引脚上输出50MHZ时钟信号
SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_RMII); //与PHY芯片通讯选择RMII模式
#endif
/* Ethernet pins configuration ************************************************/
/*
ETH_MDIO -------------------------> PA2
ETH_MDC --------------------------> PC1
ETH_RMII_REF_CLK------------------> PA1
ETH_RMII_CRS_DV ------------------> PA7
ETH_RMII_RXD0 --------------------> PC4
ETH_RMII_RXD1 --------------------> PC5
ETH_RMII_TX_EN -------------------> PB11
ETH_RMII_TXD0 --------------------> PB12
ETH_RMII_TXD1 --------------------> PB13
*/
//修改下面所有对GPIO的初始化为对应RMII接口GPIO的初始化,而RMII所用到的引脚在上面的列表中,共9个引脚
/* Configure PA1, PA2 and PA7 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_ETH);
/* Configure PB11,PB12 and PB13 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_ETH);
/* Configure PC1, PC4 and PC5 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource1, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource4, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource5, GPIO_AF_ETH);
}
总结修改之前,先做一下RMII接口相关引脚的功课:
修改总结:
接下来要来看 ETH_MACDMA_Config() 函数中的最后一个函数 ETH_Init() ,这个函数包含了所有MAC控制器相关初始化的配置,所以定位到这个函数
stm32f4xf_eth.c第416行开始:
/* Reset Timeout counter */
timeout = 0;
/* Read the result of the auto-negotiation */
// RegValue = ETH_ReadPHYRegister(PHYAddress, PHY_SR);
/* Configure the MAC with the Duplex Mode fixed by the auto-negotiation process */
// if((RegValue & PHY_DUPLEX_STATUS) != (uint32_t)RESET)
// {
/* Set Ethernet duplex mode to Full-duplex following the auto-negotiation */
//注释掉其他所有内容,只留下下面两个函数:配置为全双工
ETH_InitStruct->ETH_Mode = ETH_Mode_FullDuplex;
// }
// else
// {
/* Set Ethernet duplex mode to Half-duplex following the auto-negotiation */
// ETH_InitStruct->ETH_Mode = ETH_Mode_HalfDuplex;
// }
/* Configure the MAC with the speed fixed by the auto-negotiation process */
// if(RegValue & PHY_SPEED_STATUS)
// {
/* Set Ethernet speed to 10M following the auto-negotiation */
// ETH_InitStruct->ETH_Speed = ETH_Speed_10M;
// }
// else
// {
/* Set Ethernet speed to 100M following the auto-negotiation */
//注释掉其他所有内容,只留下下面两个函数:配置为100M以太网
ETH_InitStruct->ETH_Speed = ETH_Speed_100M;
// }
修改内容:
至此为止,代码修改结束,编译下载到板子上
如果想要修改ip地址,可以找到main.h里面的宏定义:
/*Static IP ADDRESS: IP_ADDR0.IP_ADDR1.IP_ADDR2.IP_ADDR3 */
#define IP_ADDR0 192
#define IP_ADDR1 168
#define IP_ADDR2 0
#define IP_ADDR3 10
修改成自己想要的IP地址便可以了,接下来用pc机来ping一下
ping之前,要确定两件事:
首先确定pc机连入的网络ip地址和stm32的ip地址是不是同一个网段:
这里192.168.0.1和192.168.0.10就处于同一个网段
其次如果是将stm32用网线接入路由器,则要确定stm32所使用的ip地址没有被占用,检测方法就是接入stm32前,先ping设定的地址,看能不能ping通,不能ping通表示没有被占用;这里是直接用网线连接stm32和pc机,所以不用担心这个问题
接下来可以用pc机ping下载好程序的stm32
win+R打开运行,输入cmd,回车
在命令行下输入ping 192.168.0.10
ping通成功,有图有真相
总结:
官方移植程序帮忙做了很多事情,可以方便使用,那么修改也不外乎这么几个地方,多多测试注意就可以成功,当能ping通,搭建好硬件软件环境之后就可以安心地一步步调用lwip的API接口函数建立服务器,客户端等等了。