GD32F450XX上移植RT-Thread+LWIP协议栈

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);
}

2,第二步就是LWIP的移植,LWIP1.4.1源码包我是照搬GD32F450XX的官方例程拷贝的,我们需要修改的地方主要有两个文件
ethernetif.c/.h 和 sys_arch.c/.h 文件,因为LWIP1.4.1中大量使用了信号量和邮箱,所以特别需要注意这两个地方的移植,我一开始没看懂源码,所以出了问题跑去修改LWIP里边的源码,导致越该越晕,到最后发现是因为FreeRtos与RT-Thread的邮箱和信号量使用方式不一样导致的。所以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 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 <adam@sics.se>
*
*/

#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 <string.h>


#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 <adam@sics.se>
 *
 */

/* 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 <rthw.h>

#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 sys_sem_new(sys_sem_t *sem, u8_t count)
{
    static unsigned short counter = 0;
    char tname[RT_NAME_MAX];
    sys_sem_t tmpsem;

    RT_DEBUG_NOT_IN_INTERRUPT;

    rt_snprintf(tname, RT_NAME_MAX, "%s%d", SYS_LWIP_SEM_NAME, counter);
    counter ++;

    tmpsem = rt_sem_create(tname, count, RT_IPC_FLAG_FIFO);
    if (tmpsem == RT_NULL)
        return ERR_MEM;
	
    *sem = tmpsem;
	
	// Means it can't be taken
//    if(count == 0){
//        rt_sem_take(*sem,1);
//    }

    return ERR_OK;
}

/*-----------------------------------------------------------------------------------*/
/*
  Blocks the thread while waiting for the semaphore to be
  signaled. If the "timeout" argument is non-zero, the thread should
  only be blocked for the specified time (measured in
  milliseconds).

  If the timeout argument is non-zero, the return value is the number of
  milliseconds spent waiting for the semaphore to be signaled. If the
  semaphore wasn't signaled within the specified time, the return value is
  SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
  (i.e., it was already signaled), the function may return zero.

  Notice that lwIP implements a function with a similar name,
  sys_sem_wait(), that uses the sys_arch_sem_wait() function.
*/
u32_t sys_arch_sem_wait(sys_sem_t *sem, 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
    {
        /* convert msecond to os tick */
        if (timeout < (1000/RT_TICK_PER_SECOND))
            t = 1;
        else
            t = timeout / (1000/RT_TICK_PER_SECOND);
    }

    ret = rt_sem_take(*sem, t);

    if (ret == -RT_ETIMEOUT)
        return SYS_ARCH_TIMEOUT;
    else
    {
        if (ret == RT_EOK)
            ret = 1;
    }

    /* 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;
}

/*-----------------------------------------------------------------------------------*/
 //Signals a semaphore
void sys_sem_signal(sys_sem_t *sem)
{
    rt_sem_release(*sem);
}

/*-----------------------------------------------------------------------------------*/
// Deallocates a semaphore
void sys_sem_free(sys_sem_t *sem)
{
	RT_DEBUG_NOT_IN_INTERRUPT;
    rt_sem_delete(*sem);
}
/*-----------------------------------------------------------------------------------*/
int sys_sem_valid(sys_sem_t *sem)                                               
{
    if (*sem == SYS_SEM_NULL){
        return 0;
    }    
    else{
        return 1; 
    }                                
}

/*-----------------------------------------------------------------------------------*/                                                                                                                                                                
void sys_sem_set_invalid(sys_sem_t *sem)                                        
{                                                                               
  *sem = SYS_SEM_NULL;                                                          
} 

/*-----------------------------------------------------------------------------------*/
// Initialize sys arch
void sys_init(void)
{
    // keep track of how many threads have been created
    s_nextthread = 0;
}
/*-----------------------------------------------------------------------------------*/
                                      /* Mutexes*/
/*-----------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
#if LWIP_COMPAT_MUTEX == 0
/* Create a new mutex*/
err_t sys_mutex_new(sys_mutex_t *mutex) 
{
    *mutex = xSemaphoreCreateMutex();
    if(*mutex == NULL){
#if SYS_STATS
        ++lwip_stats.sys.mutex.err;
#endif /* SYS_STATS */
        return ERR_MEM;
    }

#if SYS_STATS
    ++lwip_stats.sys.mutex.used;
    if(lwip_stats.sys.mutex.max < lwip_stats.sys.mutex.used){
        lwip_stats.sys.mutex.max = lwip_stats.sys.mutex.used;
    }
#endif /* SYS_STATS */
    return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
/* Deallocate a mutex*/
void sys_mutex_free(sys_mutex_t *mutex)
{
#if SYS_STATS
    --lwip_stats.sys.mutex.used;
#endif /* SYS_STATS */
    vQueueDelete(*mutex);
}
/*-----------------------------------------------------------------------------------*/
/* Lock a mutex*/
void sys_mutex_lock(sys_mutex_t *mutex)
{
    sys_arch_sem_wait(*mutex, 0);
}

/*-----------------------------------------------------------------------------------*/
/* Unlock a mutex*/
void sys_mutex_unlock(sys_mutex_t *mutex)
{
    rt_sem_release(*mutex);
}
#endif /*LWIP_COMPAT_MUTEX*/
/*-----------------------------------------------------------------------------------*/
// TODO
/*-----------------------------------------------------------------------------------*/
/*
  Starts a new thread with priority "prio" that will begin its execution in the
  function "thread()". The "arg" argument will be passed as an argument to the
  thread() function. The id of the new thread is returned. Both the id and
  the priority are system dependent.
*/
sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread , void *arg, int stacksize, int prio)
{
    rt_thread_t t;

    RT_DEBUG_NOT_IN_INTERRUPT;

    /* create thread */
    t = rt_thread_create(name, thread, arg, stacksize, prio, 20);
    RT_ASSERT(t != RT_NULL);

    /* startup thread */
    rt_thread_startup(t);

    return t;
}

/*
  This optional function does a "fast" critical region protection and returns
  the previous protection level. This function is only called during very short
  critical regions. An embedded system which supports ISR-based drivers might
  want to implement this function by disabling interrupts. Task-based systems
  might want to implement this by using a mutex or disabling tasking. This
  function should support recursive calls from the same task or interrupt. In
  other words, sys_arch_protect() could be called while already protected. In
  that case the return value indicates that it is already protected.

  sys_arch_protect() is only required if your port is supporting an operating
  system.
*/
sys_prot_t sys_arch_protect(void)
{
    rt_base_t level;

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

    return level;
}

/*
  This optional function does a "fast" set of critical region protection to the
  value specified by pval. See the documentation for sys_arch_protect() for
  more information. This function is only required if your port is supporting
  an operating system.
*/
void sys_arch_unprotect(sys_prot_t pval)
{
    /* enable interrupt */
    rt_hw_interrupt_enable(pval);
}

/*
 * Prints an assertion messages and aborts execution.
 */
void sys_assert( const char *msg )
{
    ( void ) msg;
    /*FSL:only needed for debugging
    printf(msg);
    printf("\n\r");
    */
    rt_base_t level;

    /* disable interrupt */
    level = rt_hw_interrupt_disable();
	
    for(;;);
}
/*-----------------------------------------------------------------------------------*/
这两个文件复制到工程中然后编译过后,LWIP协议的移植基本也没什么问题了。
总结以下:
LWIP的移植最重要的一点就是信号量和邮箱接口的使用,如果遇到问题可以跟进以下代码,把关于邮箱和信号量的部分好好看看。
欢迎大家提问与指正,谢谢!
  • 11
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: gd32f450是一款基于ARM Cortex-M4内核的微控制器系列,它集成了lwIP(轻量级IP)协议栈lwIP是一个用于嵌入式系统的开源TCP/IP协议栈,它具有轻量级、模块化和可裁剪的特点,适用于资源受限的嵌入式设备。 gd32f450 lwip的集成,在嵌入式系统中提供了方便的网络通信功能。通过gd32f450系列微控制器的lwip协议栈,可以实现TCP/IP网络通信,包括IP地址分配、IP数据包传输、网络连接、Socket编程等。lwIP协议栈还支持常见的网络协议,如UDP、ARP、ICMP等,能够满足基本的网络通信需求。 使用gd32f450 lwip的好处是,它提供了一种简单、高效的网络通信解决方案。通过lwIP协议栈开发人员可以轻松地在gd32f450微控制器上实现网络通信功能,而无需编写底层的网络协议代码。这将大大加速开发过程,同时降低了开发成本。 此外,gd32f450系列微控制器具有丰富的外设资源,包括多个串行通信接口(如UART、I2C、SPI)、多个定时器和计数器、以太网MAC控制器等。这为网络通信提供了更多的选择和灵活性。gd32f450 lwip的集成,使得开发人员可以更加方便地利用这些外设,快速构建网络应用。 总而言之,gd32f450 lwip是一种强大的网络通信解决方案,它集成了lwIP协议栈,为嵌入式系统提供了简单、高效的网络通信功能。通过gd32f450 lwip开发人员可以轻松地实现TCP/IP网络通信,加速开发过程,降低开发成本。 ### 回答2: gd32f450 lwip是一种基于GD32F450系列微控制器的轻量级IP(Internet Protocol)网络协议栈。该协议栈可以与硬件平台进行结合,用于实现网络通信功能。lwip是一个开源的协议栈,它提供了TCP/IP协议以及其他网络协议的支持,可以方便地在嵌入式系统中实现网络通信。 gd32f450 lwip的主要特点是轻巧、高效、可靠。它具有占用资源少的特点,适用于资源有限的嵌入式系统。同时,它提供了高度可定制和可移植的特性,可以根据具体需求进行配置和移植gd32f450 lwip可以支持多个网络接口,包括以太网和Wi-Fi接口,可以实现网络连接和数据传输。 gd32f450 lwip提供了丰富的API接口,使得开发人员可以方便地进行网络编程。它支持多个应用层协议,包括HTTP、FTP、SNMP等,可以用于实现各种网络应用。 总之,gd32f450 lwip是一种适用于嵌入式系统的网络协议栈,能够方便地实现网络通信功能。它具有轻巧、高效、可靠的特点,并提供了丰富的API接口和应用层协议支持。它的优点和灵活性使得它成为嵌入式系统中网络通信的理想选择。 ### 回答3: gd32f450是一款微控制器芯片,它采用了lwip协议栈lwip(Lightweight IP)是一个轻量级的网络协议栈,专为嵌入式系统设计。gd32f450芯片集成了lwip协议栈,使其可以在嵌入式系统中实现网络通信。 gd32f450 lwip提供了一系列的网络协议,包括IP协议、TCP协议和UDP协议等。它可以通过以太网接口连接到网络,支持数据的传输和接收。使用lwip协议栈gd32f450可以实现TCP/IP通信,并支持基于IP地址的网络连接。 gd32f450 lwip还具有高度的灵活性和可扩展性,可以根据需要进行配置和定制。它支持多种网络通信协议,包括SNMP和DHCP等。gd32f450 lwip还提供了API接口,方便用户进行相关功能的开发和调试。 总之,gd32f450 lwip是一款功能强大的微控制器芯片,它集成了lwip协议栈,可以实现网络通信功能。它的高度灵活性和可扩展性使得它适用于各种嵌入式系统应用场景,如物联网设备、无线通信设备和工业自动化控制等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值