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的移植最重要的一点就是信号量和邮箱接口的使用,如果遇到问题可以跟进以下代码,把关于邮箱和信号量的部分好好看看。
欢迎大家提问与指正,谢谢!
版权声明:本文为CSDN博主「DayDayUP丶。」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_41867575/article/details/122106016
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的移植最重要的一点就是信号量和邮箱接口的使用,如果遇到问题可以跟进以下代码,把关于邮箱和信号量的部分好好看看。
欢迎大家提问与指正,谢谢!
版权声明:本文为CSDN博主「DayDayUP丶。」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_41867575/article/details/122106016
暂无评论