GG32F450XX上移植RT-Thread+LWIP协议栈
时间:2022-11-08 03:00:00
GD正式提供的例程ENET例程是FreeRtos LWIP协议,所以我又做了移植(RT-Thread nano LWIP1.4.1)。
总结以下几点:
1,第一步是ENET首先要保证单片机的初始化emac能通过RMII与物理芯片通信。保证能通信的前提是RMII_REF_CLK引脚上有时钟信号,然后是RMII物理芯片地址正确。ENET初始化代码可参照官方例程。
void enet_system_setup(void) {
uint32_t ahb_frequency = 0; #ifdef USE_ENET_INTERRUPT nvic_configuration(); #endif /* USE_ENET_INTERRUPT */ /* configure the GPIO ports for ethernet pins */ enet_gpio_config(); /* configure the ethernet MAC/DMA */ enet_mac_dma_config(); if (0 == enet_init_status){
while(1){
} } enet_interrupt_enable(ENET_DMA_INT_NIE); enet_interrupt_enable(ENET_DMA_INT_RIE); }
第二步是LWIP的移植,LWIP1.4.1源码包我是照搬GD32F450XX我们需要修改的主要有两个文件
ethernetif.c/.h 和 sys_arch.c/.h 文件,因为LWIP1.4.信号量和邮箱在1中被广泛使用,因此需要特别注意这两个地方的移植。一开始我不懂源代码,所以我跑去修改问题LWIP里面的源代码越晕,最后发现是因为FreeRtos与RT-Thread邮箱和信号量的使用方式不同。所以LWIP协议栈本身没有问题,经得起考究,不要怀疑官方。所以LWIP协议栈本身没有问题,经得起考究,不要怀疑官方。这两个文件也涉及邮箱和信号量。贴源码:
ethernetif.c
/** * @file * Ethernet Interface Skeleton * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/lwip_timers.h"
#include "netif/etharp.h"
#include "err.h"
#include "ethernetif.h"
#include "main.h"
#include "gd32f4xx_enet.h"
#include
#define ETHERNETIF_INPUT_TASK_STACK_SIZE (350)
#define ETHERNETIF_INPUT_TASK_PRIO (configMAX_PRIORITIES - 1)
#define LOWLEVEL_OUTPUT_WAITING_TIME (250)
/* The time to block waiting for input */
#define LOWLEVEL_INPUT_WAITING_TIME ((uint32_t )100)
/* define those to better describe your network interface */
#define IFNAME0 'G'
#define IFNAME1 'D'
/* ENET RxDMA/TxDMA descriptor */
extern enet_descriptors_struct rxdesc_tab[ENET_RXBUF_NUM], txdesc_tab[ENET_TXBUF_NUM];
/* ENET receive buffer */
extern uint8_t rx_buff[ENET_RXBUF_NUM][ENET_RXBUF_SIZE];
/* ENET transmit buffer */
extern uint8_t tx_buff[ENET_TXBUF_NUM][ENET_TXBUF_SIZE];
/*global transmit and receive descriptors pointers */
extern enet_descriptors_struct *dma_current_txdesc;
extern enet_descriptors_struct *dma_current_rxdesc;
/* preserve another ENET RxDMA/TxDMA ptp descriptor for normal mode */
enet_descriptors_struct ptp_txstructure[ENET_TXBUF_NUM];
enet_descriptors_struct ptp_rxstructure[ENET_RXBUF_NUM];
static struct netif *low_netif = NULL;
sys_sem_t g_rx_semaphore = NULL;
/** * In this function, the hardware should be initialized. * Called from ethernetif_init(). * * @param netif the already initialized lwip network interface structure * for this ethernetif */
static void low_level_init(struct netif *netif)
{
uint32_t i;
rt_thread_t t;
/* set netif MAC hardware address length */
netif->hwaddr_len = ETHARP_HWADDR_LEN;
/* set netif MAC hardware address */
netif->hwaddr[0] = MAC_ADDR0;
netif->hwaddr[1] = MAC_ADDR1;
netif->hwaddr[2] = MAC_ADDR2;
netif->hwaddr[3] = MAC_ADDR3;
netif->hwaddr[4] = MAC_ADDR4;
netif->hwaddr[5] = MAC_ADDR5;
/* set netif maximum transfer unit */
netif->mtu = 1500;
/* accept broadcast address and ARP traffic */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
low_netif =netif;
/* create binary semaphore used for informing ethernetif of frame reception */
if (g_rx_semaphore == NULL){
g_rx_semaphore = rt_sem_create("sem", 1, RT_IPC_FLAG_FIFO);
rt_sem_take(g_rx_semaphore, 0);
}
/* initialize MAC address in ethernet MAC */
enet_mac_address_set(ENET_MAC_ADDRESS0, netif->hwaddr);
/* initialize descriptors list: chain/ring mode */
#ifdef SELECT_DESCRIPTORS_ENHANCED_MODE
enet_ptp_enhanced_descriptors_chain_init(ENET_DMA_TX);
enet_ptp_enhanced_descriptors_chain_init(ENET_DMA_RX);
#else
enet_descriptors_chain_init(ENET_DMA_TX);
enet_descriptors_chain_init(ENET_DMA_RX);
// enet_descriptors_ring_init(ENET_DMA_TX);
// enet_descriptors_ring_init(ENET_DMA_RX);
#endif /* SELECT_DESCRIPTORS_ENHANCED_MODE */
/* enable ethernet Rx interrrupt */
{
int i;
for(i=0; i<ENET_RXBUF_NUM; i++){
enet_rx_desc_immediate_receive_complete_interrupt(&rxdesc_tab[i]);
}
}
#ifdef CHECKSUM_BY_HARDWARE
/* enable the TCP, UDP and ICMP checksum insertion for the Tx frames */
for(i=0; i < ENET_TXBUF_NUM; i++){
enet_transmit_checksum_config(&txdesc_tab[i], ENET_CHECKSUM_TCPUDPICMP_FULL);
}
#endif /* CHECKSUM_BY_HARDWARE */
/* create thread */
t = rt_thread_create("ETHERNETIF_INPUT", ethernetif_input, RT_NULL, ETHERNETIF_INPUT_TASK_STACK_SIZE, ETHERNETIF_INPUT_TASK_PRIO, 1);
RT_ASSERT(t != RT_NULL);
/* startup thread */
rt_thread_startup(t);
/* enable MAC and DMA transmission and reception */
enet_enable();
}
/** * This function should do the actual transmission of the packet. The packet is * contained in the pbuf that is passed to the function. This pbuf * might be chained. * * @param netif the lwip network interface structure for this ethernetif * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) * @return ERR_OK if the packet could be sent * an err_t value if the packet couldn't be sent * * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to * strange results. You might consider waiting for space in the DMA queue * to become availale since the stack doesn't retry to send a packet * dropped because of memory failure (except for the TCP timers). */
static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
static sys_sem_t s_tx_semaphore = NULL;
struct pbuf *q;
uint8_t *buffer ;
uint16_t framelength = 0;
ErrStatus reval = ERROR;
SYS_ARCH_DECL_PROTECT(sr);
if (s_tx_semaphore == NULL){
s_tx_semaphore = rt_sem_create("sem", 1, RT_IPC_FLAG_FIFO);
}
if (RT_EOK == rt_sem_take(s_tx_semaphore, LOWLEVEL_OUTPUT_WAITING_TIME)){
SYS_ARCH_PROTECT(sr);
while((uint32_t)RESET != (dma_current_txdesc->status & ENET_TDES0_DAV)){
}
buffer = (uint8_t *)(enet_desc_information_get(dma_current_txdesc, TXDESC_BUFFER_1_ADDR));
for(q = p; q != NULL; q = q->next){
memcpy((uint8_t *)&buffer[framelength], q->payload, q->len);
framelength = framelength + q->len;
}
/* transmit descriptors to give to DMA */
#ifdef SELECT_DESCRIPTORS_ENHANCED_MODE
reval = ENET_NOCOPY_PTPFRAME_TRANSMIT_ENHANCED_MODE(framelength, NULL);
#else
reval = ENET_NOCOPY_FRAME_TRANSMIT(framelength);
#endif /* SELECT_DESCRIPTORS_ENHANCED_MODE */
SYS_ARCH_UNPROTECT(sr);
/* give semaphore and exit */
rt_sem_release(s_tx_semaphore);
}
if(SUCCESS == reval){
return ERR_OK;
}else{
while(1){
}
}
}
/** * Should allocate a pbuf and transfer the bytes of the incoming * packet from the interface into the pbuf. * * @param netif the lwip network interface structure for this ethernetif * @return a pbuf filled with the received packet (including MAC header) * NULL on memory error */
static struct pbuf * low_level_input(struct netif *netif)
{
struct pbuf *p= NULL, *q;
uint32_t l =0;
u16_t len;
uint8_t *buffer;
/* obtain the size of the packet and put it into the "len" variable. */
len = enet_desc_information_get(dma_current_rxdesc, RXDESC_FRAME_LENGTH);
buffer = (uint8_t *)(enet_desc_information_get(dma_current_rxdesc, RXDESC_BUFFER_1_ADDR));
if (len > 0){
/* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
}
if (p != NULL){
for(q = p; q != NULL; q = q->next){
memcpy((uint8_t *)q->payload, (u8_t*)&buffer[l], q->len);
l = l + q->len;
}
}
#ifdef SELECT_DESCRIPTORS_ENHANCED_MODE
ENET_NOCOPY_PTPFRAME_RECEIVE_ENHANCED_MODE(NULL);
#else
ENET_NOCOPY_FRAME_RECEIVE();
#endif /* SELECT_DESCRIPTORS_ENHANCED_MODE */
return p;
}
/** * This function is the ethernetif_input task, it is processed when a packet * is ready to be read from the interface. It uses the function low_level_input() * that should handle the actual reception of bytes from the network * interface. Then the type of the received packet is determined and * the appropriate input function is called. * * @param netif the lwip network interface structure for this ethernetif */
void ethernetif_input( void * pvParameters )
{
struct pbuf *p;
SYS_ARCH_DECL_PROTECT(sr);
for( ;; ){
if(0 == rt_sem_take(g_rx_semaphore, LOWLEVEL_INPUT_WAITING_TIME)){
TRY_GET_NEXT_FRAME:
SYS_ARCH_PROTECT(sr);
p = low_level_input( low_netif );
SYS_ARCH_UNPROTECT(sr);
if (p != NULL){
if (ERR_OK != low_netif->input( p, low_netif)){
pbuf_free(p);
}else{
goto TRY_GET_NEXT_FRAME;
}
}
}
}
}
/** * Should be called at the beginning of the program to set up the * network interface. It calls the function low_level_init() to do the * actual setup of the hardware. * * This function should be passed as a parameter to netif_add(). * * @param netif the lwip network interface structure for this ethernetif * @return ERR_OK if the loopif is initialized * ERR_MEM if private data couldn't be allocated * any other err_t on error */
err_t ethernetif_init(struct netif *netif)
{
LWIP_ASSERT("netif != NULL", (netif != NULL));
#if LWIP_NETIF_HOSTNAME
/* initialize interface hostname */
netif->hostname = "lwip";
#endif /* LWIP_NETIF_HOSTNAME */
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
netif->output = etharp_output;
netif->linkoutput = low_level_output;
/* initialize the hardware */
low_level_init(netif);
return ERR_OK;
}
sys_arch.c
/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */
/* lwIP includes. */
#include "lwip/debug.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/mem.h"
#include "lwip/stats.h"
#include "rtthread.h"
#include
#define PRIVILEGED_FUNCTION
#define PRIVILEGED_DATA
void * xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION;
static u16_t s_nextthread = 0;
/*-----------------------------------------------------------------------------------*/
//Creates an empty mailbox.
err_t sys_mbox_new(sys_mbox_t *mbox, int size)
{
static unsigned short counter = 0;
char tname[RT_NAME_MAX];
sys_mbox_t tmpmbox;
RT_DEBUG_NOT_IN_INTERRUPT;
rt_snprintf(tname, RT_NAME_MAX, "%s%d", SYS_LWIP_MBOX_NAME, counter);
counter ++;
tmpmbox = rt_mb_create(tname, size, RT_IPC_FLAG_FIFO);
if (tmpmbox == RT_NULL)
{
return ERR_MEM;
}
*mbox = tmpmbox;
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
/* Deallocates a mailbox. If there are messages still present in the mailbox when the mailbox is deallocated, it is an indication of a programming error in lwIP and the developer should be notified. */
void sys_mbox_free(sys_mbox_t *mbox)
{
RT_DEBUG_NOT_IN_INTERRUPT;
rt_mb_delete(*mbox);
return;
}
/*-----------------------------------------------------------------------------------*/
// Posts the "msg" to the mailbox.
void sys_mbox_post(sys_mbox_t *mbox, void *data)
{
RT_DEBUG_NOT_IN_INTERRUPT;
rt_mb_send_wait(*mbox, (rt_uint32_t)data, RT_WAITING_FOREVER);
return;
}
/*-----------------------------------------------------------------------------------*/
// Try to post the "msg" to the mailbox.
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
{
err_t result;
if (rt_mb_send(*mbox, (rt_uint32_t)msg) == RT_EOK)
return ERR_OK;
return ERR_MEM;
}
/*-----------------------------------------------------------------------------------*/
/* Blocks the thread until a message arrives in the mailbox, but does not block the thread longer than "timeout" milliseconds (similar to the sys_arch_sem_wait() function). The "msg" argument is a result parameter that is set by the function (i.e., by doing "*msg = ptr"). The "msg" parameter maybe NULL to indicate that the message should be dropped. The return values are the same as for the sys_arch_sem_wait() function: Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a timeout. Note that a function with a similar name, sys_mbox_fetch(), is implemented by lwIP. */
u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
{
rt_err_t ret;
s32_t t;
u32_t tick;
RT_DEBUG_NOT_IN_INTERRUPT;
/* get the begin tick */
tick = rt_tick_get();
if(timeout == 0)
t = RT_WAITING_FOREVER;
else
{
/* convirt msecond to os tick */
if (timeout < (1000/RT_TICK_PER_SECOND))
t = 1;
else
t = timeout / (1000/RT_TICK_PER_SECOND);
}
ret = rt_mb_recv(*mbox, (rt_ubase_t *)msg, t);
if(ret != RT_EOK)
{
return SYS_ARCH_TIMEOUT;
}
/* get elapse msecond */
tick = rt_tick_get() - tick;
/* convert tick to msecond */
tick = tick * (1000 / RT_TICK_PER_SECOND);
if (tick == 0)
tick = 1;
return tick;
}
/*-----------------------------------------------------------------------------------*/
/* Similar to sys_arch_mbox_fetch, but if message is not ready immediately, we'll return with SYS_MBOX_EMPTY. On success, 0 is returned. */
u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
{
int ret;
ret = rt_mb_recv(*mbox, (rt_ubase_t *)msg, 0);
if(ret == RT_EOK)
{
return ERR_OK;
}
else{
return SYS_MBOX_EMPTY;
}
}
/*----------------------------------------------------------------------------------*/
int sys_mbox_valid(sys_mbox_t *mbox)
{
if (*mbox == SYS_MBOX_NULL){
return 0;
}
else{
return 1;
}
}
/*-----------------------------------------------------------------------------------*/
void sys_mbox_set_invalid(sys_mbox_t *mbox)
{
*mbox = SYS_MBOX_NULL;
}
/*-----------------------------------------------------------------------------------*/
// Creates a new semaphore. The "count" argument specifies
// the initial state of the semaphore.
err_t