基于STM32的无协议栈实现UDP通信

来源:互联网 发布:浙江大学网络平台 编辑:程序博客网 时间:2024/06/07 23:22

前段时间使用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;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
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);


//ÅäÖÃPC1,PC4 and PC5
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5;
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(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);
                                
//ÅäÖÃPG11, PG14 and PG13 
GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_14;
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(GPIOG, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource11, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource13, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource14, GPIO_AF_ETH);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//ÍÆÍêÊä³ö
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;  
GPIO_Init(GPIOD, &GPIO_InitStructure);

LAN8720_RST = 1;
delay_ms(50);
LAN8720_RST = 0;
delay_ms(50);
//delay_us(200);
LAN8720_RST = 1;
ETHERNET_NVICConfiguration();//配置以太网终端优先级
rval = ETH_MACDMA_Config();//配置MAC和DMA
if(ETH_SUCCESS != rval)
{
printf("%s: ETH MACDMA config error\r\n",__func__);
}

  ETH_MACAddressConfig(ETH_MAC_Address0, src_MAC); //向MAC地址寄存器写入本机MAC地址

ETH_Start();
return !rval;
}

以太网终端优先级配置如下:

void ETHERNET_NVICConfiguration(void)
{
NVIC_InitTypeDef NVIC_InitStructure = {0};

NVIC_InitStructure.NVIC_IRQChannel = ETH_IRQn;  //ÒÔÌ«ÍøÖжÏ
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0X00;  //ÖжϼĴæÆ÷×é2×î¸ßÓÅÏȼ¶
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0X00;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}

MAC和DMA配置函数如下:

u8 ETH_MACDMA_Config(void)
{
u8 rval = 0;
int s32ETH_Get_Reset_Status_Time = 1024;
ETH_InitTypeDef ETH_InitStructure = {0}; 

//ʹÄÜÒÔÌ«ÍøMACÒÔ¼°MAC½ÓÊպͷ¢ËÍʱÖÓ
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_ETH_MAC | RCC_AHB1Periph_ETH_MAC_Tx | RCC_AHB1Periph_ETH_MAC_Rx, ENABLE);
                        
ETH_DeInit();  //AHB×ÜÏßÖØÆôÒÔÌ«Íø
ETH_SoftwareReset();  //Èí¼þÖØÆôÍøÂç

while (ETH_GetSoftwareResetStatus() == SET)//µÈ´ýÈí¼þÖØÆôÍøÂçÍê³É £¬ÕâÒ»¿éÈÝÒ×ËÀÔÚÕâÀï
{
/******мÓÄÚÈÝ£¬·ÀÖ¹½øÈëËÀÑ­»·ÎÞ·¨Í˳ö*****/
s32ETH_Get_Reset_Status_Time--;
if(!(s32ETH_Get_Reset_Status_Time--))
{
printf("%s(%d):wait ETH softreset timeout\r\n",__func__,__LINE__);
break;
}
}

ETH_StructInit(&ETH_InitStructure); //³õʼ»¯ÍøÂç½á¹¹ÌåΪĬÈÏÖµ


///ÍøÂçMAC²ÎÊýÉèÖÃ
ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable;   //¿ªÆôÍøÂç×ÔÊÊÓ¦¹¦ÄÜ
ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable;//¹Ø±Õ·´À¡
ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable;//¹Ø±ÕÖØ´«¹¦ÄÜ
ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;//¹Ø±Õ×Ô¶¯È¥³ýPDA/CRC¹¦ÄÜ 
ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable;//¹Ø±Õ½ÓÊÕËùÓеÄÖ¡
ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;//ÔÊÐí½ÓÊÕËùÓй㲥֡
ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable;//¹Ø±Õ»ìºÏģʽµÄµØÖ·¹ýÂË  
ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;//¶ÔÓÚ×é²¥µØַʹÓÃÍêÃÀµØÖ·¹ýÂË   
ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect;//¶Ôµ¥²¥µØַʹÓÃÍêÃÀµØÖ·¹ýÂË 
#ifdef CHECKSUM_BY_HARDWARE
ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable;//¿ªÆôipv4ºÍTCP/UDP/ICMPµÄ֡УÑéºÍжÔØ   
#endif
//µ±ÎÒÃÇʹÓÃ֡УÑéºÍжÔع¦ÄܵÄʱºò£¬Ò»¶¨ÒªÊ¹Äܴ洢ת·¢Ä£Ê½,´æ´¢×ª·¢Ä£Ê½ÖÐÒª±£Ö¤Õû¸öÖ¡´æ´¢ÔÚFIFOÖÐ,
//ÕâÑùMACÄܲåÈë/ʶ±ð³ö֡УÑéÖµ,µ±ÕæУÑéÕýÈ·µÄʱºòDMA¾Í¿ÉÒÔ´¦ÀíÖ¡,·ñÔò¾Í¶ªÆúµô¸ÃÖ¡
ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Enable; //¿ªÆô¶ªÆúTCP/IP´íÎóÖ¡
ETH_InitStructure.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable;     //¿ªÆô½ÓÊÕÊý¾ÝµÄ´æ´¢×ª·¢Ä£Ê½    
ETH_InitStructure.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable;   //¿ªÆô·¢ËÍÊý¾ÝµÄ´æ´¢×ª·¢Ä£Ê½  


ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable;     //½ûֹת·¢´íÎóÖ¡  
ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Disable;//²»×ª·¢¹ýСµÄºÃÖ¡ 
ETH_InitStructure.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Enable; //´ò¿ª´¦ÀíµÚ¶þÖ¡¹¦ÄÜ
ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable; //¿ªÆôDMA´«ÊäµÄµØÖ·¶ÔÆ빦ÄÜ
ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable;           //¿ªÆô¹Ì¶¨Í»·¢¹¦ÄÜ    
ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat;     //DMA·¢Ë͵Ä×î´óÍ»·¢³¤¶ÈΪ32¸ö½ÚÅÄ   
ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat;//DMA½ÓÊÕµÄ×î´óÍ»·¢³¤¶ÈΪ32¸ö½ÚÅÄ
ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1;

rval = ETH_Init(&ETH_InitStructure,LAN8720_PHY_ADDRESS);//ÅäÖÃETH
#if 1 //ԭΪ0
if(rval == ETH_SUCCESS)//ʹÄÜÒÔÌ«ÍøµÄ·¢ËͺͽÓÊÕÖжÏ
{
//ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_T, ENABLE);
ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_R | ETH_DMA_IT_T, ENABLE);
}
#endif
return rval;
}

网口接收中断函数如下:

void ETH_IRQHandler(void) //最好不要在中断函数中处理数据,而是将数据尽快拷出来在其他地方处理
{
static unsigned int i = 0;
FrameTypeDef frame = {0};
printf("%s(%d)\r\n",__func__,__LINE__);

if((FrameLength_Receice = ETH_GetRxPktSize(DMARxDescToGet)) != 0)//¼ì²âÊÇ·ñÊÕµ½Êý¾Ý°ü£¬²¢½«±¨µÄ³¤¶È±£´æÆðÀ´

    frame = ETH_Rx_Packet(); //¼ì²âµ½½ÓÊÕÁËÊý¾Ý°üºó£¬½ÓÊÕµÄÊý¾Ý°üÔÚ½ÓÊÕ»º³åÇøÖÐ

if(ETH_ERROR != frame.length)
{
if(eth_buff[6] != 0)
{
i++;
printf("%s(%d) lost %d package\r\n",__func__,__LINE__,i);
}
else
{
memcpy(eth_buff, (void *)frame.buffer, frame.length);
}
}

frame.descriptor->Status = ETH_DMARxDesc_OWN;//ÉèÖÃRxÃèÊö·ûOWNλ,bufferÖعéETH DMA 
if((ETH->DMASR & ETH_DMASR_RBUS) != (u32)RESET)//µ±Rx Buffer²»¿ÉÓÃλ(RBUS)±»ÉèÖõÄʱºò,ÖØÖÃËü.»Ö¸´´«Êä

ETH->DMASR = ETH_DMASR_RBUS;//ÖØÖÃETH DMA RBUSλ 
ETH->DMARPDR = 0;//»Ö¸´DMA½ÓÊÕ
}
}
ETH_DMAClearITPendingBit(ETH_DMA_IT_R); //Çå³ýDMAÖжϱê־λ
ETH_DMAClearITPendingBit(ETH_DMA_IT_NIS);//Çå³ýDMA½ÓÊÕÖжϱê־λ

//Receive_ARP(); //¿½±´»º³åÇøÄڵĽÓÊÕÊý¾Ýµ½Ö¸¶¨½á¹¹Ìå

//Answer_ARP(); //¸ø³öarpÓ¦´ð
}  

原创粉丝点击