start to add lwip support
This commit is contained in:
Vendored
+126
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
#ifndef __CC_H__
|
||||
#define __CC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/** @ingroup NET_LWIP_ARCH
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Types based on stdint.h */
|
||||
typedef uint8_t u8_t;
|
||||
typedef int8_t s8_t;
|
||||
typedef uint16_t u16_t;
|
||||
typedef int16_t s16_t;
|
||||
typedef uint32_t u32_t;
|
||||
typedef int32_t s32_t;
|
||||
typedef uintptr_t mem_ptr_t;
|
||||
|
||||
/* Define (sn)printf formatters for these lwIP types */
|
||||
#define U16_F "hu"
|
||||
#define S16_F "hd"
|
||||
#define X16_F "hx"
|
||||
#define U32_F "lu"
|
||||
#define S32_F "ld"
|
||||
#define X32_F "lx"
|
||||
#define SZT_F "uz"
|
||||
|
||||
/* ARM/LPC17xx is little endian only */
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
|
||||
/* Use LWIP error codes */
|
||||
#define LWIP_PROVIDE_ERRNO
|
||||
|
||||
#if defined(__arm__) && defined(__ARMCC_VERSION)
|
||||
/* Keil uVision4 tools */
|
||||
#define PACK_STRUCT_BEGIN __packed
|
||||
#define PACK_STRUCT_STRUCT
|
||||
#define PACK_STRUCT_END
|
||||
#define PACK_STRUCT_FIELD(fld) fld
|
||||
#define ALIGNED(n) __align(n)
|
||||
#elif defined (__IAR_SYSTEMS_ICC__)
|
||||
/* IAR Embedded Workbench tools */
|
||||
#define PACK_STRUCT_BEGIN __packed
|
||||
#define PACK_STRUCT_STRUCT
|
||||
#define PACK_STRUCT_END
|
||||
#define PACK_STRUCT_FIELD(fld) fld
|
||||
// #define PACK_STRUCT_USE_INCLUDES
|
||||
#define ALIGNEDX(x) _Pragma(#x)
|
||||
#define ALIGNEDXX(x) ALIGNEDX(data_alignment=x)
|
||||
#define ALIGNED(x) ALIGNEDXX(x)
|
||||
#else
|
||||
/* GCC tools (CodeSourcery) */
|
||||
#define PACK_STRUCT_BEGIN
|
||||
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
|
||||
#define PACK_STRUCT_END
|
||||
#define PACK_STRUCT_FIELD(fld) fld
|
||||
#define ALIGNED(n) __attribute__((aligned (n)))
|
||||
// #define ALIGNED(n) __align(n)
|
||||
#endif
|
||||
|
||||
/* Used with IP headers only */
|
||||
#define LWIP_CHKSUM_ALGORITHM 1
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
/**
|
||||
* @brief Displays an error message on assertion
|
||||
* @param msg : Error message to display
|
||||
* @param line : Line number in file with error
|
||||
* @param file : Filename with error
|
||||
* @return Nothing
|
||||
* @note This function will display an error message on an assertion
|
||||
* to the debug output.
|
||||
*/
|
||||
void assert_printf(char *msg, int line, char *file);
|
||||
|
||||
/* Plaform specific diagnostic output */
|
||||
#define LWIP_PLATFORM_DIAG(vars) printf vars
|
||||
#define LWIP_PLATFORM_ASSERT(flag) { assert_printf((flag), __LINE__, __FILE__); }
|
||||
#else
|
||||
|
||||
/**
|
||||
* @brief LWIP optimized assertion loop (no LWIP_DEBUG)
|
||||
* @return DoesnNothing, function doesn't return
|
||||
*/
|
||||
void assert_loop(void);
|
||||
#define LWIP_PLATFORM_DIAG(msg) { ; }
|
||||
#define LWIP_PLATFORM_ASSERT(flag) { assert_loop(); }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* __CC_H__ */
|
||||
+882
@@ -0,0 +1,882 @@
|
||||
/*
|
||||
* @brief LPC17xx/40xx LWIP EMAC driver
|
||||
*
|
||||
* @note
|
||||
* Copyright(C) NXP Semiconductors, 2012
|
||||
* All rights reserved.
|
||||
*
|
||||
* @par
|
||||
* Software that is described herein is for illustrative purposes only
|
||||
* which provides customers with programming information regarding the
|
||||
* LPC products. This software is supplied "AS IS" without any warranties of
|
||||
* any kind, and NXP Semiconductors and its licensor disclaim any and
|
||||
* all warranties, express or implied, including all implied warranties of
|
||||
* merchantability, fitness for a particular purpose and non-infringement of
|
||||
* intellectual property rights. NXP Semiconductors assumes no responsibility
|
||||
* or liability for the use of the software, conveys no license or rights under any
|
||||
* patent, copyright, mask work right, or any other intellectual property rights in
|
||||
* or to any products. NXP Semiconductors reserves the right to make changes
|
||||
* in the software without notification. NXP Semiconductors also makes no
|
||||
* representation or warranty that such application will be suitable for the
|
||||
* specified use without further testing or modification.
|
||||
*
|
||||
* @par
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation is hereby granted, under NXP Semiconductors' and its
|
||||
* licensor's relevant copyrights in the software, without fee, provided that it
|
||||
* is used in conjunction with NXP Semiconductors microcontrollers. This
|
||||
* copyright, permission, and disclaimer notice must appear in all copies of
|
||||
* this code.
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "netif/ppp_oe.h"
|
||||
|
||||
#include "lpc_17xx40xx_emac_config.h"
|
||||
#include "lpc17xx_40xx_emac.h"
|
||||
|
||||
#include "chip.h"
|
||||
#include "board.h"
|
||||
#include "lpc_phy.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
extern void msDelay(uint32_t ms);
|
||||
|
||||
#if LPC_NUM_BUFF_TXDESCS < 2
|
||||
#error LPC_NUM_BUFF_TXDESCS must be at least 2
|
||||
#endif
|
||||
|
||||
#if LPC_NUM_BUFF_RXDESCS < 3
|
||||
#error LPC_NUM_BUFF_RXDESCS must be at least 3
|
||||
#endif
|
||||
|
||||
/** @ingroup NET_LWIP_LPC17XX40XX_EMAC_DRIVER
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
* Private types/enumerations/variables
|
||||
****************************************************************************/
|
||||
|
||||
#if NO_SYS == 0
|
||||
/**
|
||||
* @brief Driver transmit and receive thread priorities
|
||||
* Thread priorities for receive thread and TX cleanup thread. Alter
|
||||
* to prioritize receive or transmit bandwidth. In a heavily loaded
|
||||
* system or with LWIP_DEBUG enabled, the priorities might be better
|
||||
* the same. */
|
||||
#define tskRECPKT_PRIORITY (DEFAULT_THREAD_PRIO + 4)
|
||||
#define tskTXCLEAN_PRIORITY (DEFAULT_THREAD_PRIO + 5)
|
||||
// #define tskTXCLEAN_PRIORITY (TCPIP_THREAD_PRIO - 1) // FIXME
|
||||
// #define tskRECPKT_PRIORITY (TCPIP_THREAD_PRIO - 1) // FIXME
|
||||
#endif
|
||||
|
||||
/** @brief Debug output formatter lock define
|
||||
* When using FreeRTOS and with LWIP_DEBUG enabled, enabling this
|
||||
* define will allow RX debug messages to not interleave with the
|
||||
* TX messages (so they are actually readable). Not enabling this
|
||||
* define when the system is under load will cause the output to
|
||||
* be unreadable. There is a small tradeoff in performance for this
|
||||
* so use it only for debug. */
|
||||
// #define LOCK_RX_THREAD
|
||||
|
||||
#if NO_SYS == 0
|
||||
/** @brief Receive group interrupts
|
||||
*/
|
||||
#define RXINTGROUP (ENET_INT_RXOVERRUN | ENET_INT_RXERROR | ENET_INT_RXDONE)
|
||||
|
||||
/** @brief Transmit group interrupts
|
||||
*/
|
||||
#define TXINTGROUP (ENET_INT_TXUNDERRUN | ENET_INT_TXERROR | ENET_INT_TXDONE)
|
||||
#else
|
||||
#define RXINTGROUP 0
|
||||
#define TXINTGROUP 0
|
||||
#endif
|
||||
|
||||
/* LPC EMAC driver data structure */
|
||||
typedef struct {
|
||||
/* prxs must be 8 byte aligned! */
|
||||
ENET_RXSTAT_T prxs[LPC_NUM_BUFF_RXDESCS]; /**< Pointer to RX statuses */
|
||||
ENET_RXDESC_T prxd[LPC_NUM_BUFF_RXDESCS]; /**< Pointer to RX descriptor list */
|
||||
ENET_TXSTAT_T ptxs[LPC_NUM_BUFF_TXDESCS]; /**< Pointer to TX statuses */
|
||||
ENET_TXDESC_T ptxd[LPC_NUM_BUFF_TXDESCS]; /**< Pointer to TX descriptor list */
|
||||
struct netif *pnetif; /**< Reference back to LWIP parent netif */
|
||||
|
||||
struct pbuf *rxb[LPC_NUM_BUFF_RXDESCS]; /**< RX pbuf pointer list, zero-copy mode */
|
||||
|
||||
u32_t rx_fill_desc_index; /**< RX descriptor next available index */
|
||||
volatile u32_t rx_free_descs; /**< Count of free RX descriptors */
|
||||
struct pbuf *txb[LPC_NUM_BUFF_TXDESCS]; /**< TX pbuf pointer list, zero-copy mode */
|
||||
|
||||
u32_t lpc_last_tx_idx; /**< TX last descriptor index, zero-copy mode */
|
||||
#if NO_SYS == 0
|
||||
sys_sem_t rx_sem; /**< RX receive thread wakeup semaphore */
|
||||
sys_sem_t tx_clean_sem; /**< TX cleanup thread wakeup semaphore */
|
||||
sys_mutex_t tx_lock_mutex; /**< TX critical section mutex */
|
||||
sys_mutex_t rx_lock_mutex; /**< RX critical section mutex */
|
||||
xSemaphoreHandle xtx_count_sem; /**< TX free buffer counting semaphore */
|
||||
#endif
|
||||
} lpc_enetdata_t;
|
||||
|
||||
/** \brief LPC EMAC driver work data
|
||||
*/
|
||||
ALIGNED(8) lpc_enetdata_t lpc_enetdata;
|
||||
|
||||
/*****************************************************************************
|
||||
* Public types/enumerations/variables
|
||||
****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Private functions
|
||||
****************************************************************************/
|
||||
|
||||
/* Queues a pbuf into the RX descriptor list */
|
||||
STATIC void lpc_rxqueue_pbuf(lpc_enetdata_t *lpc_enetif, struct pbuf *p)
|
||||
{
|
||||
u32_t idx;
|
||||
|
||||
/* Get next free descriptor index */
|
||||
idx = lpc_enetif->rx_fill_desc_index;
|
||||
|
||||
/* Setup descriptor and clear statuses */
|
||||
lpc_enetif->prxd[idx].Control = ENET_RCTRL_INT | ((u32_t) ENET_RCTRL_SIZE(p->len));
|
||||
lpc_enetif->prxd[idx].Packet = (u32_t) p->payload;
|
||||
lpc_enetif->prxs[idx].StatusInfo = 0xFFFFFFFF;
|
||||
lpc_enetif->prxs[idx].StatusHashCRC = 0xFFFFFFFF;
|
||||
|
||||
/* Save pbuf pointer for push to network layer later */
|
||||
lpc_enetif->rxb[idx] = p;
|
||||
|
||||
/* Wrap at end of descriptor list */
|
||||
idx++;
|
||||
if (idx >= LPC_NUM_BUFF_RXDESCS) {
|
||||
idx = 0;
|
||||
}
|
||||
|
||||
/* Queue descriptor(s) */
|
||||
lpc_enetif->rx_free_descs -= 1;
|
||||
lpc_enetif->rx_fill_desc_index = idx;
|
||||
|
||||
LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
|
||||
("lpc_rxqueue_pbuf: pbuf packet queued: %p (free desc=%d)\n", p,
|
||||
lpc_enetif->rx_free_descs));
|
||||
}
|
||||
|
||||
/* Sets up the RX descriptor ring buffers. */
|
||||
STATIC err_t lpc_rx_setup(lpc_enetdata_t *lpc_enetif)
|
||||
{
|
||||
/* Setup pointers to RX structures */
|
||||
Chip_ENET_InitRxDescriptors(LPC_ETHERNET, lpc_enetif->prxd, lpc_enetif->prxs, LPC_NUM_BUFF_RXDESCS);
|
||||
|
||||
lpc_enetif->rx_free_descs = LPC_NUM_BUFF_RXDESCS;
|
||||
lpc_enetif->rx_fill_desc_index = 0;
|
||||
|
||||
/* Build RX buffer and descriptors */
|
||||
lpc_rx_queue(lpc_enetif->pnetif);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/* Allocates a pbuf and returns the data from the incoming packet */
|
||||
STATIC struct pbuf *lpc_low_level_input(struct netif *netif) {
|
||||
lpc_enetdata_t *lpc_enetif = netif->state;
|
||||
struct pbuf *p = NULL;
|
||||
u32_t idx, length;
|
||||
|
||||
#ifdef LOCK_RX_THREAD
|
||||
#if NO_SYS == 0
|
||||
/* Get exclusive access */
|
||||
sys_mutex_lock(&lpc_enetif->rx_lock_mutex);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Monitor RX overrun status. This should never happen unless
|
||||
(possibly) the internal bus is behing held up by something.
|
||||
Unless your system is running at a very low clock speed or
|
||||
there are possibilities that the internal buses may be held
|
||||
up for a long time, this can probably safely be removed. */
|
||||
if (Chip_ENET_GetIntStatus(LPC_ETHERNET) & ENET_INT_RXOVERRUN) {
|
||||
LINK_STATS_INC(link.err);
|
||||
LINK_STATS_INC(link.drop);
|
||||
|
||||
/* Temporarily disable RX */
|
||||
Chip_ENET_RXDisable(LPC_ETHERNET);
|
||||
|
||||
/* Reset the RX side */
|
||||
Chip_ENET_ResetRXLogic(LPC_ETHERNET);
|
||||
Chip_ENET_ClearIntStatus(LPC_ETHERNET, ENET_INT_RXOVERRUN);
|
||||
|
||||
/* De-allocate all queued RX pbufs */
|
||||
for (idx = 0; idx < LPC_NUM_BUFF_RXDESCS; idx++) {
|
||||
if (lpc_enetif->rxb[idx] != NULL) {
|
||||
pbuf_free(lpc_enetif->rxb[idx]);
|
||||
lpc_enetif->rxb[idx] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Start RX side again */
|
||||
lpc_rx_setup(lpc_enetif);
|
||||
|
||||
/* Re-enable RX */
|
||||
Chip_ENET_RXEnable(LPC_ETHERNET);
|
||||
|
||||
#ifdef LOCK_RX_THREAD
|
||||
#if NO_SYS == 0
|
||||
sys_mutex_unlock(&lpc_enetif->rx_lock_mutex);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Determine if a frame has been received */
|
||||
length = 0;
|
||||
idx = Chip_ENET_GetRXConsumeIndex(LPC_ETHERNET);
|
||||
if (!Chip_ENET_IsRxEmpty(LPC_ETHERNET)) {
|
||||
/* Handle errors */
|
||||
if (lpc_enetif->prxs[idx].StatusInfo & (ENET_RINFO_CRC_ERR |
|
||||
ENET_RINFO_SYM_ERR | ENET_RINFO_ALIGN_ERR | ENET_RINFO_LEN_ERR)) {
|
||||
#if LINK_STATS
|
||||
if (lpc_enetif->prxs[idx].StatusInfo & (ENET_RINFO_CRC_ERR |
|
||||
ENET_RINFO_SYM_ERR | ENET_RINFO_ALIGN_ERR)) {
|
||||
LINK_STATS_INC(link.chkerr);
|
||||
}
|
||||
if (lpc_enetif->prxs[idx].StatusInfo & ENET_RINFO_LEN_ERR) {
|
||||
LINK_STATS_INC(link.lenerr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Drop the frame */
|
||||
LINK_STATS_INC(link.drop);
|
||||
|
||||
/* Re-queue the pbuf for receive */
|
||||
lpc_enetif->rx_free_descs++;
|
||||
p = lpc_enetif->rxb[idx];
|
||||
lpc_enetif->rxb[idx] = NULL;
|
||||
lpc_rxqueue_pbuf(lpc_enetif, p);
|
||||
|
||||
LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
|
||||
("lpc_low_level_input: Packet dropped with errors (0x%x)\n",
|
||||
lpc_enetif->prxs[idx].StatusInfo));
|
||||
|
||||
p = NULL;
|
||||
}
|
||||
else {
|
||||
/* A packet is waiting, get length */
|
||||
length = ENET_RINFO_SIZE(lpc_enetif->prxs[idx].StatusInfo) - 4; /* Remove FCS */
|
||||
|
||||
/* Zero-copy */
|
||||
p = lpc_enetif->rxb[idx];
|
||||
p->len = (u16_t) length;
|
||||
|
||||
/* Free pbuf from desriptor */
|
||||
lpc_enetif->rxb[idx] = NULL;
|
||||
lpc_enetif->rx_free_descs++;
|
||||
|
||||
/* Queue new buffer(s) */
|
||||
if (lpc_rx_queue(lpc_enetif->pnetif) == 0) {
|
||||
|
||||
/* Re-queue the pbuf for receive */
|
||||
lpc_rxqueue_pbuf(lpc_enetif, p);
|
||||
|
||||
/* Drop the frame */
|
||||
LINK_STATS_INC(link.drop);
|
||||
|
||||
LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
|
||||
("lpc_low_level_input: Packet dropped since it could not allocate Rx Buffer\n"));
|
||||
|
||||
p = NULL;
|
||||
}
|
||||
else {
|
||||
|
||||
LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
|
||||
("lpc_low_level_input: Packet received: %p, size %d (index=%d)\n",
|
||||
p, length, idx));
|
||||
|
||||
/* Save size */
|
||||
p->tot_len = (u16_t) length;
|
||||
LINK_STATS_INC(link.recv);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update Consume index */
|
||||
Chip_ENET_IncRXConsumeIndex(LPC_ETHERNET);
|
||||
}
|
||||
|
||||
#ifdef LOCK_RX_THREAD
|
||||
#if NO_SYS == 0
|
||||
sys_mutex_unlock(&lpc_enetif->rx_lock_mutex);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Determine if the passed address is usable for the ethernet DMA controller */
|
||||
STATIC s32_t lpc_packet_addr_notsafe(void *addr) {
|
||||
#if defined(CHIP_LPC175X_6X)
|
||||
/* Check for legal address ranges */
|
||||
if ((((u32_t) addr >= 0x10000000) && ((u32_t) addr < 0x10008000)) /* 32kB local SRAM */
|
||||
|| (((u32_t) addr >= 0x1FFF0000) && ((u32_t) addr < 0x1FFF2000)) /* 8kB ROM */
|
||||
|| (((u32_t) addr >= 0x2007C000) && ((u32_t) addr < 0x20084000)) /* 32kB AHB SRAM */
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
#else
|
||||
/* Check for legal address ranges */
|
||||
if ((((u32_t) addr >= 0x20000000) && ((u32_t) addr < 0x20008000)) ||
|
||||
(((u32_t) addr >= 0x80000000) && ((u32_t) addr < 0xF0000000))) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Sets up the TX descriptor ring buffers */
|
||||
STATIC err_t lpc_tx_setup(lpc_enetdata_t *lpc_enetif)
|
||||
{
|
||||
s32_t idx;
|
||||
|
||||
/* Build TX descriptors for local buffers */
|
||||
for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) {
|
||||
lpc_enetif->ptxd[idx].Control = 0;
|
||||
lpc_enetif->ptxs[idx].StatusInfo = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
/* Setup pointers to TX structures */
|
||||
Chip_ENET_InitTxDescriptors(LPC_ETHERNET, lpc_enetif->ptxd, lpc_enetif->ptxs, LPC_NUM_BUFF_TXDESCS);
|
||||
|
||||
lpc_enetif->lpc_last_tx_idx = 0;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/* Free TX buffers that are complete */
|
||||
STATIC void lpc_tx_reclaim_st(lpc_enetdata_t *lpc_enetif, u32_t cidx)
|
||||
{
|
||||
#if NO_SYS == 0
|
||||
/* Get exclusive access */
|
||||
sys_mutex_lock(&lpc_enetif->tx_lock_mutex);
|
||||
#endif
|
||||
|
||||
while (cidx != lpc_enetif->lpc_last_tx_idx) {
|
||||
if (lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx] != NULL) {
|
||||
LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
|
||||
("lpc_tx_reclaim_st: Freeing packet %p (index %d)\n",
|
||||
lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx],
|
||||
lpc_enetif->lpc_last_tx_idx));
|
||||
pbuf_free(lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx]);
|
||||
lpc_enetif->txb[lpc_enetif->lpc_last_tx_idx] = NULL;
|
||||
}
|
||||
|
||||
#if NO_SYS == 0
|
||||
xSemaphoreGive(lpc_enetif->xtx_count_sem);
|
||||
#endif
|
||||
lpc_enetif->lpc_last_tx_idx++;
|
||||
if (lpc_enetif->lpc_last_tx_idx >= LPC_NUM_BUFF_TXDESCS) {
|
||||
lpc_enetif->lpc_last_tx_idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if NO_SYS == 0
|
||||
/* Restore access */
|
||||
sys_mutex_unlock(&lpc_enetif->tx_lock_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Low level output of a packet. Never call this from an interrupt context,
|
||||
* as it may block until TX descriptors become available. */
|
||||
STATIC err_t lpc_low_level_output(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
lpc_enetdata_t *lpc_enetif = netif->state;
|
||||
struct pbuf *q;
|
||||
|
||||
#if LPC_TX_PBUF_BOUNCE_EN == 1
|
||||
u8_t *dst;
|
||||
struct pbuf *np;
|
||||
#endif
|
||||
u32_t idx;
|
||||
u32_t dn, notdmasafe = 0;
|
||||
|
||||
/* Zero-copy TX buffers may be fragmented across mutliple payload
|
||||
chains. Determine the number of descriptors needed for the
|
||||
transfer. The pbuf chaining can be a mess! */
|
||||
dn = (u32_t) pbuf_clen(p);
|
||||
|
||||
/* Test to make sure packet addresses are DMA safe. A DMA safe
|
||||
address is once that uses external memory or periphheral RAM.
|
||||
IRAM and FLASH are not safe! */
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
notdmasafe += lpc_packet_addr_notsafe(q->payload);
|
||||
}
|
||||
|
||||
#if LPC_TX_PBUF_BOUNCE_EN == 1
|
||||
/* If the pbuf is not DMA safe, a new bounce buffer (pbuf) will be
|
||||
created that will be used instead. This requires an copy from the
|
||||
non-safe DMA region to the new pbuf */
|
||||
if (notdmasafe) {
|
||||
/* Allocate a pbuf in DMA memory */
|
||||
np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
|
||||
if (np == NULL) {
|
||||
LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
|
||||
("lpc_low_level_output: could not allocate TX pbuf\n"));
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
/* This buffer better be contiguous! */
|
||||
LWIP_ASSERT("lpc_low_level_output: New transmit pbuf is chained",
|
||||
(pbuf_clen(np) == 1));
|
||||
|
||||
/* Copy to DMA safe pbuf */
|
||||
dst = (u8_t *) np->payload;
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
/* Copy the buffer to the descriptor's buffer */
|
||||
MEMCPY(dst, (u8_t *) q->payload, q->len);
|
||||
dst += q->len;
|
||||
}
|
||||
np->len = p->tot_len;
|
||||
|
||||
LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
|
||||
("lpc_low_level_output: Switched to DMA safe buffer, old=%p, new=%p\n",
|
||||
q, np));
|
||||
|
||||
/* use the new buffer for descrptor queueing. The original pbuf will
|
||||
be de-allocated outsuide this driver. */
|
||||
p = np;
|
||||
dn = 1;
|
||||
}
|
||||
#else
|
||||
if (notdmasafe) {
|
||||
LWIP_ASSERT("lpc_low_level_output: Not a DMA safe pbuf",
|
||||
(notdmasafe == 0));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Wait until enough descriptors are available for the transfer. */
|
||||
/* THIS WILL BLOCK UNTIL THERE ARE ENOUGH DESCRIPTORS AVAILABLE */
|
||||
while (dn > lpc_tx_ready(netif)) {
|
||||
#if NO_SYS == 0
|
||||
xSemaphoreTake(lpc_enetif->xtx_count_sem, 0);
|
||||
#else
|
||||
msDelay(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Get free TX buffer index */
|
||||
idx = Chip_ENET_GetTXProduceIndex(LPC_ETHERNET);
|
||||
|
||||
#if NO_SYS == 0
|
||||
/* Get exclusive access */
|
||||
sys_mutex_lock(&lpc_enetif->tx_lock_mutex);
|
||||
#endif
|
||||
|
||||
/* Prevent LWIP from de-allocating this pbuf. The driver will
|
||||
free it once it's been transmitted. */
|
||||
if (!notdmasafe) {
|
||||
pbuf_ref(p);
|
||||
}
|
||||
|
||||
/* Setup transfers */
|
||||
q = p;
|
||||
while (dn > 0) {
|
||||
dn--;
|
||||
|
||||
/* Only save pointer to free on last descriptor */
|
||||
if (dn == 0) {
|
||||
/* Save size of packet and signal it's ready */
|
||||
lpc_enetif->ptxd[idx].Control = ENET_TCTRL_SIZE(q->len) | ENET_TCTRL_INT |
|
||||
ENET_TCTRL_LAST;
|
||||
lpc_enetif->txb[idx] = p;
|
||||
}
|
||||
else {
|
||||
/* Save size of packet, descriptor is not last */
|
||||
lpc_enetif->ptxd[idx].Control = ENET_TCTRL_SIZE(q->len) | ENET_TCTRL_INT;
|
||||
lpc_enetif->txb[idx] = NULL;
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
|
||||
("lpc_low_level_output: pbuf packet(%p) sent, chain#=%d,"
|
||||
" size = %d (index=%d)\n", q->payload, dn, q->len, idx));
|
||||
|
||||
lpc_enetif->ptxd[idx].Packet = (u32_t) q->payload;
|
||||
|
||||
q = q->next;
|
||||
|
||||
idx = Chip_ENET_IncTXProduceIndex(LPC_ETHERNET);
|
||||
}
|
||||
|
||||
LINK_STATS_INC(link.xmit);
|
||||
|
||||
#if NO_SYS == 0
|
||||
/* Restore access */
|
||||
sys_mutex_unlock(&lpc_enetif->tx_lock_mutex);
|
||||
#endif
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#if NO_SYS == 0
|
||||
/* Packet reception task for FreeRTOS */
|
||||
STATIC portTASK_FUNCTION(vPacketReceiveTask, pvParameters)
|
||||
{
|
||||
lpc_enetdata_t *lpc_enetif = pvParameters;
|
||||
|
||||
while (1) {
|
||||
/* Wait for receive task to wakeup */
|
||||
sys_arch_sem_wait(&lpc_enetif->rx_sem, 0);
|
||||
|
||||
/* Process packets until all empty */
|
||||
while (!Chip_ENET_IsRxEmpty(LPC_ETHERNET)) {
|
||||
lpc_enetif_input(lpc_enetif->pnetif);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Transmit cleanup task for FreeRTOS */
|
||||
STATIC portTASK_FUNCTION(vTransmitCleanupTask, pvParameters)
|
||||
{
|
||||
lpc_enetdata_t *lpc_enetif = pvParameters;
|
||||
s32_t idx;
|
||||
|
||||
while (1) {
|
||||
/* Wait for transmit cleanup task to wakeup */
|
||||
sys_arch_sem_wait(&lpc_enetif->tx_clean_sem, 0);
|
||||
|
||||
/* Error handling for TX underruns. This should never happen unless
|
||||
something is holding the bus or the clocks are going too slow. It
|
||||
can probably be safely removed. */
|
||||
if (Chip_ENET_GetIntStatus(LPC_ETHERNET) & ENET_INT_TXUNDERRUN) {
|
||||
LINK_STATS_INC(link.err);
|
||||
LINK_STATS_INC(link.drop);
|
||||
|
||||
#if NO_SYS == 0
|
||||
/* Get exclusive access */
|
||||
sys_mutex_lock(&lpc_enetif->tx_lock_mutex);
|
||||
#endif
|
||||
/* Reset the TX side */
|
||||
Chip_ENET_ResetTXLogic(LPC_ETHERNET);
|
||||
Chip_ENET_ClearIntStatus(LPC_ETHERNET, ENET_INT_TXUNDERRUN);
|
||||
|
||||
/* De-allocate all queued TX pbufs */
|
||||
for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) {
|
||||
if (lpc_enetif->txb[idx] != NULL) {
|
||||
pbuf_free(lpc_enetif->txb[idx]);
|
||||
lpc_enetif->txb[idx] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if NO_SYS == 0
|
||||
/* Restore access */
|
||||
sys_mutex_unlock(&lpc_enetif->tx_lock_mutex);
|
||||
#endif
|
||||
/* Start TX side again */
|
||||
lpc_tx_setup(lpc_enetif);
|
||||
}
|
||||
else {
|
||||
/* Free TX buffers that are done sending */
|
||||
lpc_tx_reclaim(lpc_enetdata.pnetif);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Low level init of the MAC and PHY */
|
||||
STATIC err_t low_level_init(struct netif *netif)
|
||||
{
|
||||
lpc_enetdata_t *lpc_enetif = netif->state;
|
||||
err_t err = ERR_OK;
|
||||
|
||||
Chip_ENET_Init(LPC_ETHERNET);
|
||||
|
||||
/* Initialize the PHY */
|
||||
Chip_ENET_SetupMII(LPC_ETHERNET, Chip_ENET_FindMIIDiv(LPC_ETHERNET, 2500000), LPC_PHYDEF_PHYADDR);
|
||||
#if defined(USE_RMII)
|
||||
if (lpc_phy_init(true, msDelay) != SUCCESS) {
|
||||
return ERROR;
|
||||
}
|
||||
#else
|
||||
if (lpc_phy_init(false, msDelay) != SUCCESS) {
|
||||
return ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Save station address */
|
||||
Chip_ENET_SetADDR(LPC_ETHERNET, netif->hwaddr);
|
||||
|
||||
/* Setup transmit and receive descriptors */
|
||||
if (lpc_tx_setup(lpc_enetif) != ERR_OK) {
|
||||
return ERR_BUF;
|
||||
}
|
||||
if (lpc_rx_setup(lpc_enetif) != ERR_OK) {
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
/* Enable packet reception */
|
||||
#if IP_SOF_BROADCAST_RECV
|
||||
Chip_ENET_EnableRXFilter(LPC_ETHERNET, ENET_RXFILTERCTRL_APE | ENET_RXFILTERCTRL_ABE);
|
||||
#else
|
||||
Chip_ENET_EnableRXFilter(ENET_RXFILTERCTRL_APE);
|
||||
#endif
|
||||
|
||||
/* Clear and enable rx/tx interrupts */
|
||||
Chip_ENET_EnableInt(LPC_ETHERNET, RXINTGROUP | TXINTGROUP);
|
||||
|
||||
/* Enable RX and TX */
|
||||
Chip_ENET_TXEnable(LPC_ETHERNET);
|
||||
Chip_ENET_RXEnable(LPC_ETHERNET);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* This function is the ethernet packet send function. It calls
|
||||
* etharp_output after checking link status. */
|
||||
STATIC err_t lpc_etharp_output(struct netif *netif, struct pbuf *q,
|
||||
ip_addr_t *ipaddr)
|
||||
{
|
||||
/* Only send packet is link is up */
|
||||
if (netif->flags & NETIF_FLAG_LINK_UP) {
|
||||
return etharp_output(netif, q, ipaddr);
|
||||
}
|
||||
|
||||
return ERR_CONN;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Public functions
|
||||
****************************************************************************/
|
||||
/* Attempt to allocate and requeue a new pbuf for RX */
|
||||
s32_t lpc_rx_queue(struct netif *netif)
|
||||
{
|
||||
lpc_enetdata_t *lpc_enetif = netif->state;
|
||||
struct pbuf *p;
|
||||
|
||||
s32_t queued = 0;
|
||||
|
||||
/* Attempt to requeue as many packets as possible */
|
||||
while (lpc_enetif->rx_free_descs > 0) {
|
||||
/* Allocate a pbuf from the pool. We need to allocate at the
|
||||
maximum size as we don't know the size of the yet to be
|
||||
received packet. */
|
||||
p = pbuf_alloc(PBUF_RAW, (u16_t) ENET_ETH_MAX_FLEN, PBUF_RAM);
|
||||
if (p == NULL) {
|
||||
LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
|
||||
("lpc_rx_queue: could not allocate RX pbuf (free desc=%d)\n",
|
||||
lpc_enetif->rx_free_descs));
|
||||
return queued;
|
||||
}
|
||||
|
||||
/* pbufs allocated from the RAM pool should be non-chained. */
|
||||
LWIP_ASSERT("lpc_rx_queue: pbuf is not contiguous (chained)",
|
||||
pbuf_clen(p) <= 1);
|
||||
|
||||
/* Queue packet */
|
||||
lpc_rxqueue_pbuf(lpc_enetif, p);
|
||||
|
||||
/* Update queued count */
|
||||
queued++;
|
||||
}
|
||||
|
||||
return queued;
|
||||
}
|
||||
|
||||
/* Attempt to read a packet from the EMAC interface */
|
||||
void lpc_enetif_input(struct netif *netif)
|
||||
{
|
||||
struct eth_hdr *ethhdr;
|
||||
|
||||
struct pbuf *p;
|
||||
|
||||
/* move received packet into a new pbuf */
|
||||
p = lpc_low_level_input(netif);
|
||||
if (p == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* points to packet payload, which starts with an Ethernet header */
|
||||
ethhdr = p->payload;
|
||||
|
||||
switch (htons(ethhdr->type)) {
|
||||
case ETHTYPE_IP:
|
||||
case ETHTYPE_ARP:
|
||||
#if PPPOE_SUPPORT
|
||||
case ETHTYPE_PPPOEDISC:
|
||||
case ETHTYPE_PPPOE:
|
||||
#endif /* PPPOE_SUPPORT */
|
||||
/* full packet send to tcpip_thread to process */
|
||||
if (netif->input(p, netif) != ERR_OK) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("lpc_enetif_input: IP input error\n"));
|
||||
/* Free buffer */
|
||||
pbuf_free(p);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Return buffer */
|
||||
pbuf_free(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call for freeing TX buffers that are complete */
|
||||
void lpc_tx_reclaim(struct netif *netif)
|
||||
{
|
||||
lpc_tx_reclaim_st((lpc_enetdata_t *) netif->state,
|
||||
Chip_ENET_GetTXConsumeIndex(LPC_ETHERNET));
|
||||
}
|
||||
|
||||
/* Polls if an available TX descriptor is ready */
|
||||
s32_t lpc_tx_ready(struct netif *netif)
|
||||
{
|
||||
u32_t pidx, cidx;
|
||||
|
||||
cidx = Chip_ENET_GetTXConsumeIndex(LPC_ETHERNET);
|
||||
pidx = Chip_ENET_GetTXProduceIndex(LPC_ETHERNET);
|
||||
|
||||
return Chip_ENET_GetFreeDescNum(LPC_ETHERNET, pidx, cidx, LPC_NUM_BUFF_TXDESCS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief EMAC interrupt handler
|
||||
* @return Nothing
|
||||
* @note This function handles the transmit, receive, and error interrupt of
|
||||
* the LPC17xx/40xx. This is meant to be used when NO_SYS=0.
|
||||
*/
|
||||
void ETH_IRQHandler(void)
|
||||
{
|
||||
#if NO_SYS == 1
|
||||
/* Interrupts are not used without an RTOS */
|
||||
NVIC_DisableIRQ(ETHERNET_IRQn);
|
||||
#else
|
||||
signed portBASE_TYPE xRecTaskWoken = pdFALSE, XTXTaskWoken = pdFALSE;
|
||||
uint32_t ints;
|
||||
|
||||
/* Interrupts are of 2 groups - transmit or receive. Based on the
|
||||
interrupt, kick off the receive or transmit (cleanup) task */
|
||||
|
||||
/* Get pending interrupts */
|
||||
ints = Chip_ENET_GetIntStatus(LPC_ETHERNET);
|
||||
|
||||
if (ints & RXINTGROUP) {
|
||||
/* RX group interrupt(s) */
|
||||
/* Give semaphore to wakeup RX receive task. Note the FreeRTOS
|
||||
method is used instead of the LWIP arch method. */
|
||||
xSemaphoreGiveFromISR(lpc_enetdata.rx_sem, &xRecTaskWoken);
|
||||
}
|
||||
|
||||
if (ints & TXINTGROUP) {
|
||||
/* TX group interrupt(s) */
|
||||
/* Give semaphore to wakeup TX cleanup task. Note the FreeRTOS
|
||||
method is used instead of the LWIP arch method. */
|
||||
xSemaphoreGiveFromISR(lpc_enetdata.tx_clean_sem, &XTXTaskWoken);
|
||||
}
|
||||
|
||||
/* Clear pending interrupts */
|
||||
Chip_ENET_ClearIntStatus(LPC_ETHERNET, ints);
|
||||
|
||||
/* Context switch needed? */
|
||||
portEND_SWITCHING_ISR(xRecTaskWoken || XTXTaskWoken);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Set up the MAC interface duplex */
|
||||
void lpc_emac_set_duplex(int full_duplex)
|
||||
{
|
||||
if (full_duplex) {
|
||||
Chip_ENET_SetFullDuplex(LPC_ETHERNET);
|
||||
}
|
||||
else {
|
||||
Chip_ENET_SetHalfDuplex(LPC_ETHERNET);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up the MAC interface speed */
|
||||
void lpc_emac_set_speed(int mbs_100)
|
||||
{
|
||||
if (mbs_100) {
|
||||
Chip_ENET_Set100Mbps(LPC_ETHERNET);
|
||||
}
|
||||
else {
|
||||
Chip_ENET_Set10Mbps(LPC_ETHERNET);
|
||||
}
|
||||
}
|
||||
|
||||
/* LWIP 17xx/40xx EMAC initialization function */
|
||||
err_t lpc_enetif_init(struct netif *netif)
|
||||
{
|
||||
err_t err;
|
||||
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
|
||||
lpc_enetdata.pnetif = netif;
|
||||
|
||||
/* set MAC hardware address */
|
||||
Board_ENET_GetMacADDR(netif->hwaddr);
|
||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
||||
|
||||
/* maximum transfer unit */
|
||||
netif->mtu = 1500;
|
||||
|
||||
/* device capabilities */
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_UP |
|
||||
NETIF_FLAG_ETHERNET;
|
||||
|
||||
/* Initialize the hardware */
|
||||
netif->state = &lpc_enetdata;
|
||||
err = low_level_init(netif);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
/* Initialize interface hostname */
|
||||
netif->hostname = "lwiplpc";
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
netif->name[0] = 'e';
|
||||
netif->name[1] = 'n';
|
||||
|
||||
netif->output = lpc_etharp_output;
|
||||
netif->linkoutput = lpc_low_level_output;
|
||||
|
||||
/* For FreeRTOS, start tasks */
|
||||
#if NO_SYS == 0
|
||||
lpc_enetdata.xtx_count_sem = xSemaphoreCreateCounting(LPC_NUM_BUFF_TXDESCS,
|
||||
LPC_NUM_BUFF_TXDESCS);
|
||||
LWIP_ASSERT("xtx_count_sem creation error",
|
||||
(lpc_enetdata.xtx_count_sem != NULL));
|
||||
|
||||
err = sys_mutex_new(&lpc_enetdata.tx_lock_mutex);
|
||||
LWIP_ASSERT("tx_lock_mutex creation error", (err == ERR_OK));
|
||||
|
||||
err = sys_mutex_new(&lpc_enetdata.rx_lock_mutex);
|
||||
LWIP_ASSERT("rx_lock_mutex creation error", (err == ERR_OK));
|
||||
|
||||
/* Packet receive task */
|
||||
err = sys_sem_new(&lpc_enetdata.rx_sem, 0);
|
||||
LWIP_ASSERT("rx_sem creation error", (err == ERR_OK));
|
||||
sys_thread_new("receive_thread", vPacketReceiveTask, netif->state,
|
||||
DEFAULT_THREAD_STACKSIZE, tskRECPKT_PRIORITY);
|
||||
|
||||
/* Transmit cleanup task */
|
||||
err = sys_sem_new(&lpc_enetdata.tx_clean_sem, 0);
|
||||
LWIP_ASSERT("tx_clean_sem creation error", (err == ERR_OK));
|
||||
sys_thread_new("txclean_thread", vTransmitCleanupTask, netif->state,
|
||||
DEFAULT_THREAD_STACKSIZE, tskTXCLEAN_PRIORITY);
|
||||
#endif
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* @brief LPC17xx/40xx LWIP EMAC driver
|
||||
*
|
||||
* @note
|
||||
* Copyright(C) NXP Semiconductors, 2012
|
||||
* All rights reserved.
|
||||
*
|
||||
* @par
|
||||
* Software that is described herein is for illustrative purposes only
|
||||
* which provides customers with programming information regarding the
|
||||
* LPC products. This software is supplied "AS IS" without any warranties of
|
||||
* any kind, and NXP Semiconductors and its licensor disclaim any and
|
||||
* all warranties, express or implied, including all implied warranties of
|
||||
* merchantability, fitness for a particular purpose and non-infringement of
|
||||
* intellectual property rights. NXP Semiconductors assumes no responsibility
|
||||
* or liability for the use of the software, conveys no license or rights under any
|
||||
* patent, copyright, mask work right, or any other intellectual property rights in
|
||||
* or to any products. NXP Semiconductors reserves the right to make changes
|
||||
* in the software without notification. NXP Semiconductors also makes no
|
||||
* representation or warranty that such application will be suitable for the
|
||||
* specified use without further testing or modification.
|
||||
*
|
||||
* @par
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation is hereby granted, under NXP Semiconductors' and its
|
||||
* licensor's relevant copyrights in the software, without fee, provided that it
|
||||
* is used in conjunction with NXP Semiconductors microcontrollers. This
|
||||
* copyright, permission, and disclaimer notice must appear in all copies of
|
||||
* this code.
|
||||
*/
|
||||
|
||||
#ifndef __LPC17XX_40XX_EMAC_H_
|
||||
#define __LPC17XX_40XX_EMAC_H_
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/** @defgroup NET_LWIP_LPC17XX40XX_EMAC_DRIVER 17xx/40xx EMAC driver for LWIP
|
||||
* @ingroup NET_LWIP
|
||||
* @note This is the LPC17xx/40xx EMAC driver for LWIP. This driver supports both
|
||||
* RTOS-based and no-RTOS operation with LWIP. WHen using an RTOS, several
|
||||
* threads will be created for handling RX and TX packet fucntions.
|
||||
*
|
||||
* Note that some LWIP examples may not necessarily use all the provided
|
||||
* LWIP driver functions or may contain overriden versions of the functions.
|
||||
* (For example, PHY drives may have their own implementation of the MII
|
||||
* read/write functions).
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Attempt to read a packet from the EMAC interface
|
||||
* @param netif : lwip network interface structure pointer
|
||||
* @return Nothing
|
||||
*/
|
||||
void lpc_enetif_input(struct netif *netif);
|
||||
|
||||
/**
|
||||
* @brief Attempt to allocate and requeue a new pbuf for RX
|
||||
* @param netif : lwip network interface structure pointer
|
||||
* @return The number of new descriptors queued
|
||||
*/
|
||||
s32_t lpc_rx_queue(struct netif *netif);
|
||||
|
||||
/**
|
||||
* @brief Polls if an available TX descriptor is ready
|
||||
* @param netif : lwip network interface structure pointer
|
||||
* @return 0 if no descriptors are read, or >0
|
||||
* @note Can be used to determine if the low level transmit function will block
|
||||
*/
|
||||
s32_t lpc_tx_ready(struct netif *netif);
|
||||
|
||||
/**
|
||||
* @brief Call for freeing TX buffers that are complete
|
||||
* @param netif : lwip network interface structure pointer
|
||||
* @return Nothing
|
||||
*/
|
||||
void lpc_tx_reclaim(struct netif *netif);
|
||||
|
||||
/**
|
||||
* @brief LWIP 17xx/40xx EMAC initialization function
|
||||
* @param netif : lwip network interface structure pointer
|
||||
* @return ERR_OK if the loopif is initialized, or ERR_* on other errors
|
||||
* @note Should be called at the beginning of the program to set up the
|
||||
* network interface. This function should be passed as a parameter to
|
||||
* netif_add().
|
||||
*/
|
||||
err_t lpc_enetif_init(struct netif *netif);
|
||||
|
||||
/**
|
||||
* @brief Set up the MAC interface duplex
|
||||
* @param full_duplex : 0 = half duplex, 1 = full duplex
|
||||
* @return Nothing
|
||||
* @note This function provides a method for the PHY to setup the EMAC
|
||||
* for the PHY negotiated duplex mode.
|
||||
*/
|
||||
void lpc_emac_set_duplex(int full_duplex);
|
||||
|
||||
/**
|
||||
* @brief Set up the MAC interface speed
|
||||
* @param mbs_100 : 0 = 10mbs mode, 1 = 100mbs mode
|
||||
* @return Nothing
|
||||
* @note This function provides a method for the PHY to setup the EMAC
|
||||
* for the PHY negotiated bit rate.
|
||||
*/
|
||||
void lpc_emac_set_speed(int mbs_100);
|
||||
|
||||
/**
|
||||
* @brief Millisecond Delay function
|
||||
* @param ms : Milliseconds to wait
|
||||
* @return None
|
||||
*/
|
||||
extern void msDelay(uint32_t ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* __LPC17XX_40XX_EMAC_H_ */
|
||||
@@ -0,0 +1,142 @@
|
||||
/**********************************************************************
|
||||
* @brief Setups up the LWIP timebase (tick)
|
||||
*
|
||||
* @note
|
||||
* Copyright(C) NXP Semiconductors, 2012
|
||||
* All rights reserved.
|
||||
*
|
||||
* @par
|
||||
* Software that is described herein is for illustrative purposes only
|
||||
* which provides customers with programming information regarding the
|
||||
* LPC products. This software is supplied "AS IS" without any warranties of
|
||||
* any kind, and NXP Semiconductors and its licensor disclaim any and
|
||||
* all warranties, express or implied, including all implied warranties of
|
||||
* merchantability, fitness for a particular purpose and non-infringement of
|
||||
* intellectual property rights. NXP Semiconductors assumes no responsibility
|
||||
* or liability for the use of the software, conveys no license or rights under any
|
||||
* patent, copyright, mask work right, or any other intellectual property rights in
|
||||
* or to any products. NXP Semiconductors reserves the right to make changes
|
||||
* in the software without notification. NXP Semiconductors also makes no
|
||||
* representation or warranty that such application will be suitable for the
|
||||
* specified use without further testing or modification.
|
||||
*
|
||||
* @par
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation is hereby granted, under NXP Semiconductors' and its
|
||||
* licensor's relevant copyrights in the software, without fee, provided that it
|
||||
* is used in conjunction with NXP Semiconductors microcontrollers. This
|
||||
* copyright, permission, and disclaimer notice must appear in all copies of
|
||||
* this code.
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if NO_SYS == 1
|
||||
|
||||
#include "chip.h"
|
||||
#include "lpc_arch.h"
|
||||
|
||||
/** @ingroup NET_LWIP_ARCH
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
* Private types/enumerations/variables
|
||||
****************************************************************************/
|
||||
|
||||
/* Saved reference period foe standalone mode */
|
||||
static uint32_t saved_period;
|
||||
|
||||
/* Saved total time in mS since timer was enabled */
|
||||
static volatile u32_t systick_timems;
|
||||
|
||||
/*****************************************************************************
|
||||
* Public types/enumerations/variables
|
||||
****************************************************************************/
|
||||
|
||||
/* Current system clock rate, mainly used for sysTick */
|
||||
extern uint32_t SystemCoreClock;
|
||||
|
||||
/*****************************************************************************
|
||||
* Private functions
|
||||
****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Public functions
|
||||
****************************************************************************/
|
||||
|
||||
/* Enable LWIP tick and interrupt */
|
||||
void SysTick_Enable(uint32_t period)
|
||||
{
|
||||
/* Initialize System Tick with time interval */
|
||||
// SYSTICK_InternalInit(period); // FIXME
|
||||
// saved_period = period; // FIXME
|
||||
// systick_timems = 0; // FIXME
|
||||
|
||||
/* Enable System Tick interrupt */
|
||||
// SYSTICK_IntCmd(ENABLE); // FIXME
|
||||
|
||||
/* Enable System Tick Counter */
|
||||
// SYSTICK_Cmd(ENABLE); // FIXME
|
||||
|
||||
saved_period = period;
|
||||
SysTick_Config((SystemCoreClock * period) / 1000);
|
||||
}
|
||||
|
||||
/* Disable LWIP tick */
|
||||
void SysTick_Disable(void)
|
||||
{
|
||||
/* Disable System Tick Counter */
|
||||
// SYSTICK_Cmd(DISABLE); // FIXME
|
||||
|
||||
/* Disable System Tick interrupt */
|
||||
// SYSTICK_IntCmd(DISABLE); // FIXME
|
||||
|
||||
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SysTick IRQ handler and timebase management
|
||||
* @return Nothing
|
||||
* @note This function keeps a timebase for LWIP that can be
|
||||
* used for other functions.
|
||||
*/
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
/* Clear System Tick counter flag */
|
||||
// SYSTICK_ClearCounterFlag(); // FIXME
|
||||
|
||||
/* Increment tick count */
|
||||
systick_timems += saved_period;
|
||||
}
|
||||
|
||||
|
||||
/* Get the current systick time in milliSeconds */
|
||||
uint32_t SysTick_GetMS(void)
|
||||
{
|
||||
return systick_timems;
|
||||
}
|
||||
|
||||
/* Delay for the specified number of milliSeconds */
|
||||
void msDelay(uint32_t ms)
|
||||
{
|
||||
uint32_t to = ms + systick_timems;
|
||||
|
||||
while (to > systick_timems) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LWIP standalone mode time support
|
||||
* @return Returns the current time in mS
|
||||
* @note Returns the current time in mS. This is needed for the LWIP timers
|
||||
*/
|
||||
u32_t sys_now(void)
|
||||
{
|
||||
return (u32_t) SysTick_GetMS();
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* NO_SYS == 1 */
|
||||
+936
@@ -0,0 +1,936 @@
|
||||
/*
|
||||
* @brief LPC18xx/43xx LWIP EMAC driver
|
||||
*
|
||||
* @note
|
||||
* Copyright(C) NXP Semiconductors, 2012
|
||||
* All rights reserved.
|
||||
*
|
||||
* @par
|
||||
* Software that is described herein is for illustrative purposes only
|
||||
* which provides customers with programming information regarding the
|
||||
* LPC products. This software is supplied "AS IS" without any warranties of
|
||||
* any kind, and NXP Semiconductors and its licensor disclaim any and
|
||||
* all warranties, express or implied, including all implied warranties of
|
||||
* merchantability, fitness for a particular purpose and non-infringement of
|
||||
* intellectual property rights. NXP Semiconductors assumes no responsibility
|
||||
* or liability for the use of the software, conveys no license or rights under any
|
||||
* patent, copyright, mask work right, or any other intellectual property rights in
|
||||
* or to any products. NXP Semiconductors reserves the right to make changes
|
||||
* in the software without notification. NXP Semiconductors also makes no
|
||||
* representation or warranty that such application will be suitable for the
|
||||
* specified use without further testing or modification.
|
||||
*
|
||||
* @par
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation is hereby granted, under NXP Semiconductors' and its
|
||||
* licensor's relevant copyrights in the software, without fee, provided that it
|
||||
* is used in conjunction with NXP Semiconductors microcontrollers. This
|
||||
* copyright, permission, and disclaimer notice must appear in all copies of
|
||||
* this code.
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "netif/ppp_oe.h"
|
||||
|
||||
#include "lpc_18xx43xx_emac_config.h"
|
||||
#include "lpc18xx_43xx_emac.h"
|
||||
|
||||
#include "chip.h"
|
||||
#include "board.h"
|
||||
#include "lpc_phy.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
extern void msDelay(uint32_t ms);
|
||||
|
||||
#if LPC_NUM_BUFF_TXDESCS < 2
|
||||
#error LPC_NUM_BUFF_TXDESCS must be at least 2
|
||||
#endif
|
||||
|
||||
#if LPC_NUM_BUFF_RXDESCS < 3
|
||||
#error LPC_NUM_BUFF_RXDESCS must be at least 3
|
||||
#endif
|
||||
|
||||
#ifndef LPC_CHECK_SLOWMEM
|
||||
#error LPC_CHECK_SLOWMEM must be 0 or 1
|
||||
#endif
|
||||
|
||||
/** @ingroup NET_LWIP_LPC18XX43XX_EMAC_DRIVER
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
* Private types/enumerations/variables
|
||||
****************************************************************************/
|
||||
|
||||
#if NO_SYS == 0
|
||||
/**
|
||||
* @brief Driver transmit and receive thread priorities
|
||||
* Thread priorities for receive thread and TX cleanup thread. Alter
|
||||
* to prioritize receive or transmit bandwidth. In a heavily loaded
|
||||
* system or with LWIP_DEBUG enabled, the priorities might be better
|
||||
* the same. */
|
||||
#define tskTXCLEAN_PRIORITY (TCPIP_THREAD_PRIO - 1)
|
||||
#define tskRECPKT_PRIORITY (TCPIP_THREAD_PRIO - 1)
|
||||
#endif
|
||||
|
||||
/** @brief Debug output formatter lock define
|
||||
* When using FreeRTOS and with LWIP_DEBUG enabled, enabling this
|
||||
* define will allow RX debug messages to not interleave with the
|
||||
* TX messages (so they are actually readable). Not enabling this
|
||||
* define when the system is under load will cause the output to
|
||||
* be unreadable. There is a small tradeoff in performance for this
|
||||
* so use it only for debug. */
|
||||
// #define LOCK_RX_THREAD
|
||||
|
||||
/* LPC EMAC driver data structure */
|
||||
struct lpc_enetdata {
|
||||
struct netif *netif; /**< Reference back to LWIP parent netif */
|
||||
|
||||
IP_ENET_001_ENHTXDESC_T ptdesc[LPC_NUM_BUFF_TXDESCS]; /**< TX descriptor list */
|
||||
IP_ENET_001_ENHRXDESC_T prdesc[LPC_NUM_BUFF_RXDESCS]; /**< RX descriptor list */
|
||||
struct pbuf *txpbufs[LPC_NUM_BUFF_TXDESCS]; /**< Saved pbuf pointers, for free after TX */
|
||||
|
||||
volatile u32_t tx_free_descs; /**< Number of free TX descriptors */
|
||||
u32_t tx_fill_idx; /**< Current free TX descriptor index */
|
||||
u32_t tx_reclaim_idx; /**< Next incoming TX packet descriptor index */
|
||||
struct pbuf *rxpbufs[LPC_NUM_BUFF_RXDESCS]; /**< Saved pbuf pointers for RX */
|
||||
|
||||
volatile u32_t rx_free_descs; /**< Number of free RX descriptors */
|
||||
volatile u32_t rx_get_idx; /**< Index to next RX descriptor that id to be received */
|
||||
u32_t rx_next_idx; /**< Index to next RX descriptor that needs a pbuf */
|
||||
#if NO_SYS == 0
|
||||
sys_sem_t RxSem;/**< RX receive thread wakeup semaphore */
|
||||
sys_sem_t TxCleanSem; /**< TX cleanup thread wakeup semaphore */
|
||||
sys_mutex_t TXLockMutex;/**< TX critical section mutex */
|
||||
xSemaphoreHandle xTXDCountSem; /**< TX free buffer counting semaphore */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* LPC EMAC driver work data */
|
||||
static struct lpc_enetdata lpc_enetdata;
|
||||
|
||||
static uint32_t intMask;
|
||||
|
||||
#if LPC_CHECK_SLOWMEM == 1
|
||||
struct lpc_slowmem_array_t {
|
||||
u32_t start;
|
||||
u32_t end;
|
||||
};
|
||||
|
||||
const static struct lpc_slowmem_array_t slmem[] = LPC_SLOWMEM_ARRAY;
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* Public types/enumerations/variables
|
||||
****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Private functions
|
||||
****************************************************************************/
|
||||
|
||||
/* Queues a pbuf into a free RX descriptor */
|
||||
static void lpc_rxqueue_pbuf(struct lpc_enetdata *lpc_netifdata,
|
||||
struct pbuf *p)
|
||||
{
|
||||
u32_t idx = lpc_netifdata->rx_next_idx;
|
||||
|
||||
/* Save location of pbuf so we know what to pass to LWIP later */
|
||||
lpc_netifdata->rxpbufs[idx] = p;
|
||||
|
||||
/* Buffer size and address for pbuf */
|
||||
lpc_netifdata->prdesc[idx].CTRL = (u32_t) RDES_ENH_BS1(p->len) |
|
||||
RDES_ENH_RCH;
|
||||
if (idx == (LPC_NUM_BUFF_RXDESCS - 1)) {
|
||||
lpc_netifdata->prdesc[idx].CTRL |= RDES_ENH_RER;
|
||||
}
|
||||
lpc_netifdata->prdesc[idx].B1ADD = (u32_t) p->payload;
|
||||
|
||||
/* Give descriptor to MAC/DMA */
|
||||
lpc_netifdata->prdesc[idx].STATUS = RDES_OWN;
|
||||
|
||||
/* Update free count */
|
||||
lpc_netifdata->rx_free_descs--;
|
||||
|
||||
LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
|
||||
("lpc_rxqueue_pbuf: Queueing packet %p at index %d, free %d\n",
|
||||
p, idx, lpc_netifdata->rx_free_descs));
|
||||
|
||||
/* Update index for next pbuf */
|
||||
idx++;
|
||||
if (idx >= LPC_NUM_BUFF_RXDESCS) {
|
||||
idx = 0;
|
||||
}
|
||||
lpc_netifdata->rx_next_idx = idx;
|
||||
}
|
||||
|
||||
/* This function sets up the descriptor list used for receive packets */
|
||||
static err_t lpc_rx_setup(struct lpc_enetdata *lpc_netifdata)
|
||||
{
|
||||
s32_t idx;
|
||||
|
||||
/* Set to start of list */
|
||||
lpc_netifdata->rx_get_idx = 0;
|
||||
lpc_netifdata->rx_next_idx = 0;
|
||||
lpc_netifdata->rx_free_descs = LPC_NUM_BUFF_RXDESCS;
|
||||
|
||||
/* Clear initial RX descriptor list */
|
||||
memset(lpc_netifdata->prdesc, 0, sizeof(lpc_netifdata->prdesc));
|
||||
|
||||
/* Setup buffer chaining before allocating pbufs for descriptors
|
||||
just in case memory runs out. */
|
||||
for (idx = 0; idx < LPC_NUM_BUFF_RXDESCS; idx++) {
|
||||
lpc_netifdata->prdesc[idx].CTRL = RDES_ENH_RCH;
|
||||
lpc_netifdata->prdesc[idx].B2ADD = (u32_t)
|
||||
&lpc_netifdata->prdesc[idx + 1];
|
||||
}
|
||||
lpc_netifdata->prdesc[LPC_NUM_BUFF_RXDESCS - 1].CTRL =
|
||||
RDES_ENH_RCH | RDES_ENH_RER;
|
||||
lpc_netifdata->prdesc[LPC_NUM_BUFF_RXDESCS - 1].B2ADD =
|
||||
(u32_t) &lpc_netifdata->prdesc[0];
|
||||
LPC_ETHERNET->DMA_REC_DES_ADDR = (u32_t) lpc_netifdata->prdesc;
|
||||
|
||||
/* Setup up RX pbuf queue, but post a warning if not enough were
|
||||
queued for all descriptors. */
|
||||
if (lpc_rx_queue(lpc_netifdata->netif) != LPC_NUM_BUFF_RXDESCS) {
|
||||
LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
|
||||
("lpc_rx_setup: Warning, not enough memory for RX pbufs\n"));
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/* Gets data from queue and forwards to LWIP */
|
||||
static struct pbuf *lpc_low_level_input(struct netif *netif) {
|
||||
struct lpc_enetdata *lpc_netifdata = netif->state;
|
||||
u32_t status, ridx;
|
||||
int rxerr = 0;
|
||||
struct pbuf *p;
|
||||
|
||||
#ifdef LOCK_RX_THREAD
|
||||
#if NO_SYS == 0
|
||||
/* Get exclusive access */
|
||||
sys_mutex_lock(&lpc_netifdata->TXLockMutex);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* If there are no used descriptors, then this call was
|
||||
not for a received packet, try to setup some descriptors now */
|
||||
if (lpc_netifdata->rx_free_descs == LPC_NUM_BUFF_RXDESCS) {
|
||||
lpc_rx_queue(netif);
|
||||
#ifdef LOCK_RX_THREAD
|
||||
#if NO_SYS == 0
|
||||
sys_mutex_unlock(&lpc_netifdata->TXLockMutex);
|
||||
#endif
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get index for next descriptor with data */
|
||||
ridx = lpc_netifdata->rx_get_idx;
|
||||
|
||||
/* Return if descriptor is still owned by DMA */
|
||||
if (lpc_netifdata->prdesc[ridx].STATUS & RDES_OWN) {
|
||||
#ifdef LOCK_RX_THREAD
|
||||
#if NO_SYS == 0
|
||||
sys_mutex_unlock(&lpc_netifdata->TXLockMutex);
|
||||
#endif
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get address of pbuf for this descriptor */
|
||||
p = lpc_netifdata->rxpbufs[ridx];
|
||||
|
||||
/* Get receive packet status */
|
||||
status = lpc_netifdata->prdesc[ridx].STATUS;
|
||||
|
||||
/* Check packet for errors */
|
||||
if (status & RDES_ES) {
|
||||
LINK_STATS_INC(link.drop);
|
||||
|
||||
/* Error conditions that cause a packet drop */
|
||||
if (status & intMask) {
|
||||
LINK_STATS_INC(link.err);
|
||||
rxerr = 1;
|
||||
}
|
||||
else
|
||||
/* Length error check needs qualification */
|
||||
if ((status & (RDES_LE | RDES_FT)) == RDES_LE) {
|
||||
LINK_STATS_INC(link.lenerr);
|
||||
rxerr = 1;
|
||||
}
|
||||
else
|
||||
/* CRC error check needs qualification */
|
||||
if ((status & (RDES_CE | RDES_LS)) == (RDES_CE | RDES_LS)) {
|
||||
LINK_STATS_INC(link.chkerr);
|
||||
rxerr = 1;
|
||||
}
|
||||
|
||||
/* Descriptor error check needs qualification */
|
||||
if ((status & (RDES_DE | RDES_LS)) == (RDES_DE | RDES_LS)) {
|
||||
LINK_STATS_INC(link.err);
|
||||
rxerr = 1;
|
||||
}
|
||||
else
|
||||
/* Dribble bit error only applies in half duplex mode */
|
||||
if ((status & RDES_DE) &&
|
||||
(!(LPC_ETHERNET->MAC_CONFIG & MAC_CFG_DM))) {
|
||||
LINK_STATS_INC(link.err);
|
||||
rxerr = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Increment free descriptor count and next get index */
|
||||
lpc_netifdata->rx_free_descs++;
|
||||
ridx++;
|
||||
if (ridx >= LPC_NUM_BUFF_RXDESCS) {
|
||||
ridx = 0;
|
||||
}
|
||||
lpc_netifdata->rx_get_idx = ridx;
|
||||
|
||||
/* If an error occurred, just re-queue the pbuf */
|
||||
if (rxerr) {
|
||||
lpc_rxqueue_pbuf(lpc_netifdata, p);
|
||||
p = NULL;
|
||||
|
||||
LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
|
||||
("lpc_low_level_input: RX error condition status 0x%08x\n",
|
||||
status));
|
||||
}
|
||||
else {
|
||||
/* Attempt to queue a new pbuf for the descriptor */
|
||||
lpc_rx_queue(netif);
|
||||
|
||||
/* Get length of received packet */
|
||||
p->len = p->tot_len = (u16_t) RDES_FLMSK(status);
|
||||
|
||||
LINK_STATS_INC(link.recv);
|
||||
|
||||
LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
|
||||
("lpc_low_level_input: Packet received, %d bytes, "
|
||||
"status 0x%08x\n", p->len, status));
|
||||
}
|
||||
|
||||
/* (Re)start receive polling */
|
||||
LPC_ETHERNET->DMA_REC_POLL_DEMAND = 1;
|
||||
|
||||
#ifdef LOCK_RX_THREAD
|
||||
#if NO_SYS == 0
|
||||
/* Get exclusive access */
|
||||
sys_mutex_unlock(&lpc_netifdata->TXLockMutex);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/* This function sets up the descriptor list used for transmit packets */
|
||||
static err_t lpc_tx_setup(struct lpc_enetdata *lpc_netifdata)
|
||||
{
|
||||
s32_t idx;
|
||||
|
||||
/* Clear TX descriptors, will be queued with pbufs as needed */
|
||||
memset((void *) &lpc_netifdata->ptdesc[0], 0, sizeof(lpc_netifdata->ptdesc));
|
||||
lpc_netifdata->tx_free_descs = LPC_NUM_BUFF_TXDESCS;
|
||||
lpc_netifdata->tx_fill_idx = 0;
|
||||
lpc_netifdata->tx_reclaim_idx = 0;
|
||||
|
||||
/* Link/wrap descriptors */
|
||||
for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) {
|
||||
lpc_netifdata->ptdesc[idx].CTRLSTAT = TDES_ENH_TCH | TDES_ENH_CIC(3);
|
||||
lpc_netifdata->ptdesc[idx].B2ADD =
|
||||
(u32_t) &lpc_netifdata->ptdesc[idx + 1];
|
||||
}
|
||||
lpc_netifdata->ptdesc[LPC_NUM_BUFF_TXDESCS - 1].CTRLSTAT =
|
||||
TDES_ENH_TCH | TDES_ENH_TER | TDES_ENH_CIC(3);
|
||||
lpc_netifdata->ptdesc[LPC_NUM_BUFF_TXDESCS - 1].B2ADD =
|
||||
(u32_t) &lpc_netifdata->ptdesc[0];
|
||||
|
||||
/* Setup pointer to TX descriptor table */
|
||||
LPC_ETHERNET->DMA_TRANS_DES_ADDR = (u32_t) lpc_netifdata->ptdesc;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/* Low level output of a packet. Never call this from an interrupt context,
|
||||
as it may block until TX descriptors become available */
|
||||
static err_t lpc_low_level_output(struct netif *netif, struct pbuf *sendp)
|
||||
{
|
||||
struct lpc_enetdata *lpc_netifdata = netif->state;
|
||||
u32_t idx, fidx, dn;
|
||||
struct pbuf *p = sendp;
|
||||
|
||||
#if LPC_CHECK_SLOWMEM == 1
|
||||
struct pbuf *q, *wp;
|
||||
|
||||
u8_t *dst;
|
||||
int pcopy = 0;
|
||||
|
||||
/* Check packet address to determine if it's in slow memory and
|
||||
relocate if necessary */
|
||||
for (q = p; ((q != NULL) && (pcopy == 0)); q = q->next) {
|
||||
fidx = 0;
|
||||
for (idx = 0; idx < sizeof(slmem);
|
||||
idx += sizeof(struct lpc_slowmem_array_t)) {
|
||||
if ((q->payload >= (void *) slmem[fidx].start) &&
|
||||
(q->payload <= (void *) slmem[fidx].end)) {
|
||||
/* Needs copy */
|
||||
pcopy = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pcopy) {
|
||||
/* Create a new pbuf with the total pbuf size */
|
||||
wp = pbuf_alloc(PBUF_RAW, (u16_t) EMAC_ETH_MAX_FLEN, PBUF_RAM);
|
||||
if (!wp) {
|
||||
/* Exit with error */
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
/* Copy pbuf */
|
||||
dst = (u8_t *) wp->payload;
|
||||
wp->tot_len = 0;
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
MEMCPY(dst, (u8_t *) q->payload, q->len);
|
||||
dst += q->len;
|
||||
wp->tot_len += q->len;
|
||||
}
|
||||
wp->len = wp->tot_len;
|
||||
|
||||
/* LWIP will free original pbuf on exit of function */
|
||||
|
||||
p = sendp = wp;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Zero-copy TX buffers may be fragmented across mutliple payload
|
||||
chains. Determine the number of descriptors needed for the
|
||||
transfer. The pbuf chaining can be a mess! */
|
||||
dn = (u32_t) pbuf_clen(p);
|
||||
|
||||
/* Wait until enough descriptors are available for the transfer. */
|
||||
/* THIS WILL BLOCK UNTIL THERE ARE ENOUGH DESCRIPTORS AVAILABLE */
|
||||
while (dn > lpc_tx_ready(netif))
|
||||
#if NO_SYS == 0
|
||||
{xSemaphoreTake(lpc_netifdata->xTXDCountSem, 0); }
|
||||
#else
|
||||
{msDelay(1); }
|
||||
#endif
|
||||
|
||||
/* Get the next free descriptor index */
|
||||
fidx = idx = lpc_netifdata->tx_fill_idx;
|
||||
|
||||
#if NO_SYS == 0
|
||||
/* Get exclusive access */
|
||||
sys_mutex_lock(&lpc_netifdata->TXLockMutex);
|
||||
#endif
|
||||
|
||||
/* Fill in the next free descriptor(s) */
|
||||
while (dn > 0) {
|
||||
dn--;
|
||||
|
||||
/* Setup packet address and length */
|
||||
lpc_netifdata->ptdesc[idx].B1ADD = (u32_t) p->payload;
|
||||
lpc_netifdata->ptdesc[idx].BSIZE = (u32_t) TDES_ENH_BS1(p->len);
|
||||
|
||||
/* Save pointer to pbuf so we can reclain the memory for
|
||||
the pbuf after the buffer has been sent. Only the first
|
||||
pbuf in a chain is saved since the full chain doesn't
|
||||
need to be freed. */
|
||||
/* For first packet only, first flag */
|
||||
lpc_netifdata->tx_free_descs--;
|
||||
if (idx == fidx) {
|
||||
lpc_netifdata->ptdesc[idx].CTRLSTAT |= TDES_ENH_FS;
|
||||
#if LPC_CHECK_SLOWMEM == 1
|
||||
/* If this is a copied pbuf, then avoid getting the extra reference
|
||||
or the TX reclaim will be off by 1 */
|
||||
if (!pcopy) {
|
||||
pbuf_ref(p);
|
||||
}
|
||||
#else
|
||||
/* Increment reference count on this packet so LWIP doesn't
|
||||
attempt to free it on return from this call */
|
||||
pbuf_ref(p);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
lpc_netifdata->ptdesc[idx].CTRLSTAT |= TDES_OWN;
|
||||
}
|
||||
|
||||
/* Save address of pbuf, but make sure it's associated with the
|
||||
first chained pbuf so it gets freed once all pbuf chains are
|
||||
transferred. */
|
||||
if (!dn) {
|
||||
lpc_netifdata->txpbufs[idx] = sendp;
|
||||
}
|
||||
else {
|
||||
lpc_netifdata->txpbufs[idx] = NULL;
|
||||
}
|
||||
|
||||
/* For last packet only, interrupt and last flag */
|
||||
if (dn == 0) {
|
||||
lpc_netifdata->ptdesc[idx].CTRLSTAT |= TDES_ENH_LS |
|
||||
TDES_ENH_IC;
|
||||
}
|
||||
|
||||
/* IP checksumming requires full buffering in IP */
|
||||
lpc_netifdata->ptdesc[idx].CTRLSTAT |= TDES_ENH_CIC(3);
|
||||
|
||||
LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
|
||||
("lpc_low_level_output: pbuf packet %p sent, chain %d,"
|
||||
" size %d, index %d, free %d\n", p, dn, p->len, idx,
|
||||
lpc_netifdata->tx_free_descs));
|
||||
|
||||
/* Update next available descriptor */
|
||||
idx++;
|
||||
if (idx >= LPC_NUM_BUFF_TXDESCS) {
|
||||
idx = 0;
|
||||
}
|
||||
|
||||
/* Next packet fragment */
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
lpc_netifdata->tx_fill_idx = idx;
|
||||
|
||||
LINK_STATS_INC(link.xmit);
|
||||
|
||||
/* Give first descriptor to DMA to start transfer */
|
||||
lpc_netifdata->ptdesc[fidx].CTRLSTAT |= TDES_OWN;
|
||||
|
||||
/* Tell DMA to poll descriptors to start transfer */
|
||||
LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = 1;
|
||||
|
||||
#if NO_SYS == 0
|
||||
/* Restore access */
|
||||
sys_mutex_unlock(&lpc_netifdata->TXLockMutex);
|
||||
#endif
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/* This function is the ethernet packet send function. It calls
|
||||
etharp_output after checking link status */
|
||||
static err_t lpc_etharp_output(struct netif *netif, struct pbuf *q,
|
||||
ip_addr_t *ipaddr)
|
||||
{
|
||||
/* Only send packet is link is up */
|
||||
if (netif->flags & NETIF_FLAG_LINK_UP) {
|
||||
return etharp_output(netif, q, ipaddr);
|
||||
}
|
||||
|
||||
return ERR_CONN;
|
||||
}
|
||||
|
||||
#if NO_SYS == 0
|
||||
/* Packet reception task
|
||||
This task is called when a packet is received. It will
|
||||
pass the packet to the LWIP core */
|
||||
static portTASK_FUNCTION(vPacketReceiveTask, pvParameters) {
|
||||
struct lpc_enetdata *lpc_netifdata = pvParameters;
|
||||
|
||||
while (1) {
|
||||
/* Wait for receive task to wakeup */
|
||||
sys_arch_sem_wait(&lpc_netifdata->RxSem, 0);
|
||||
|
||||
/* Process receive packets */
|
||||
while (!(lpc_netifdata->prdesc[lpc_netifdata->rx_get_idx].STATUS
|
||||
& RDES_OWN)) {
|
||||
lpc_enetif_input(lpc_netifdata->netif);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Transmit cleanup task
|
||||
This task is called when a transmit interrupt occurs and
|
||||
reclaims the pbuf and descriptor used for the packet once
|
||||
the packet has been transferred */
|
||||
static portTASK_FUNCTION(vTransmitCleanupTask, pvParameters) {
|
||||
struct lpc_enetdata *lpc_netifdata = pvParameters;
|
||||
|
||||
while (1) {
|
||||
/* Wait for transmit cleanup task to wakeup */
|
||||
sys_arch_sem_wait(&lpc_netifdata->TxCleanSem, 0);
|
||||
|
||||
/* Free TX pbufs and descriptors that are done */
|
||||
lpc_tx_reclaim(lpc_netifdata->netif);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Low level init of the MAC and PHY */
|
||||
static err_t low_level_init(struct netif *netif)
|
||||
{
|
||||
struct lpc_enetdata *lpc_netifdata = netif->state;
|
||||
|
||||
/* Initialize via Chip ENET function */
|
||||
Chip_ENET_Init(LPC_ETHERNET);
|
||||
|
||||
/* Save MAC address */
|
||||
Chip_ENET_SetADDR(LPC_ETHERNET, netif->hwaddr);
|
||||
|
||||
/* Initial MAC configuration for checksum offload, full duplex,
|
||||
100Mbps, disable receive own in half duplex, inter-frame gap
|
||||
of 64-bits */
|
||||
LPC_ETHERNET->MAC_CONFIG = MAC_CFG_BL(0) | MAC_CFG_IPC | MAC_CFG_DM |
|
||||
MAC_CFG_DO | MAC_CFG_FES | MAC_CFG_PS | MAC_CFG_IFG(3);
|
||||
|
||||
/* Setup filter */
|
||||
#if IP_SOF_BROADCAST_RECV
|
||||
LPC_ETHERNET->MAC_FRAME_FILTER = MAC_FF_PR | MAC_FF_RA;
|
||||
#else
|
||||
LPC_ETHERNET->MAC_FRAME_FILTER = 0; /* Only matching MAC address */
|
||||
#endif
|
||||
|
||||
/* Initialize the PHY */
|
||||
#if defined(USE_RMII)
|
||||
if (lpc_phy_init(true, msDelay) != SUCCESS) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
intMask = RDES_CE | RDES_DE | RDES_RE | RDES_RWT | RDES_LC | RDES_OE |
|
||||
RDES_SAF | RDES_AFM;
|
||||
#else
|
||||
if (lpc_phy_init(false, msDelay) != SUCCESS) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
intMask = RDES_CE | RDES_RE | RDES_RWT | RDES_LC | RDES_OE | RDES_SAF |
|
||||
RDES_AFM;
|
||||
#endif
|
||||
|
||||
/* Setup transmit and receive descriptors */
|
||||
if (lpc_tx_setup(lpc_netifdata) != ERR_OK) {
|
||||
return ERR_BUF;
|
||||
}
|
||||
if (lpc_rx_setup(lpc_netifdata) != ERR_OK) {
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
/* Flush transmit FIFO */
|
||||
LPC_ETHERNET->DMA_OP_MODE = DMA_OM_FTF;
|
||||
|
||||
/* Setup DMA to flush receive FIFOs at 32 bytes, service TX FIFOs at
|
||||
64 bytes */
|
||||
LPC_ETHERNET->DMA_OP_MODE |= DMA_OM_RTC(1) | DMA_OM_TTC(0);
|
||||
|
||||
/* Clear all MAC interrupts */
|
||||
LPC_ETHERNET->DMA_STAT = DMA_ST_ALL;
|
||||
|
||||
/* Enable MAC interrupts */
|
||||
LPC_ETHERNET->DMA_INT_EN =
|
||||
#if NO_SYS == 1
|
||||
0;
|
||||
#else
|
||||
DMA_IE_TIE | DMA_IE_OVE | DMA_IE_UNE | DMA_IE_RIE | DMA_IE_NIE |
|
||||
DMA_IE_AIE | DMA_IE_TUE | DMA_IE_RUE;
|
||||
#endif
|
||||
|
||||
/* Enable receive and transmit DMA processes */
|
||||
LPC_ETHERNET->DMA_OP_MODE |= DMA_OM_ST | DMA_OM_SR;
|
||||
|
||||
/* Enable packet reception */
|
||||
LPC_ETHERNET->MAC_CONFIG |= MAC_CFG_RE | MAC_CFG_TE;
|
||||
|
||||
/* Start receive polling */
|
||||
LPC_ETHERNET->DMA_REC_POLL_DEMAND = 1;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Public functions
|
||||
****************************************************************************/
|
||||
/* Attempt to allocate and requeue a new pbuf for RX */
|
||||
s32_t lpc_rx_queue(struct netif *netif)
|
||||
{
|
||||
struct lpc_enetdata *lpc_netifdata = netif->state;
|
||||
struct pbuf *p;
|
||||
|
||||
s32_t queued = 0;
|
||||
|
||||
/* Attempt to requeue as many packets as possible */
|
||||
while (lpc_netifdata->rx_free_descs > 0) {
|
||||
/* Allocate a pbuf from the pool. We need to allocate at the
|
||||
maximum size as we don't know the size of the yet to be
|
||||
received packet. */
|
||||
p = pbuf_alloc(PBUF_RAW, (u16_t) EMAC_ETH_MAX_FLEN, PBUF_RAM);
|
||||
if (p == NULL) {
|
||||
LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
|
||||
("lpc_rx_queue: could not allocate RX pbuf index %d, "
|
||||
"free %d)\n", lpc_netifdata->rx_next_idx,
|
||||
lpc_netifdata->rx_free_descs));
|
||||
return queued;
|
||||
}
|
||||
|
||||
/* pbufs allocated from the RAM pool should be non-chained (although
|
||||
the hardware will allow chaining) */
|
||||
LWIP_ASSERT("lpc_rx_queue: pbuf is not contiguous (chained)",
|
||||
pbuf_clen(p) <= 1);
|
||||
|
||||
/* Queue packet */
|
||||
lpc_rxqueue_pbuf(lpc_netifdata, p);
|
||||
|
||||
/* Update queued count */
|
||||
queued++;
|
||||
}
|
||||
|
||||
return queued;
|
||||
}
|
||||
|
||||
/* Attempt to read a packet from the EMAC interface */
|
||||
void lpc_enetif_input(struct netif *netif)
|
||||
{
|
||||
struct eth_hdr *ethhdr;
|
||||
|
||||
struct pbuf *p;
|
||||
|
||||
/* move received packet into a new pbuf */
|
||||
p = lpc_low_level_input(netif);
|
||||
if (p == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* points to packet payload, which starts with an Ethernet header */
|
||||
ethhdr = p->payload;
|
||||
|
||||
switch (htons(ethhdr->type)) {
|
||||
case ETHTYPE_IP:
|
||||
case ETHTYPE_ARP:
|
||||
#if PPPOE_SUPPORT
|
||||
case ETHTYPE_PPPOEDISC:
|
||||
case ETHTYPE_PPPOE:
|
||||
#endif /* PPPOE_SUPPORT */
|
||||
/* full packet send to tcpip_thread to process */
|
||||
if (netif->input(p, netif) != ERR_OK) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG,
|
||||
("lpc_enetif_input: IP input error\n"));
|
||||
/* Free buffer */
|
||||
pbuf_free(p);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Return buffer */
|
||||
pbuf_free(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call for freeing TX buffers that are complete */
|
||||
void lpc_tx_reclaim(struct netif *netif)
|
||||
{
|
||||
struct lpc_enetdata *lpc_netifdata = netif->state;
|
||||
s32_t ridx;
|
||||
u32_t status;
|
||||
|
||||
#if NO_SYS == 0
|
||||
/* Get exclusive access */
|
||||
sys_mutex_lock(&lpc_netifdata->TXLockMutex);
|
||||
#endif
|
||||
|
||||
/* If a descriptor is available and is no longer owned by the
|
||||
hardware, it can be reclaimed */
|
||||
ridx = lpc_netifdata->tx_reclaim_idx;
|
||||
while ((lpc_netifdata->tx_free_descs < LPC_NUM_BUFF_TXDESCS) &&
|
||||
(!(lpc_netifdata->ptdesc[ridx].CTRLSTAT & TDES_OWN))) {
|
||||
/* Peek at the status of the descriptor to determine if the
|
||||
packet is good and any status information. */
|
||||
status = lpc_netifdata->ptdesc[ridx].CTRLSTAT;
|
||||
|
||||
LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
|
||||
("lpc_tx_reclaim: Reclaiming sent packet %p, index %d\n",
|
||||
lpc_netifdata->txpbufs[ridx], ridx));
|
||||
|
||||
/* Check TX error conditions */
|
||||
if (status & TDES_ES) {
|
||||
LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
|
||||
("lpc_tx_reclaim: TX error condition status 0x%x\n", status));
|
||||
LINK_STATS_INC(link.err);
|
||||
|
||||
#if LINK_STATS == 1
|
||||
/* Error conditions that cause a packet drop */
|
||||
if (status & (TDES_UF | TDES_ED | TDES_EC | TDES_LC)) {
|
||||
LINK_STATS_INC(link.drop);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Reset control for this descriptor */
|
||||
if (ridx == (LPC_NUM_BUFF_TXDESCS - 1)) {
|
||||
lpc_netifdata->ptdesc[ridx].CTRLSTAT = TDES_ENH_TCH |
|
||||
TDES_ENH_TER;
|
||||
}
|
||||
else {
|
||||
lpc_netifdata->ptdesc[ridx].CTRLSTAT = TDES_ENH_TCH;
|
||||
}
|
||||
|
||||
/* Free the pbuf associate with this descriptor */
|
||||
if (lpc_netifdata->txpbufs[ridx]) {
|
||||
pbuf_free(lpc_netifdata->txpbufs[ridx]);
|
||||
}
|
||||
|
||||
/* Reclaim this descriptor */
|
||||
lpc_netifdata->tx_free_descs++;
|
||||
#if NO_SYS == 0
|
||||
xSemaphoreGive(lpc_netifdata->xTXDCountSem);
|
||||
#endif
|
||||
ridx++;
|
||||
if (ridx >= LPC_NUM_BUFF_TXDESCS) {
|
||||
ridx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
lpc_netifdata->tx_reclaim_idx = ridx;
|
||||
|
||||
#if NO_SYS == 0
|
||||
/* Restore access */
|
||||
sys_mutex_unlock(&lpc_netifdata->TXLockMutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Polls if an available TX descriptor is ready */
|
||||
s32_t lpc_tx_ready(struct netif *netif)
|
||||
{
|
||||
return ((struct lpc_enetdata *) netif->state)->tx_free_descs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief EMAC interrupt handler
|
||||
* @return Nothing
|
||||
* @note This function handles the transmit, receive, and error interrupt of
|
||||
* the LPC118xx/43xx. This is meant to be used when NO_SYS=0.
|
||||
*/
|
||||
void ETH_IRQHandler(void)
|
||||
{
|
||||
#if NO_SYS == 1
|
||||
/* Interrupts are not used without an RTOS */
|
||||
NVIC_DisableIRQ((IRQn_Type) ETHERNET_IRQn);
|
||||
#else
|
||||
signed portBASE_TYPE xRecTaskWoken = pdFALSE, XTXTaskWoken = pdFALSE;
|
||||
uint32_t ints;
|
||||
|
||||
/* Get pending interrupts */
|
||||
ints = LPC_ETHERNET->DMA_STAT;
|
||||
|
||||
/* RX group interrupt(s) */
|
||||
if (ints & (DMA_ST_RI | DMA_ST_OVF | DMA_ST_RU)) {
|
||||
/* Give semaphore to wakeup RX receive task. Note the FreeRTOS
|
||||
method is used instead of the LWIP arch method. */
|
||||
xSemaphoreGiveFromISR(lpc_enetdata.RxSem, &xRecTaskWoken);
|
||||
}
|
||||
|
||||
/* TX group interrupt(s) */
|
||||
if (ints & (DMA_ST_TI | DMA_ST_UNF | DMA_ST_TU)) {
|
||||
/* Give semaphore to wakeup TX cleanup task. Note the FreeRTOS
|
||||
method is used instead of the LWIP arch method. */
|
||||
xSemaphoreGiveFromISR(lpc_enetdata.TxCleanSem, &XTXTaskWoken);
|
||||
}
|
||||
|
||||
/* Clear pending interrupts */
|
||||
LPC_ETHERNET->DMA_STAT = ints;
|
||||
|
||||
/* Context switch needed? */
|
||||
portEND_SWITCHING_ISR(xRecTaskWoken || XTXTaskWoken);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Set up the MAC interface duplex */
|
||||
void lpc_emac_set_duplex(int full_duplex)
|
||||
{
|
||||
if (full_duplex) {
|
||||
LPC_ETHERNET->MAC_CONFIG |= MAC_CFG_DM;
|
||||
}
|
||||
else {
|
||||
LPC_ETHERNET->MAC_CONFIG &= ~MAC_CFG_DM;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up the MAC interface speed */
|
||||
void lpc_emac_set_speed(int mbs_100)
|
||||
{
|
||||
if (mbs_100) {
|
||||
LPC_ETHERNET->MAC_CONFIG |= MAC_CFG_FES;
|
||||
}
|
||||
else {
|
||||
LPC_ETHERNET->MAC_CONFIG &= ~MAC_CFG_FES;
|
||||
}
|
||||
}
|
||||
|
||||
/* LWIP 18xx/43xx EMAC initialization function */
|
||||
err_t lpc_enetif_init(struct netif *netif)
|
||||
{
|
||||
err_t err;
|
||||
extern void Board_ENET_GetMacADDR(u8_t *mcaddr);
|
||||
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
|
||||
lpc_enetdata.netif = netif;
|
||||
|
||||
/* set MAC hardware address */
|
||||
Board_ENET_GetMacADDR(netif->hwaddr);
|
||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
||||
|
||||
/* maximum transfer unit */
|
||||
netif->mtu = 1500;
|
||||
|
||||
/* device capabilities */
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_UP |
|
||||
NETIF_FLAG_ETHERNET;
|
||||
|
||||
/* Initialize the hardware */
|
||||
netif->state = &lpc_enetdata;
|
||||
err = low_level_init(netif);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
/* Initialize interface hostname */
|
||||
netif->hostname = "lwiplpc";
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
netif->name[0] = 'e';
|
||||
netif->name[1] = 'n';
|
||||
|
||||
netif->output = lpc_etharp_output;
|
||||
netif->linkoutput = lpc_low_level_output;
|
||||
|
||||
/* For FreeRTOS, start tasks */
|
||||
#if NO_SYS == 0
|
||||
lpc_enetdata.xTXDCountSem = xSemaphoreCreateCounting(LPC_NUM_BUFF_TXDESCS,
|
||||
LPC_NUM_BUFF_TXDESCS);
|
||||
LWIP_ASSERT("xTXDCountSem creation error",
|
||||
(lpc_enetdata.xTXDCountSem != NULL));
|
||||
|
||||
err = sys_mutex_new(&lpc_enetdata.TXLockMutex);
|
||||
LWIP_ASSERT("TXLockMutex creation error", (err == ERR_OK));
|
||||
|
||||
/* Packet receive task */
|
||||
err = sys_sem_new(&lpc_enetdata.RxSem, 0);
|
||||
LWIP_ASSERT("RxSem creation error", (err == ERR_OK));
|
||||
sys_thread_new("receive_thread", vPacketReceiveTask, netif->state,
|
||||
DEFAULT_THREAD_STACKSIZE, tskRECPKT_PRIORITY);
|
||||
|
||||
/* Transmit cleanup task */
|
||||
err = sys_sem_new(&lpc_enetdata.TxCleanSem, 0);
|
||||
LWIP_ASSERT("TxCleanSem creation error", (err == ERR_OK));
|
||||
sys_thread_new("txclean_thread", vTransmitCleanupTask, netif->state,
|
||||
DEFAULT_THREAD_STACKSIZE, tskTXCLEAN_PRIORITY);
|
||||
#endif
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* @brief LPC18xx/43xx LWIP EMAC driver
|
||||
*
|
||||
* @note
|
||||
* Copyright(C) NXP Semiconductors, 2012
|
||||
* All rights reserved.
|
||||
*
|
||||
* @par
|
||||
* Software that is described herein is for illustrative purposes only
|
||||
* which provides customers with programming information regarding the
|
||||
* LPC products. This software is supplied "AS IS" without any warranties of
|
||||
* any kind, and NXP Semiconductors and its licensor disclaim any and
|
||||
* all warranties, express or implied, including all implied warranties of
|
||||
* merchantability, fitness for a particular purpose and non-infringement of
|
||||
* intellectual property rights. NXP Semiconductors assumes no responsibility
|
||||
* or liability for the use of the software, conveys no license or rights under any
|
||||
* patent, copyright, mask work right, or any other intellectual property rights in
|
||||
* or to any products. NXP Semiconductors reserves the right to make changes
|
||||
* in the software without notification. NXP Semiconductors also makes no
|
||||
* representation or warranty that such application will be suitable for the
|
||||
* specified use without further testing or modification.
|
||||
*
|
||||
* @par
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation is hereby granted, under NXP Semiconductors' and its
|
||||
* licensor's relevant copyrights in the software, without fee, provided that it
|
||||
* is used in conjunction with NXP Semiconductors microcontrollers. This
|
||||
* copyright, permission, and disclaimer notice must appear in all copies of
|
||||
* this code.
|
||||
*/
|
||||
|
||||
#ifndef __LPC18XX_43XX_EMAC_H_
|
||||
#define __LPC18XX_43XX_EMAC_H_
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/** @defgroup NET_LWIP_LPC18XX43XX_EMAC_DRIVER 18xx/43xx EMAC driver for LWIP
|
||||
* @ingroup NET_LWIP
|
||||
* This is the LPC18xx/43xx EMAC driver for LWIP. This driver supports both
|
||||
* RTOS-based and no-RTOS operation with LWIP. WHen using an RTOS, several
|
||||
* threads will be created for handling RX and TX packet fucntions.
|
||||
*
|
||||
* Note that some LWIP examples may not necessarily use all the provided
|
||||
* LWIP driver functions or may contain overriden versions of the functions.
|
||||
* (For example, PHY drives may have their own implementation of the MII
|
||||
* read/write functions).
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Attempt to read a packet from the EMAC interface
|
||||
* @param netif : lwip network interface structure pointer
|
||||
* @return Nothing
|
||||
*/
|
||||
void lpc_enetif_input(struct netif *netif);
|
||||
|
||||
/**
|
||||
* @brief Attempt to allocate and requeue a new pbuf for RX
|
||||
* @param netif : lwip network interface structure pointer
|
||||
* @return The number of new descriptors queued
|
||||
*/
|
||||
s32_t lpc_rx_queue(struct netif *netif);
|
||||
|
||||
/**
|
||||
* @brief Polls if an available TX descriptor is ready
|
||||
* @param netif : lwip network interface structure pointer
|
||||
* @return 0 if no descriptors are read, or >0
|
||||
* @note Can be used to determine if the low level transmit function will block
|
||||
*/
|
||||
s32_t lpc_tx_ready(struct netif *netif);
|
||||
|
||||
/**
|
||||
* @brief Call for freeing TX buffers that are complete
|
||||
* @param netif : lwip network interface structure pointer
|
||||
* @return Nothing
|
||||
*/
|
||||
void lpc_tx_reclaim(struct netif *netif);
|
||||
|
||||
/**
|
||||
* @brief LWIP 18xx/43xx EMAC initialization function
|
||||
* @param netif : lwip network interface structure pointer
|
||||
* @return ERR_OK if the loopif is initialized, or ERR_* on other errors
|
||||
* @note Should be called at the beginning of the program to set up the
|
||||
* network interface. This function should be passed as a parameter to
|
||||
* netif_add().
|
||||
*/
|
||||
err_t lpc_enetif_init(struct netif *netif);
|
||||
|
||||
/**
|
||||
* @brief Set up the MAC interface duplex
|
||||
* @param full_duplex : 0 = half duplex, 1 = full duplex
|
||||
* @return Nothing
|
||||
* @note This function provides a method for the PHY to setup the EMAC
|
||||
* for the PHY negotiated duplex mode.
|
||||
*/
|
||||
void lpc_emac_set_duplex(int full_duplex);
|
||||
|
||||
/**
|
||||
* @brief Set up the MAC interface speed
|
||||
* @param mbs_100 : 0 = 10mbs mode, 1 = 100mbs mode
|
||||
* @return Nothing
|
||||
* @note This function provides a method for the PHY to setup the EMAC
|
||||
* for the PHY negotiated bit rate.
|
||||
*/
|
||||
void lpc_emac_set_speed(int mbs_100);
|
||||
|
||||
/**
|
||||
* @brief Millisecond Delay function
|
||||
* @param ms : Milliseconds to wait
|
||||
* @return None
|
||||
*/
|
||||
extern void msDelay(uint32_t ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* __LPC18XX_43XX_EMAC_H_ */
|
||||
@@ -0,0 +1,174 @@
|
||||
/**********************************************************************
|
||||
* @brief Setups up the LWIP timebase (tick)
|
||||
*
|
||||
* @note
|
||||
* Copyright(C) NXP Semiconductors, 2012
|
||||
* All rights reserved.
|
||||
*
|
||||
* @par
|
||||
* Software that is described herein is for illustrative purposes only
|
||||
* which provides customers with programming information regarding the
|
||||
* LPC products. This software is supplied "AS IS" without any warranties of
|
||||
* any kind, and NXP Semiconductors and its licensor disclaim any and
|
||||
* all warranties, express or implied, including all implied warranties of
|
||||
* merchantability, fitness for a particular purpose and non-infringement of
|
||||
* intellectual property rights. NXP Semiconductors assumes no responsibility
|
||||
* or liability for the use of the software, conveys no license or rights under any
|
||||
* patent, copyright, mask work right, or any other intellectual property rights in
|
||||
* or to any products. NXP Semiconductors reserves the right to make changes
|
||||
* in the software without notification. NXP Semiconductors also makes no
|
||||
* representation or warranty that such application will be suitable for the
|
||||
* specified use without further testing or modification.
|
||||
*
|
||||
* @par
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation is hereby granted, under NXP Semiconductors' and its
|
||||
* licensor's relevant copyrights in the software, without fee, provided that it
|
||||
* is used in conjunction with NXP Semiconductors microcontrollers. This
|
||||
* copyright, permission, and disclaimer notice must appear in all copies of
|
||||
* this code.
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if NO_SYS == 1
|
||||
|
||||
#include "chip.h"
|
||||
#include "lpc_arch.h"
|
||||
|
||||
/** @ingroup NET_LWIP_ARCH
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
* Private types/enumerations/variables
|
||||
****************************************************************************/
|
||||
|
||||
/* Saved reference period foe standalone mode */
|
||||
static uint32_t saved_period;
|
||||
|
||||
#if (defined(CHIP_LPC43XX) && defined(CORE_M0))
|
||||
|
||||
#define RITIMER_IRQn_PRI (255)
|
||||
|
||||
/* RITimer Reload value */
|
||||
static uint32_t reload_val;
|
||||
#endif
|
||||
|
||||
/* Saved total time in mS since timer was enabled */
|
||||
static volatile u32_t systick_timems;
|
||||
|
||||
/*****************************************************************************
|
||||
* Public types/enumerations/variables
|
||||
****************************************************************************/
|
||||
|
||||
/* Current system clock rate, mainly used for sysTick */
|
||||
extern uint32_t SystemCoreClock;
|
||||
|
||||
/*****************************************************************************
|
||||
* Private functions
|
||||
****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Public functions
|
||||
****************************************************************************/
|
||||
|
||||
#if (defined(CHIP_LPC43XX) && defined(CORE_M0))
|
||||
|
||||
/* Enable LWIP tick and interrupt */
|
||||
void SysTick_Enable(uint32_t period)
|
||||
{
|
||||
saved_period = period;
|
||||
|
||||
/* Clear any pending interrupt */
|
||||
Chip_RIT_ClearInt(LPC_RITIMER);
|
||||
|
||||
/* Calculate reload value */
|
||||
reload_val = ( SystemCoreClock / ( 1000 / period ) );
|
||||
Chip_RIT_SetCOMPVAL(LPC_RITIMER, Chip_RIT_GetCounter(LPC_RITIMER) + reload_val);/* Let it tick */
|
||||
|
||||
/* Set the priority and enable the interrupt */
|
||||
NVIC_SetPriority((IRQn_Type) RITIMER_IRQn, RITIMER_IRQn_PRI);
|
||||
NVIC_EnableIRQ((IRQn_Type) RITIMER_IRQn);
|
||||
}
|
||||
|
||||
/* Disable LWIP tick */
|
||||
void SysTick_Disable(void)
|
||||
{
|
||||
Chip_RIT_Disable(LPC_RITIMER);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RITimer IRQ handler and timebase management
|
||||
* @return Nothing
|
||||
* @note This function keeps a timebase for LWIP that can be
|
||||
* used for other functions.
|
||||
*/
|
||||
void RIT_IRQHandler(void)
|
||||
{
|
||||
/* Clear RITimer Interrupt, Reload counter value */
|
||||
Chip_RIT_ClearInt(LPC_RITIMER);
|
||||
Chip_RIT_SetCOMPVAL(LPC_RITIMER, Chip_RIT_GetCounter(LPC_RITIMER) + reload_val);/* Reload value */
|
||||
|
||||
/* Increment tick count */
|
||||
systick_timems += saved_period;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Enable LWIP tick and interrupt */
|
||||
void SysTick_Enable(uint32_t period)
|
||||
{
|
||||
saved_period = period;
|
||||
SysTick_Config((SystemCoreClock * period) / 1000);
|
||||
}
|
||||
|
||||
/* Disable LWIP tick */
|
||||
void SysTick_Disable(void)
|
||||
{
|
||||
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SysTick IRQ handler and timebase management
|
||||
* @return Nothing
|
||||
* @note This function keeps a timebase for LWIP that can be
|
||||
* used for other functions.
|
||||
*/
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
/* Increment tick count */
|
||||
systick_timems += saved_period;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Get the current systick time in milliSeconds */
|
||||
uint32_t SysTick_GetMS(void)
|
||||
{
|
||||
return systick_timems;
|
||||
}
|
||||
|
||||
/* Delay for the specified number of milliSeconds */
|
||||
void msDelay(uint32_t ms)
|
||||
{
|
||||
uint32_t to = ms + systick_timems;
|
||||
|
||||
while (to > systick_timems) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LWIP standalone mode time support
|
||||
* @return Returns the current time in mS
|
||||
* @note Returns the current time in mS. This is needed for the LWIP timers
|
||||
*/
|
||||
u32_t sys_now(void)
|
||||
{
|
||||
return (u32_t) SysTick_GetMS();
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* NO_SYS == 1 */
|
||||
Vendored
+93
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* @brief Architecture specific functions used with the LWIP examples
|
||||
*
|
||||
* @note
|
||||
* Copyright(C) NXP Semiconductors, 2012
|
||||
* All rights reserved.
|
||||
*
|
||||
* @par
|
||||
* Software that is described herein is for illustrative purposes only
|
||||
* which provides customers with programming information regarding the
|
||||
* LPC products. This software is supplied "AS IS" without any warranties of
|
||||
* any kind, and NXP Semiconductors and its licensor disclaim any and
|
||||
* all warranties, express or implied, including all implied warranties of
|
||||
* merchantability, fitness for a particular purpose and non-infringement of
|
||||
* intellectual property rights. NXP Semiconductors assumes no responsibility
|
||||
* or liability for the use of the software, conveys no license or rights under any
|
||||
* patent, copyright, mask work right, or any other intellectual property rights in
|
||||
* or to any products. NXP Semiconductors reserves the right to make changes
|
||||
* in the software without notification. NXP Semiconductors also makes no
|
||||
* representation or warranty that such application will be suitable for the
|
||||
* specified use without further testing or modification.
|
||||
*
|
||||
* @par
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation is hereby granted, under NXP Semiconductors' and its
|
||||
* licensor's relevant copyrights in the software, without fee, provided that it
|
||||
* is used in conjunction with NXP Semiconductors microcontrollers. This
|
||||
* copyright, permission, and disclaimer notice must appear in all copies of
|
||||
* this code.
|
||||
*/
|
||||
|
||||
#ifndef __LPC_ARCH_H_
|
||||
#define __LPC_ARCH_H_
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/** @defgroup NET_LWIP_ARCH Architecture specific functions used with the LWIP examples
|
||||
* @ingroup NET_LWIP
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if NO_SYS == 1
|
||||
/**
|
||||
* @brief Enable LWIP tick and interrupt
|
||||
* @param period : Period of the systick clock
|
||||
* @return Nothing
|
||||
* @note This enables the systick interrupt and sets up the systick rate. This
|
||||
* function is only used in standalone systems.
|
||||
*/
|
||||
void SysTick_Enable(uint32_t period);
|
||||
|
||||
/**
|
||||
* @brief Disable LWIP tick
|
||||
* @return Nothing
|
||||
* This disables the systick interrupt. This function is only used in
|
||||
* standalone systems.
|
||||
*/
|
||||
void SysTick_Disable(void);
|
||||
|
||||
/**
|
||||
* @brief Get the current systick time in milliSeconds
|
||||
* @return current systick time in milliSeconds
|
||||
* @note Returns the current systick time in milliSeconds. This function is only
|
||||
* used in standalone systems.
|
||||
*/
|
||||
uint32_t SysTick_GetMS(void);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Delay for the specified number of milliSeconds
|
||||
* @param ms : Time in milliSeconds to delay
|
||||
* @return Nothing
|
||||
* @note For standalone systems. This function will block for the specified
|
||||
* number of milliSconds. For RTOS based systems, this function will delay
|
||||
* the task by the specified number of milliSeconds.
|
||||
*/
|
||||
void msDelay(uint32_t ms);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LPC_ARCH_H_ */
|
||||
Vendored
+78
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* @brief LWIP debug re-direction
|
||||
*
|
||||
* @note
|
||||
* Copyright(C) NXP Semiconductors, 2012
|
||||
* All rights reserved.
|
||||
*
|
||||
* @par
|
||||
* Software that is described herein is for illustrative purposes only
|
||||
* which provides customers with programming information regarding the
|
||||
* LPC products. This software is supplied "AS IS" without any warranties of
|
||||
* any kind, and NXP Semiconductors and its licensor disclaim any and
|
||||
* all warranties, express or implied, including all implied warranties of
|
||||
* merchantability, fitness for a particular purpose and non-infringement of
|
||||
* intellectual property rights. NXP Semiconductors assumes no responsibility
|
||||
* or liability for the use of the software, conveys no license or rights under any
|
||||
* patent, copyright, mask work right, or any other intellectual property rights in
|
||||
* or to any products. NXP Semiconductors reserves the right to make changes
|
||||
* in the software without notification. NXP Semiconductors also makes no
|
||||
* representation or warranty that such application will be suitable for the
|
||||
* specified use without further testing or modification.
|
||||
*
|
||||
* @par
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation is hereby granted, under NXP Semiconductors' and its
|
||||
* licensor's relevant copyrights in the software, without fee, provided that it
|
||||
* is used in conjunction with NXP Semiconductors microcontrollers. This
|
||||
* copyright, permission, and disclaimer notice must appear in all copies of
|
||||
* this code.
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
/** @defgroup NET_LWIP_DEBUG LWIP debug re-direction
|
||||
* @ingroup NET_LWIP
|
||||
* Support functions for debug output for LWIP
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
|
||||
/*****************************************************************************
|
||||
* Private types/enumerations/variables
|
||||
****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Public types/enumerations/variables
|
||||
****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Private functions
|
||||
****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Public functions
|
||||
****************************************************************************/
|
||||
|
||||
/* Displays an error message on assertion */
|
||||
void assert_printf(char *msg, int line, char *file)
|
||||
{
|
||||
if (msg) {
|
||||
LWIP_DEBUGF(LWIP_DBG_ON, ("%s:%d in file %s\n", msg, line, file));
|
||||
}
|
||||
while (1) {}
|
||||
}
|
||||
|
||||
#else
|
||||
/* LWIP optimized assertion loop (no LWIP_DEBUG) */
|
||||
void assert_loop(void)
|
||||
{
|
||||
while (1) {}
|
||||
}
|
||||
|
||||
#endif /* LWIP_DEBUG */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
Vendored
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
#ifndef __PERF_H__
|
||||
#define __PERF_H__
|
||||
|
||||
#define PERF_START /* null definition */
|
||||
#define PERF_STOP(x) /* null definition */
|
||||
|
||||
#endif /* __PERF_H__ */
|
||||
Vendored
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
#ifndef __ARCH_SYS_ARCH_H__
|
||||
#define __ARCH_SYS_ARCH_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if NO_SYS == 0
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
|
||||
#define SYS_MBOX_NULL ( ( xQueueHandle ) NULL )
|
||||
#define SYS_SEM_NULL ( ( xSemaphoreHandle ) NULL )
|
||||
#define SYS_DEFAULT_THREAD_STACK_DEPTH configMINIMAL_STACK_SIZE
|
||||
|
||||
typedef xSemaphoreHandle sys_sem_t;
|
||||
typedef xSemaphoreHandle sys_mutex_t;
|
||||
typedef xQueueHandle sys_mbox_t;
|
||||
typedef xTaskHandle sys_thread_t;
|
||||
typedef int sys_prot_t;
|
||||
|
||||
#define sys_mbox_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE )
|
||||
#define sys_mbox_set_invalid( x ) ( ( *x ) = NULL )
|
||||
#define sys_sem_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE )
|
||||
#define sys_sem_set_invalid( x ) ( ( *x ) = NULL )
|
||||
#endif
|
||||
|
||||
#endif /* __ARCH_SYS_ARCH_H__ */
|
||||
+544
@@ -0,0 +1,544 @@
|
||||
/*
|
||||
* 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 "lpc_arch.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#if NO_SYS==0
|
||||
/* ------------------------ System architecture includes ----------------------------- */
|
||||
#include "arch/sys_arch.h"
|
||||
|
||||
/* ------------------------ lwIP includes --------------------------------- */
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/stats.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* Routine: sys_mbox_new
|
||||
*---------------------------------------------------------------------------*
|
||||
* Description:
|
||||
* Creates a new mailbox
|
||||
* Inputs:
|
||||
* int size -- Size of elements in the mailbox
|
||||
* Outputs:
|
||||
* sys_mbox_t -- Handle to new mailbox
|
||||
*---------------------------------------------------------------------------*/
|
||||
err_t sys_mbox_new( sys_mbox_t *pxMailBox, int iSize )
|
||||
{
|
||||
err_t xReturn = ERR_MEM;
|
||||
|
||||
*pxMailBox = xQueueCreate( iSize, sizeof( void * ) );
|
||||
|
||||
if( *pxMailBox != NULL )
|
||||
{
|
||||
xReturn = ERR_OK;
|
||||
SYS_STATS_INC_USED( mbox );
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* Routine: sys_mbox_free
|
||||
*---------------------------------------------------------------------------*
|
||||
* Description:
|
||||
* 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.
|
||||
* Inputs:
|
||||
* sys_mbox_t mbox -- Handle of mailbox
|
||||
* Outputs:
|
||||
* sys_mbox_t -- Handle to new mailbox
|
||||
*---------------------------------------------------------------------------*/
|
||||
void sys_mbox_free( sys_mbox_t *pxMailBox )
|
||||
{
|
||||
unsigned long ulMessagesWaiting;
|
||||
|
||||
ulMessagesWaiting = uxQueueMessagesWaiting( *pxMailBox );
|
||||
configASSERT( ( ulMessagesWaiting == 0 ) );
|
||||
|
||||
#if SYS_STATS
|
||||
{
|
||||
if( ulMessagesWaiting != 0UL )
|
||||
{
|
||||
SYS_STATS_INC( mbox.err );
|
||||
}
|
||||
|
||||
SYS_STATS_DEC( mbox.used );
|
||||
}
|
||||
#endif /* SYS_STATS */
|
||||
|
||||
vQueueDelete( *pxMailBox );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* Routine: sys_mbox_post
|
||||
*---------------------------------------------------------------------------*
|
||||
* Description:
|
||||
* Post the "msg" to the mailbox.
|
||||
* Inputs:
|
||||
* sys_mbox_t mbox -- Handle of mailbox
|
||||
* void *data -- Pointer to data to post
|
||||
*---------------------------------------------------------------------------*/
|
||||
void sys_mbox_post( sys_mbox_t *pxMailBox, void *pxMessageToPost )
|
||||
{
|
||||
while( xQueueSendToBack( *pxMailBox, &pxMessageToPost, portMAX_DELAY ) != pdTRUE );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* Routine: sys_mbox_trypost
|
||||
*---------------------------------------------------------------------------*
|
||||
* Description:
|
||||
* Try to post the "msg" to the mailbox. Returns immediately with
|
||||
* error if cannot.
|
||||
* Inputs:
|
||||
* sys_mbox_t mbox -- Handle of mailbox
|
||||
* void *msg -- Pointer to data to post
|
||||
* Outputs:
|
||||
* err_t -- ERR_OK if message posted, else ERR_MEM
|
||||
* if not.
|
||||
*---------------------------------------------------------------------------*/
|
||||
err_t sys_mbox_trypost( sys_mbox_t *pxMailBox, void *pxMessageToPost )
|
||||
{
|
||||
err_t xReturn;
|
||||
|
||||
if( xQueueSend( *pxMailBox, &pxMessageToPost, 0UL ) == pdPASS )
|
||||
{
|
||||
xReturn = ERR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The queue was already full. */
|
||||
xReturn = ERR_MEM;
|
||||
SYS_STATS_INC( mbox.err );
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* Routine: sys_arch_mbox_fetch
|
||||
*---------------------------------------------------------------------------*
|
||||
* Description:
|
||||
* 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.
|
||||
* Inputs:
|
||||
* sys_mbox_t mbox -- Handle of mailbox
|
||||
* void **msg -- Pointer to pointer to msg received
|
||||
* u32_t timeout -- Number of milliseconds until timeout
|
||||
* Outputs:
|
||||
* u32_t -- SYS_ARCH_TIMEOUT if timeout, else number
|
||||
* of milliseconds until received.
|
||||
*---------------------------------------------------------------------------*/
|
||||
u32_t sys_arch_mbox_fetch( sys_mbox_t *pxMailBox, void **ppvBuffer, u32_t ulTimeOut )
|
||||
{
|
||||
void *pvDummy;
|
||||
portTickType xStartTime, xEndTime, xElapsed;
|
||||
unsigned long ulReturn;
|
||||
|
||||
xStartTime = xTaskGetTickCount();
|
||||
|
||||
if( NULL == ppvBuffer )
|
||||
{
|
||||
ppvBuffer = &pvDummy;
|
||||
}
|
||||
|
||||
if( ulTimeOut != 0UL )
|
||||
{
|
||||
if( pdTRUE == xQueueReceive( *pxMailBox, &( *ppvBuffer ), ulTimeOut/ portTICK_RATE_MS ) )
|
||||
{
|
||||
xEndTime = xTaskGetTickCount();
|
||||
xElapsed = ( xEndTime - xStartTime ) * portTICK_RATE_MS;
|
||||
|
||||
ulReturn = xElapsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Timed out. */
|
||||
*ppvBuffer = NULL;
|
||||
ulReturn = SYS_ARCH_TIMEOUT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while( pdTRUE != xQueueReceive( *pxMailBox, &( *ppvBuffer ), portMAX_DELAY ) );
|
||||
xEndTime = xTaskGetTickCount();
|
||||
xElapsed = ( xEndTime - xStartTime ) * portTICK_RATE_MS;
|
||||
|
||||
if( xElapsed == 0UL )
|
||||
{
|
||||
xElapsed = 1UL;
|
||||
}
|
||||
|
||||
ulReturn = xElapsed;
|
||||
}
|
||||
|
||||
return ulReturn;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* Routine: sys_arch_mbox_tryfetch
|
||||
*---------------------------------------------------------------------------*
|
||||
* Description:
|
||||
* 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.
|
||||
* Inputs:
|
||||
* sys_mbox_t mbox -- Handle of mailbox
|
||||
* void **msg -- Pointer to pointer to msg received
|
||||
* Outputs:
|
||||
* u32_t -- SYS_MBOX_EMPTY if no messages. Otherwise,
|
||||
* return ERR_OK.
|
||||
*---------------------------------------------------------------------------*/
|
||||
u32_t sys_arch_mbox_tryfetch( sys_mbox_t *pxMailBox, void **ppvBuffer )
|
||||
{
|
||||
void *pvDummy;
|
||||
unsigned long ulReturn;
|
||||
|
||||
if( ppvBuffer== NULL )
|
||||
{
|
||||
ppvBuffer = &pvDummy;
|
||||
}
|
||||
|
||||
if( pdTRUE == xQueueReceive( *pxMailBox, &( *ppvBuffer ), 0UL ) )
|
||||
{
|
||||
ulReturn = ERR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulReturn = SYS_MBOX_EMPTY;
|
||||
}
|
||||
|
||||
return ulReturn;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* Routine: sys_sem_new
|
||||
*---------------------------------------------------------------------------*
|
||||
* Description:
|
||||
* Creates and returns a new semaphore. The "ucCount" argument specifies
|
||||
* the initial state of the semaphore.
|
||||
* NOTE: Currently this routine only creates counts of 1 or 0
|
||||
* Inputs:
|
||||
* sys_mbox_t mbox -- Handle of mailbox
|
||||
* u8_t ucCount -- Initial ucCount of semaphore (1 or 0)
|
||||
* Outputs:
|
||||
* sys_sem_t -- Created semaphore or 0 if could not create.
|
||||
*---------------------------------------------------------------------------*/
|
||||
err_t sys_sem_new( sys_sem_t *pxSemaphore, u8_t ucCount )
|
||||
{
|
||||
err_t xReturn = ERR_MEM;
|
||||
|
||||
vSemaphoreCreateBinary( ( *pxSemaphore ) );
|
||||
|
||||
if( *pxSemaphore != NULL )
|
||||
{
|
||||
if( ucCount == 0U )
|
||||
{
|
||||
xSemaphoreTake( *pxSemaphore, 1UL );
|
||||
}
|
||||
|
||||
xReturn = ERR_OK;
|
||||
SYS_STATS_INC_USED( sem );
|
||||
}
|
||||
else
|
||||
{
|
||||
SYS_STATS_INC( sem.err );
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* Routine: sys_arch_sem_wait
|
||||
*---------------------------------------------------------------------------*
|
||||
* Description:
|
||||
* 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.
|
||||
* Inputs:
|
||||
* sys_sem_t sem -- Semaphore to wait on
|
||||
* u32_t timeout -- Number of milliseconds until timeout
|
||||
* Outputs:
|
||||
* u32_t -- Time elapsed or SYS_ARCH_TIMEOUT.
|
||||
*---------------------------------------------------------------------------*/
|
||||
u32_t sys_arch_sem_wait( sys_sem_t *pxSemaphore, u32_t ulTimeout )
|
||||
{
|
||||
portTickType xStartTime, xEndTime, xElapsed;
|
||||
unsigned long ulReturn;
|
||||
|
||||
xStartTime = xTaskGetTickCount();
|
||||
|
||||
if( ulTimeout != 0UL )
|
||||
{
|
||||
if( xSemaphoreTake( *pxSemaphore, ulTimeout / portTICK_RATE_MS ) == pdTRUE )
|
||||
{
|
||||
xEndTime = xTaskGetTickCount();
|
||||
xElapsed = (xEndTime - xStartTime) * portTICK_RATE_MS;
|
||||
ulReturn = xElapsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulReturn = SYS_ARCH_TIMEOUT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while( xSemaphoreTake( *pxSemaphore, portMAX_DELAY ) != pdTRUE );
|
||||
xEndTime = xTaskGetTickCount();
|
||||
xElapsed = ( xEndTime - xStartTime ) * portTICK_RATE_MS;
|
||||
|
||||
if( xElapsed == 0UL )
|
||||
{
|
||||
xElapsed = 1UL;
|
||||
}
|
||||
|
||||
ulReturn = xElapsed;
|
||||
}
|
||||
|
||||
return ulReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a new mutex
|
||||
* @param pxMutex pointer to the mutex to create
|
||||
* @return a new mutex
|
||||
*/
|
||||
err_t sys_mutex_new( sys_mutex_t *pxMutex )
|
||||
{
|
||||
err_t xReturn = ERR_MEM;
|
||||
|
||||
*pxMutex = xSemaphoreCreateMutex();
|
||||
|
||||
if( *pxMutex != NULL )
|
||||
{
|
||||
xReturn = ERR_OK;
|
||||
SYS_STATS_INC_USED( mutex );
|
||||
}
|
||||
else
|
||||
{
|
||||
SYS_STATS_INC( mutex.err );
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
/** Lock a mutex
|
||||
* @param pxMutex the mutex to lock */
|
||||
void sys_mutex_lock( sys_mutex_t *pxMutex )
|
||||
{
|
||||
while( xSemaphoreTake( *pxMutex, portMAX_DELAY ) != pdPASS );
|
||||
}
|
||||
|
||||
/** Unlock a mutex
|
||||
* @param pxMutex the mutex to unlock */
|
||||
void sys_mutex_unlock(sys_mutex_t *pxMutex )
|
||||
{
|
||||
xSemaphoreGive( *pxMutex );
|
||||
}
|
||||
|
||||
|
||||
/** Delete a semaphore
|
||||
* @param pxMutex the mutex to delete */
|
||||
void sys_mutex_free( sys_mutex_t *pxMutex )
|
||||
{
|
||||
SYS_STATS_DEC( mutex.used );
|
||||
vQueueDelete( *pxMutex );
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* Routine: sys_sem_signal
|
||||
*---------------------------------------------------------------------------*
|
||||
* Description:
|
||||
* Signals (releases) a semaphore
|
||||
* Inputs:
|
||||
* sys_sem_t sem -- Semaphore to signal
|
||||
*---------------------------------------------------------------------------*/
|
||||
void sys_sem_signal( sys_sem_t *pxSemaphore )
|
||||
{
|
||||
xSemaphoreGive( *pxSemaphore );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* Routine: sys_sem_free
|
||||
*---------------------------------------------------------------------------*
|
||||
* Description:
|
||||
* Deallocates a semaphore
|
||||
* Inputs:
|
||||
* sys_sem_t sem -- Semaphore to free
|
||||
*---------------------------------------------------------------------------*/
|
||||
void sys_sem_free( sys_sem_t *pxSemaphore )
|
||||
{
|
||||
SYS_STATS_DEC(sem.used);
|
||||
vQueueDelete( *pxSemaphore );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* Routine: sys_init
|
||||
*---------------------------------------------------------------------------*
|
||||
* Description:
|
||||
* Initialize sys arch
|
||||
*---------------------------------------------------------------------------*/
|
||||
void sys_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
u32_t sys_now(void)
|
||||
{
|
||||
return xTaskGetTickCount();
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* Routine: sys_thread_new
|
||||
*---------------------------------------------------------------------------*
|
||||
* Description:
|
||||
* 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.
|
||||
* Inputs:
|
||||
* char *name -- Name of thread
|
||||
* void (* thread)(void *arg) -- Pointer to function to run.
|
||||
* void *arg -- Argument passed into function
|
||||
* int stacksize -- Required stack amount in bytes
|
||||
* int prio -- Thread priority
|
||||
* Outputs:
|
||||
* sys_thread_t -- Pointer to per-thread timeouts.
|
||||
*---------------------------------------------------------------------------*/
|
||||
sys_thread_t sys_thread_new( const char *pcName, void( *pxThread )( void *pvParameters ), void *pvArg, int iStackSize, int iPriority )
|
||||
{
|
||||
xTaskHandle xCreatedTask;
|
||||
portBASE_TYPE xResult;
|
||||
sys_thread_t xReturn;
|
||||
|
||||
xResult = xTaskCreate( pxThread, ( signed char * ) pcName, iStackSize, pvArg, iPriority, &xCreatedTask );
|
||||
|
||||
if( xResult == pdPASS )
|
||||
{
|
||||
xReturn = xCreatedTask;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = NULL;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* Routine: sys_arch_protect
|
||||
*---------------------------------------------------------------------------*
|
||||
* Description:
|
||||
* 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.
|
||||
* Outputs:
|
||||
* sys_prot_t -- Previous protection level (not used here)
|
||||
*---------------------------------------------------------------------------*/
|
||||
sys_prot_t sys_arch_protect( void )
|
||||
{
|
||||
vPortEnterCritical();
|
||||
return ( sys_prot_t ) 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* Routine: sys_arch_unprotect
|
||||
*---------------------------------------------------------------------------*
|
||||
* Description:
|
||||
* 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.
|
||||
* Inputs:
|
||||
* sys_prot_t -- Previous protection level (not used here)
|
||||
*---------------------------------------------------------------------------*/
|
||||
void sys_arch_unprotect( sys_prot_t xValue )
|
||||
{
|
||||
(void) xValue;
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints an assertion messages and aborts execution.
|
||||
*/
|
||||
void sys_assert( const char *pcMessage )
|
||||
{
|
||||
(void) pcMessage;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
}
|
||||
}
|
||||
/*-------------------------------------------------------------------------*
|
||||
* End of File: sys_arch.c
|
||||
*-------------------------------------------------------------------------*/
|
||||
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
Reference in New Issue
Block a user