Copyright: Chengdu Heng Yuan Internet of Things Technology Co., Ltd.
Website: www.heryit.cn
Tel: 028-87657875 13060063607
Introduce the configuration of stm32f107 Ethernet and porting rl-tcpnet protocol stack, the official routine is LWIP, here is how to use rl-tcpnet. (need to include STM32_ETH.C and STM32_ETH.H)
Here is the descriptor definition, what is the descriptor please see the STM32 Chinese Reference Manual Ethernet Chapter
/* 描述符数量和缓存大小定义 */#define NUM_RX_BUF 4 //接收描述符数量和缓存数量#define NUM_TX_BUF 2 //发送描述符数量和缓存数量#define ETH_BUF_SIZE 1536 //每个缓存大小/* 接收描述符和发送描述符结构体类型定义(含义请参考STM32中文参考手册) */typedef struct { U32 volatile Stat; U32 Ctrl; U32 Addr; U32 Next;} RX_Desc;typedef struct { U32 volatile CtrlStat; U32 Size; U32 Addr; U32 Next;} TX_Desc;/* 当前使用的描述符序号 */static U8 TxBufIndex;static U8 RxBufIndex;/* DMA描述符声明 */static RX_Desc Rx_Desc[NUM_RX_BUF];static TX_Desc Tx_Desc[NUM_TX_BUF];/* 描述符所指向的内存 */static U32 rx_buf[NUM_RX_BUF][ETH_BUF_SIZE>>2];static U32 tx_buf[NUM_TX_BUF][ETH_BUF_SIZE>>2];
To use the Rl-tcpnet protocol stack, you need to provide an interface function for rl-tcpnet: void init_ethernet (void); void Send_frame (Os_frame *frame); void Int_enable_eth (void); void Int_disable_eth (void); The following are the corresponding functions:
Ethernet Hardware initialization (interface provided to rl-tcpnet) void init_ethernet (void) {nvic_inittypedef nvic_initstructure; Gpio_inittypedef gpio_initstructure; Eth_inittypedef eth_initstructure; #define Time_out 0x0003fffful uint32_t time = 0; /* Enable clock */Rcc_ahbperiphclockcmd (Rcc_ahbperiph_eth_mac | Rcc_ahbperiph_eth_mac_tx | RCC_AHBPERIPH_ETH_MAC_RX, ENABLE); /* Enable GPIO clock */rcc_apb2periphclockcmd (Rcc_apb2periph_gpioa | Rcc_apb2periph_gpiob | RCC_APB2PERIPH_GPIOC | Rcc_apb2periph_gpiod | Rcc_apb2periph_gpioe | Rcc_apb2periph_afio, ENABLE); /* Select interrupt vector table */nvic_setvectortable (Nvic_vecttab_flash, 0x0); Nvic_prioritygroupconfig (nvic_prioritygroup_2); /* Enable Ethernet Global Interrupt */Nvic_initstructure.nvic_irqchannel = ETH_IRQN; Nvic_initstructure.nvic_irqchannelpreemptionpriority = 2; nvic_initstructure.nvic_irqchannelsubpriority = 0; Nvic_initstructure.nvic_irqchannelcmd = ENABLE; Nvic_init (&nvic_Initstructure); /* Ethernet PIN configuration currently using the RMII interface, no remapping required to use the Mii interface please modify */* AF Output Push Pull by yourself:-eth_rmii_mdio:pa2-eth_rmi I_MDC:PC1-ETH_RMII_TX_EN:PB11-ETH_RMII_TXD0:PB12-ETH_RMII_TXD1:PB13 */* Configure PA2 as alternate function Push-pull */gpio_initstructure.gpio_pin = gpio_pin_2; Gpio_initstructure.gpio_speed = Gpio_speed_50mhz; Gpio_initstructure.gpio_mode = gpio_mode_af_pp; Gpio_init (Gpioa, &gpio_initstructure); /* Configure PC1 as alternate function push-pull */gpio_initstructure.gpio_pin = gpio_pin_1; Gpio_initstructure.gpio_speed = Gpio_speed_50mhz; Gpio_initstructure.gpio_mode = gpio_mode_af_pp; Gpio_init (GPIOC, &gpio_initstructure); /* Configure PB5, PB8, PB11, PB12 and PB13 as alternate function push-pull */Gpio_initstructure.gpio_pin = Gpio_pin_11 | Gpio_pin_12 | gpio_pin_13; Gpio_initstructure.gpio_speed = Gpio_speed_50mhz; Gpio_initstructure.gpio_mode = gpio_mode_af_pp; Gpio_iNIT (GPIOB, &gpio_initstructure); /* Input:-ETH_RMII_REF_CLK:PA1-ETH_RMII_CRS_DV:PA7-ETH_RMII_RXD0:PC4-ETH_RMII_RXD1:PC5 */* Con Figure PA1 and PA7 as input */Gpio_initstructure.gpio_pin = gpio_pin_1 | gpio_pin_7; Gpio_initstructure.gpio_speed = Gpio_speed_50mhz; Gpio_initstructure.gpio_mode = gpio_mode_in_floating; Gpio_init (Gpioa, &gpio_initstructure); /* Configure PC4 and PC5 as input */Gpio_initstructure.gpio_pin = Gpio_pin_4 | Gpio_pin_5; Gpio_initstructure.gpio_speed = Gpio_speed_50mhz; Gpio_initstructure.gpio_mode = gpio_mode_in_floating; Gpio_init (GPIOC, &gpio_initstructure); /* Select configured as Mii or RMII, currently rmii*/gpio_eth_mediainterfaceconfig (GPIO_ETH_MEDIAINTERFACE_RMII); /* Reset Ethernet */Eth_deinit (); Eth_softwarereset (); /* Wait for the reset to complete */while (eth_getsoftwareresetstatus () = = SET); /* Ethernet configuration, populate the eth_initstructure structure, and finally call Eth_init () to configure Ethernet */Eth_structinit (ð_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; 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; #endif/*------------------------DMA-----------------------------------*/Eth_initstructure.eth_droptcpipche Cksumerrorframe = Eth_droptcpipchecksumerrorframe_enable; 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; Eth_initstructure.eth_fixedburst = eth_fixedburst_enable; Eth_initstructure.eth_rxdmaburstlength = Eth_rxdmaburstlength_32beat; Eth_initstructure.eth_txdmaburstlength = Eth_txdmaburstlength_32beat; Eth_initstructure.eth_dmaarbitration = Eth_dmaarbitration_roundrobin_rxtx_2_1; /* Initialize Ethernet, the second parameter is phY chip Address */Eth_init (ð_initstructure, lan9303_vphy_addr); Receive descriptor initialization rx_descr_init (); Send descriptor initialization tx_descr_init (); /* Enable normal total interrupt and receive interrupt */Eth_dmaitconfig (Eth_dma_it_nis | Eth_dma_it_r, ENABLE); Enable to send and receive ETH->DMAOMR |= Domr_st | DOMR_SR; ETH->MACCR |= Mcr_re | Mcr_te; Configure the MAC address, otherwise you can only receive broadcast data Eth_macaddressconfig (ETH_MAC_ADDRESS0, Own_hw_adr);} Enable and disable Ethernet interrupts void Int_enable_eth (void) {/* Ethernet Interrupt Enable function. */nvic->iser[1] = 1 << 29; }void Int_disable_eth (void) {/* Ethernet Interrupt Disable function. */nvic->icer[1] = 1 << 29;} Send a frame of data (interface function provided to rl-tcpnet) void Send_frame (Os_frame *frame) {U32 *sp,*dp; U32 i,j; j = Txbufindex; /* Wait until the data is sent */while (Tx_desc[j]. Ctrlstat & Dma_tx_own); SP =** (U32 *) &frame->data[0]; DP = (U32 *) tx_desc[j]. ADDR; /* Copy the data that needs to be sent to the memory specified by the Send descriptor */for (i = (frame->length + 3) >> 2; i; i--) {*dp++ = *sp++; }//Send data volume TX_DESC[J]. Size = frame->length; Modify send descriptor belongs to DMA Tx_desc[j]. Ctrlstat |= Dma_tx_own; /* Write data to DMATPDR to begin DMA Transfer */if ((Eth->dmasr | Dsr_tbus)!*= 0) {Eth->dmasr = Dsr_tbus; ETH->DMATPDR = 0; } if (++j = = num_tx_buf) j = 0; Txbufindex = j;}
The above is the interface function that needs to be provided to rl-tcpnet.
Interrupt Service function for receiving Ethernet data.
Ethernet Interrupt Service function (for receiving Ethernet data) void Eth_irqhandler (void) {/* Ethernet Controller Interrupt function. */Os_frame *frame; U32 I,rxlen; U32 *SP,*DP; i = Rxbufindex; do {/* Valid frame has been received. */* if (Rx_desc[i]. Stat & Dma_rx_error_mask) {goto rel; } if ((Rx_desc[i]. Stat & dma_rx_seg_mask)! = dma_rx_seg_mask) {goto rel; } Rxlen = ((rx_desc[i). Stat >>) & 0X3FFF)-4; if (Rxlen > Eth_mtu) {/* Packet too big, ignore it and free buffer. */goto rel; }/* Flag 0x80000000 to skip Sys_error () call when out of memory. */frame = Alloc_mem (Rxlen | 0x80000000); /* if ' alloc_mem () ' have failed, ignore this packet. */if (frame! = NULL) {SP = (U32 *) (Rx_desc[i]. Addr &); DP = (U32 *) &frame->data[0]; for (Rxlen = (Rxlen + 3) >> 2; Rxlen; rxlen--) {*dp++ = *sp++; } put_in_queue (frame); }/* Release this frame from ETH IO buffer. */rel:rx_desc[i]. Stat = Dma_rx_own; if (++i = = num_rx_buf) i = 0; } while ((Rx_desc[i]. Stat & dma_rx_own) = = 0); Rxbufindex = i; if (Eth->dmasr & Int_rbuie) {/* Rx DMA suspended, resume DMA reception. */Eth->dmasr = Int_rbu IE; ETH->DMARPDR = 0; }/* Clear the Interrupt pending bits. */Eth->dmasr = Int_nise | Int_rie;}
Receive descriptor Initialization
//接收描述符初始化static void rx_descr_init (void) { /* Initialize Receive DMA Descriptor array. */ U32 i,next; RxBufIndex = 0; for (i = 0, next = 0; i < NUM_RX_BUF; i++) { if (++next == NUM_RX_BUF) next = 0; Rx_Desc[i].Stat = DMA_RX_OWN; Rx_Desc[i].Ctrl = DMA_RX_RCH | ETH_BUF_SIZE; Rx_Desc[i].Addr = (U32)&rx_buf[i]; Rx_Desc[i].Next = (U32)&Rx_Desc[next]; } //指向第一个描述符 ETH->DMARDLAR = (U32)&Rx_Desc[0];}
Send Descriptor initialization
//发送描述符初始化static void tx_descr_init (void) { /* Initialize Transmit DMA Descriptor array. */ U32 i,next; TxBufIndex = 0; for (i = 0, next = 0; i < NUM_TX_BUF; i++) { if (++next == NUM_TX_BUF) next = 0; Tx_Desc[i].CtrlStat = DMA_TX_TCH | DMA_TX_LS | DMA_TX_FS; Tx_Desc[i].Addr = (U32)&tx_buf[i]; Tx_Desc[i].Next = (U32)&Tx_Desc[next]; } //指向第一个描述符 ETH->DMATDLAR = (U32)&Tx_Desc[0];}
To do this, add the Rl-tcpnet library and configuration file to the project to use Rl-tcpnet, and refer to the Rl-arm Help documentation for use.
stm32f107 Ethernet + rl-tcpnet