说在前面
由于工作原因,从接触LWIP开始就是用的 CubeMX+HAL库。每次用起来都很方便,但也出现了一个问题:当没有CubeMX时就不知到该如何实现LWIP,于是有了这个突然的想法:学习LWIP标准库移植,在学习LWIP移植的同时还能学一下标准库的使用(其实就是找不到HAL库移植的教程和资料)。
注:本次的测试平台是 STM32F207 + DP83848
一、STM32标准库LWIP例程源码下载:
进入ST官网,首先点击放大镜图案,之后点击产品后的小三角形弹出类别选择框,选择类别为“工具与软件”,最后在搜索框里输入“LWIP”后回车
输入回车后会进入以下页面,找到F2的LWIP演示例程后下载(下载时需要登录ST账号,没有的自行注册一个吧),如下图所示:
二、LWIP移植
解压以后可以看到里面有“_htmresc”、“Libraries”、“Project”、“Utilities”这4个文件夹和“Release_Notes.html”这个文件。接下来开始进入移植工作,我们就以裸机实现tcp_echo_client这个例程为例进行移植,步骤如下:
1、新建一个文件夹,命名为“tcp_echo_client”,里面分别新建“Libraries”、“MDK-ARM”、“USER”这3个文件夹。
2、将例程源码中“Libraries”文件夹复制到“tcp_echo_client”根目录,之后再对复制过来的“Libraries”中的“CMSIS”文件夹进行处理:
a.将“CMSIS -> CM3 -> CoreSupport”里面的两个文件剪切到“CMSIS”根目录;
b.将“CMSIS -> CM3 -> DeviceSupport -> ST -> STM32F2xx -> startup -> arm”里面的“startup_stm32f2xx.s”文件剪切到“tcp_echo_client”里的“MDK-ARM”中;
c.将“CMSIS -> CM3 -> DeviceSupport -> ST -> STM32F2xx”里面的1个C文件和2个H文件剪切到“CMSIS”根目录;
d.删除“CMSIS”根目录中除了刚才剪切出来的5个文件其余文件/文件夹。
3、将例程源码中“Utilities -> Third_Party”的“lwip_v1.3.2”文件夹复制到“tcp_echo_client”的根目录。
4、将例程源码中“Project -> Standalone -> tcp_echo_client”里的“src”、“inc”两个文件夹复制到自己“tcp_echo_client -> USER”中,“src”文件夹只保留“main.c”、“netconf.c”、“stm32f2x7_eth_bsp.c”、“stm32f2xx_it.c”四个文件,“inc”文件夹删除“serial_debug.h”和“tcp_echoclient.h”这2个文件。
5、打开MDK5,新建“tcp_echo_client”工程,工程路径选择“tcp_echo_client -> MDK-ARM”,芯片选择STM32F207ZGTx,驱动文件后面手动添加。
6、点击MDK上面的红白绿三色品字形方块按钮打开工程树,将工程树名称设置为“tcp_echo_client”,之后在下面建立“StartUP”、“CORE”、“Driver”、“STM32F2x7_ETH_Driver”、“USER”、“LWIP”几个文件夹。
7、按下图所示添加文件到依次对应的文件夹。
8、MDK设置(点击上面的魔术棒按钮进入):
Tagget选项卡:勾上“Use MicroLIB”
C/C++选项卡:
Define栏输入:“USE_STDPERIPH_DRIVER,STM32F207ZG”两条处理宏;
编译路径:按下图添加
9、代码修改(解决代码中现在的bug):
main.h文件: 注销:“#define USE_LCD”
main.h文件:
注销:#include "serial_debug.h"
注销 “LCD_LED_BUTTON_Init”这个函数及其在开头的声明;
注销main函数中的语句:LCD_LED_BUTTON_Init();
stm32f2x7_eth_bsp.h文件:
注销 #include "stm322xg_eval.h"
注销 #include "stm322xg_eval_lcd.h"
stm32f2xx_it.c文件:
注销:#include "tcp_echoclient.h"
注销“EXTI15_10_IRQHandler”函数中的第一个if语句;
stm32f2x7_eth_bsp.c文件:
注销“ETH_BSP_Config”函数中以下语句:
if (EthInitStatus == 0)
{
LCD_SetTextColor(Red);
LCD_DisplayStringLine(Line5, (uint8_t*)" Ethernet Init ");
LCD_DisplayStringLine(Line6, (uint8_t*)" failed ");
while(1);
}
10、根据板子IO修改IO初始化代码(以我手上的板子为例,修改后的代码如下):
void ETH_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOs clocks */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB |
RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOI |
RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOH |
RCC_AHB1Periph_GPIOF, ENABLE);
/* Enable SYSCFG clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
/* MII/RMII Media interface selection --------------------------------------*/
#ifdef MII_MODE /* Mode MII with STM322xG-EVAL */
#ifdef PHY_CLOCK_MCO
/* Output HSE clock (25MHz) on MCO pin (PA8) to clock the PHY */
RCC_MCO1Config(RCC_MCO1Source_HSE, RCC_MCO1Div_1);
#endif /* PHY_CLOCK_MCO */
SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_MII);
/* Ethernet pins configuration ************************************************/
/**ETH GPIO Configuration
PA0/WKUP ------> ETH_CRS
PA1 ------> ETH_RX_CLK
PA2 ------> ETH_MDIO
PA3 ------> ETH_COL
PA7 ------> ETH_RX_DV
PB0 ------> ETH_RXD2
PB1 ------> ETH_RXD3
PB8 ------> ETH_TXD3
PB11 ------> ETH_TX_EN
PB12 ------> ETH_TXD0
PB13 ------> ETH_TXD1
PC1 ------> ETH_MDC
PC2 ------> ETH_TXD2
PC3 ------> ETH_TX_CLK
PC4 ------> ETH_RXD0
PC5 ------> ETH_RXD1
*/
/* Configure MCO (PA8) */
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);
/* Configure PA0 PA1, PA2 PA3 and PA7 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_ETH);
/* Configure PB0 PB1 PB8 PB11 PB12 and PB13 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1 | GPIO_Pin_8 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource0, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource1, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_ETH);
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, PC2, PC3, PC4 and PC5 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource1, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource2, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource3, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource4, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource5, GPIO_AF_ETH);
#elif defined RMII_MODE /* Mode RMII with STM322xG-EVAL */
SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_RMII);
#endif
}
修改完成后编译下载测试,网络已经通了
三、优化
使用硬件复位替代软件复位
先编写一个ETH_Hard_RESET函数,同时添加声明在文件开头,代码如下:
void ETH_Hard_RESET(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC, ENABLE);
/* Configure (PC9) */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//中等速度
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; //上拉
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_WriteBit(GPIOC,GPIO_Pin_9,Bit_RESET);
Delay(20);
GPIO_WriteBit(GPIOC,GPIO_Pin_9,Bit_SET);
Delay(50);
}
将”ETH_Hard_RESET“函数在”ETH_BSP_Config“函数开头调用;
注销“ETH_MACDMA_Config”函数中的“ETH_SoftwareReset();“语句;
修改完成后编译下载测试,网络也是通的。
-------------------------------------此记到此结束!希望能对大家有所帮助