前段时间使用STM32收发UDP消息,由于系统只需简单的接收和发送UDP消息,不需要ARP、TCP等复杂功能,首先在网上搜索相关例程,发现有不少人在问这个问题,但是给出的建议多是让移植LWIP,于是本人就在分析LWIP的基础上,找到了网口收发最底层接口,通过最底层收发接口实现UDP消息收发。
STM32的网口只具有MAC层协议,没有物理层PHY;在硬件上首先要外接一个物理层PHY芯片,本人使用的PHY芯片为lan8720,连接方式如图1所示。
图1 STM32与网口物理层芯片连接电路图
网口需要两个缓冲区,发送缓冲区和接收缓冲器。STM32网口收发流程为:首先将数据写入发送缓冲区,然后启动DMA传输开始发送;接收是通过中断去读接收缓冲区,接收完清除DMA传输完成标志。
my_mem_init(SRAMIN); //初始化内存管理
DMARxDscrTab = mymalloc(s32Sram_Address, ETH_RXBUFNB * sizeof(ETH_DMADESCTypeDef));//申请内存
DMATxDscrTab = mymalloc(s32Sram_Address, ETH_TXBUFNB * sizeof(ETH_DMADESCTypeDef));
Rx_Buff = mymalloc(s32Sram_Address, ETH_RX_BUF_SIZE * ETH_RXBUFNB);
Tx_Buff = mymalloc(s32Sram_Address, ETH_TX_BUF_SIZE * ETH_TXBUFNB);
ETH_DMATxDescChainInit(DMATxDscrTab, Tx_Buff, ETH_TXBUFNB); //将发送缓冲区设置为循环链表
ETH_DMARxDescChainInit(DMARxDscrTab, Rx_Buff, ETH_RXBUFNB);//将接收缓冲区设置为循环链表
for(i = 0; i < ETH_TXBUFNB; i++)//使能TCP、UDP和ICMP发送帧校验
{
ETH_DMATxDescChecksumInsertionConfig(&DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull);
}
if(LAN8720_Init() != 0)
{
PHY_Register_Print(LAN8720_PHY_ADDRESS);//µ÷ÊÔʱ²é¿´LAN8720AËùÓмĴæÆ÷µÄ״̬
printf("LAN8720_Init error! \r\n");
}
LAN8720_Init函数的实现如下:
u8 LAN8720_Init(void)
{
u8 rval = 0;
int i = 0;
GPIO_InitTypeDef GPIO_InitStructure = {0};
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOD, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_RMII);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;