LPC546XX: Add ENET support

Signed-off-by: Mahadevan Mahesh <Mahesh.Mahadevan@nxp.com>
pull/5609/head
Mahadevan Mahesh 2017-09-22 11:03:50 -05:00 committed by Martin Kojtal
parent 70e7b40468
commit f2d2ed44cd
17 changed files with 1957 additions and 0 deletions

View File

@ -0,0 +1,261 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fsl_iocon.h"
#define IOCON_PIO_DIGITAL_EN 0x0100u /*!<@brief Enables digital function */
#define IOCON_PIO_FUNC0 0x00u /*!<@brief Selects pin function 0 */
#define IOCON_PIO_FUNC1 0x01u /*!<@brief Selects pin function 1 */
#define IOCON_PIO_FUNC6 0x06u /*!<@brief Selects pin function 6 */
#define IOCON_PIO_FUNC7 0x07u /*!<@brief Selects pin function 7 */
#define IOCON_PIO_INPFILT_OFF 0x0200u /*!<@brief Input filter disabled */
#define IOCON_PIO_INV_DI 0x00u /*!<@brief Input function is not inverted */
#define IOCON_PIO_MODE_INACT 0x00u /*!<@brief No addition pin function */
#define IOCON_PIO_MODE_PULLUP 0x20u /*!<@brief Selects pull-up function */
#define IOCON_PIO_OPENDRAIN_DI 0x00u /*!<@brief Open drain is disabled */
#define IOCON_PIO_SLEW_FAST 0x0400u /*!<@brief Fast mode, slew rate control is disabled */
#define IOCON_PIO_SLEW_STANDARD 0x00u /*!<@brief Standard mode, output slew rate control is enabled */
/*******************************************************************************
* Code
******************************************************************************/
void lpc546xx_init_eth_hardware(void)
{
CLOCK_EnableClock(kCLOCK_InputMux);
/* Enables the clock for the IOCON block. 0 = Disable; 1 = Enable.: 0x01u */
CLOCK_EnableClock(kCLOCK_Iocon);
const uint32_t port0_pin10_config = (/* Pin is configured as SWO */
IOCON_PIO_FUNC6 |
/* No addition pin function */
IOCON_PIO_MODE_INACT |
/* Input function is not inverted */
IOCON_PIO_INV_DI |
/* Enables digital function */
IOCON_PIO_DIGITAL_EN |
/* Input filter disabled */
IOCON_PIO_INPFILT_OFF |
/* Open drain is disabled */
IOCON_PIO_OPENDRAIN_DI);
/* PORT0 PIN10 (coords: P2) is configured as SWO */
IOCON_PinMuxSet(IOCON, 0U, 10U, port0_pin10_config);
const uint32_t port0_pin17_config = (/* Pin is configured as ENET_TXD1 */
IOCON_PIO_FUNC7 |
/* No addition pin function */
IOCON_PIO_MODE_INACT |
/* Input function is not inverted */
IOCON_PIO_INV_DI |
/* Enables digital function */
IOCON_PIO_DIGITAL_EN |
/* Input filter disabled */
IOCON_PIO_INPFILT_OFF |
/* Standard mode, output slew rate control is enabled */
IOCON_PIO_SLEW_STANDARD |
/* Open drain is disabled */
IOCON_PIO_OPENDRAIN_DI);
/* PORT0 PIN17 (coords: E14) is configured as ENET_TXD1 */
IOCON_PinMuxSet(IOCON, 0U, 17U, port0_pin17_config);
const uint32_t port0_pin29_config = (/* Pin is configured as FC0_RXD_SDA_MOSI */
IOCON_PIO_FUNC1 |
/* No addition pin function */
IOCON_PIO_MODE_INACT |
/* Input function is not inverted */
IOCON_PIO_INV_DI |
/* Enables digital function */
IOCON_PIO_DIGITAL_EN |
/* Input filter disabled */
IOCON_PIO_INPFILT_OFF |
/* Fast mode, slew rate control is disabled */
IOCON_PIO_SLEW_FAST |
/* Open drain is disabled */
IOCON_PIO_OPENDRAIN_DI);
/* PORT0 PIN29 (coords: B13) is configured as FC0_RXD_SDA_MOSI */
IOCON_PinMuxSet(IOCON, 0U, 29U, port0_pin29_config);
const uint32_t port0_pin30_config = (/* Pin is configured as FC0_TXD_SCL_MISO */
IOCON_PIO_FUNC1 |
/* No addition pin function */
IOCON_PIO_MODE_INACT |
/* Input function is not inverted */
IOCON_PIO_INV_DI |
/* Enables digital function */
IOCON_PIO_DIGITAL_EN |
/* Input filter disabled */
IOCON_PIO_INPFILT_OFF |
/* Fast mode, slew rate control is disabled */
IOCON_PIO_SLEW_FAST |
/* Open drain is disabled */
IOCON_PIO_OPENDRAIN_DI);
/* PORT0 PIN30 (coords: A2) is configured as FC0_TXD_SCL_MISO */
IOCON_PinMuxSet(IOCON, 0U, 30U, port0_pin30_config);
const uint32_t port2_pin26_config = (/* Pin is configured as PIO2_26 */
IOCON_PIO_FUNC0 |
/* Selects pull-up function */
IOCON_PIO_MODE_PULLUP |
/* Input function is not inverted */
IOCON_PIO_INV_DI |
/* Enables digital function */
IOCON_PIO_DIGITAL_EN |
/* Input filter disabled */
IOCON_PIO_INPFILT_OFF |
/* Standard mode, output slew rate control is enabled */
IOCON_PIO_SLEW_STANDARD |
/* Open drain is disabled */
IOCON_PIO_OPENDRAIN_DI);
/* PORT2 PIN26 (coords: H11) is configured as PIO2_26 */
IOCON_PinMuxSet(IOCON, 2U, 26U, port2_pin26_config);
const uint32_t port4_pin10_config = (/* Pin is configured as ENET_RX_DV */
IOCON_PIO_FUNC1 |
/* No addition pin function */
IOCON_PIO_MODE_INACT |
/* Input function is not inverted */
IOCON_PIO_INV_DI |
/* Enables digital function */
IOCON_PIO_DIGITAL_EN |
/* Input filter disabled */
IOCON_PIO_INPFILT_OFF |
/* Standard mode, output slew rate control is enabled */
IOCON_PIO_SLEW_STANDARD |
/* Open drain is disabled */
IOCON_PIO_OPENDRAIN_DI);
/* PORT4 PIN10 (coords: B9) is configured as ENET_RX_DV */
IOCON_PinMuxSet(IOCON, 4U, 10U, port4_pin10_config);
const uint32_t port4_pin11_config = (/* Pin is configured as ENET_RXD0 */
IOCON_PIO_FUNC1 |
/* No addition pin function */
IOCON_PIO_MODE_INACT |
/* Input function is not inverted */
IOCON_PIO_INV_DI |
/* Enables digital function */
IOCON_PIO_DIGITAL_EN |
/* Input filter disabled */
IOCON_PIO_INPFILT_OFF |
/* Standard mode, output slew rate control is enabled */
IOCON_PIO_SLEW_STANDARD |
/* Open drain is disabled */
IOCON_PIO_OPENDRAIN_DI);
/* PORT4 PIN11 (coords: A9) is configured as ENET_RXD0 */
IOCON_PinMuxSet(IOCON, 4U, 11U, port4_pin11_config);
const uint32_t port4_pin12_config = (/* Pin is configured as ENET_RXD1 */
IOCON_PIO_FUNC1 |
/* No addition pin function */
IOCON_PIO_MODE_INACT |
/* Input function is not inverted */
IOCON_PIO_INV_DI |
/* Enables digital function */
IOCON_PIO_DIGITAL_EN |
/* Input filter disabled */
IOCON_PIO_INPFILT_OFF |
/* Standard mode, output slew rate control is enabled */
IOCON_PIO_SLEW_STANDARD |
/* Open drain is disabled */
IOCON_PIO_OPENDRAIN_DI);
/* PORT4 PIN12 (coords: A6) is configured as ENET_RXD1 */
IOCON_PinMuxSet(IOCON, 4U, 12U, port4_pin12_config);
const uint32_t port4_pin13_config = (/* Pin is configured as ENET_TX_EN */
IOCON_PIO_FUNC1 |
/* No addition pin function */
IOCON_PIO_MODE_INACT |
/* Input function is not inverted */
IOCON_PIO_INV_DI |
/* Enables digital function */
IOCON_PIO_DIGITAL_EN |
/* Input filter disabled */
IOCON_PIO_INPFILT_OFF |
/* Standard mode, output slew rate control is enabled */
IOCON_PIO_SLEW_STANDARD |
/* Open drain is disabled */
IOCON_PIO_OPENDRAIN_DI);
/* PORT4 PIN13 (coords: B6) is configured as ENET_TX_EN */
IOCON_PinMuxSet(IOCON, 4U, 13U, port4_pin13_config);
const uint32_t port4_pin14_config = (/* Pin is configured as ENET_RX_CLK */
IOCON_PIO_FUNC1 |
/* No addition pin function */
IOCON_PIO_MODE_INACT |
/* Input function is not inverted */
IOCON_PIO_INV_DI |
/* Enables digital function */
IOCON_PIO_DIGITAL_EN |
/* Input filter disabled */
IOCON_PIO_INPFILT_OFF |
/* Standard mode, output slew rate control is enabled */
IOCON_PIO_SLEW_STANDARD |
/* Open drain is disabled */
IOCON_PIO_OPENDRAIN_DI);
/* PORT4 PIN14 (coords: B5) is configured as ENET_RX_CLK */
IOCON_PinMuxSet(IOCON, 4U, 14U, port4_pin14_config);
const uint32_t port4_pin15_config = (/* Pin is configured as ENET_MDC */
IOCON_PIO_FUNC1 |
/* No addition pin function */
IOCON_PIO_MODE_INACT |
/* Input function is not inverted */
IOCON_PIO_INV_DI |
/* Enables digital function */
IOCON_PIO_DIGITAL_EN |
/* Input filter disabled */
IOCON_PIO_INPFILT_OFF |
/* Standard mode, output slew rate control is enabled */
IOCON_PIO_SLEW_STANDARD |
/* Open drain is disabled */
IOCON_PIO_OPENDRAIN_DI);
/* PORT4 PIN15 (coords: A4) is configured as ENET_MDC */
IOCON_PinMuxSet(IOCON, 4U, 15U, port4_pin15_config);
const uint32_t port4_pin16_config = (/* Pin is configured as ENET_MDIO */
IOCON_PIO_FUNC1 |
/* No addition pin function */
IOCON_PIO_MODE_INACT |
/* Input function is not inverted */
IOCON_PIO_INV_DI |
/* Enables digital function */
IOCON_PIO_DIGITAL_EN |
/* Input filter disabled */
IOCON_PIO_INPFILT_OFF |
/* Standard mode, output slew rate control is enabled */
IOCON_PIO_SLEW_STANDARD |
/* Open drain is disabled */
IOCON_PIO_OPENDRAIN_DI);
/* PORT4 PIN16 (coords: C4) is configured as ENET_MDIO */
IOCON_PinMuxSet(IOCON, 4U, 16U, port4_pin16_config);
const uint32_t port4_pin8_config = (/* Pin is configured as ENET_TXD0 */
IOCON_PIO_FUNC1 |
/* No addition pin function */
IOCON_PIO_MODE_INACT |
/* Input function is not inverted */
IOCON_PIO_INV_DI |
/* Enables digital function */
IOCON_PIO_DIGITAL_EN |
/* Input filter disabled */
IOCON_PIO_INPFILT_OFF |
/* Standard mode, output slew rate control is enabled */
IOCON_PIO_SLEW_STANDARD |
/* Open drain is disabled */
IOCON_PIO_OPENDRAIN_DI);
/* PORT4 PIN8 (coords: B14) is configured as ENET_TXD0 */
IOCON_PinMuxSet(IOCON, 4U, 8U, port4_pin8_config);
}

View File

@ -0,0 +1,692 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#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 "lwip/tcpip.h"
#include "lwip/ethip6.h"
#include "netif/etharp.h"
#include "netif/ppp/pppoe.h"
#include "eth_arch.h"
#include "sys_arch.h"
#include "fsl_phy.h"
#include "lpc546xx_emac_config.h"
#include <string.h>
#include "mbed_interface.h"
#if LWIP_ARP || LWIP_ETHERNET
enet_handle_t g_handle;
// RX packet buffer pointers
struct pbuf *rx_buff[ENET_RX_RING_LEN];
// TX packet buffer pointers
uint8_t *tx_buff[ENET_TX_RING_LEN];
// RX packet payload pointers
uint32_t rx_ptr[ENET_RX_RING_LEN];
/** \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
/* LPC546XX EMAC driver data structure */
struct lpc_enetdata {
struct netif *netif; /**< Reference back to LWIP parent netif */
osThreadId_t thread; /**< Processing thread */
sys_mutex_t TXLockMutex; /**< TX critical section mutex */
sys_sem_t xTXDCountSem; /**< TX free buffer counting semaphore */
};
static struct lpc_enetdata lpc_enetdata;
/* \brief Flags for worker thread */
#define FLAG_TX 1
#define FLAG_RX 2
/** \brief Driver thread priority */
#define THREAD_PRIORITY (osPriorityNormal)
#ifdef LWIP_DEBUG
#define THREAD_STACKSIZE (DEFAULT_THREAD_STACKSIZE * 5)
#else
#define THREAD_STACKSIZE DEFAULT_THREAD_STACKSIZE
#endif
static void lpc546xx_phy_task(void *data);
static void lpc546xx_packet_rx(struct lpc_enetdata *lpc_enet);
static void lpc546xx_packet_tx(struct lpc_enetdata *lpc_enet);
#define PHY_TASK_PERIOD_MS 200
/********************************************************************************
* Buffer management
********************************************************************************/
/*
* This function will queue a new receive buffer
*/
static void update_read_buffer(enet_rx_bd_struct_t *rxDesc, uint8_t *buf)
{
enet_rx_bd_ring_t *rxBdRing = (enet_rx_bd_ring_t *)&g_handle.rxBdRing[0];
uint32_t control = ENET_RXDESCRIP_RD_OWN_MASK | ENET_RXDESCRIP_RD_BUFF1VALID_MASK | ENET_RXDESCRIP_RD_IOC_MASK;
uint32_t index = rxBdRing->rxGenIdx;
/* Increase the index. */
index++;
if (index >= ENET_RX_RING_LEN) {
index = 0;
}
rxBdRing->rxGenIdx = index;
if (buf != NULL) {
rxDesc->buff1Addr = (uint32_t)buf;
}
rxDesc->buff2Addr = 0;
rxDesc->reserved = 0;
rxDesc->control = control;
}
/** \brief Free TX buffers that are complete
*
* \param[in] lpc_enet Pointer to driver data structure
*/
static void lpc546xx_tx_reclaim(struct lpc_enetdata *lpc_enet)
{
static uint8_t consume_index = 0;
enet_tx_bd_ring_t *txBdRing = (enet_tx_bd_ring_t *)&g_handle.txBdRing[0];
while (consume_index != txBdRing->txConsumIdx) {
/* Free the transmit buffer */
free(tx_buff[consume_index]);
tx_buff[consume_index] = NULL;
osSemaphoreRelease(lpc_enetdata.xTXDCountSem.id);
consume_index++;
if (consume_index >= ENET_TX_RING_LEN) {
consume_index = 0;
}
}
}
/********************************************************************************
* Internal data
********************************************************************************/
#define ENET_BuffSizeAlign(n) ENET_ALIGN(n, ENET_BUFF_ALIGNMENT)
#define ENET_ALIGN(x,align) ((unsigned int)((x) + ((align)-1)) & (unsigned int)(~(unsigned int)((align)- 1)))
extern void lpc546xx_init_eth_hardware(void);
/** \brief Allocates a pbuf and returns the data from the incoming packet.
*
* \param[in] netif the lwip network interface structure for this lpc_enetif
* \return a pbuf filled with the received packet (including MAC header)
* NULL on memory error
*/
static struct pbuf *lpc546xx_low_level_input(struct netif *netif)
{
enet_rx_bd_ring_t *rxBdRing = (enet_rx_bd_ring_t *)&g_handle.rxBdRing[0];
enet_rx_bd_struct_t *bdPtr = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
#ifdef LOCK_RX_THREAD
struct lpc_enetdata *lpc_enet = netif->state;
#endif
struct pbuf *p = NULL;
struct pbuf *temp_rxbuf = NULL;
u32_t length = 0;
/* Determine if a frame has been received */
if ((bdPtr->control & ENET_RXDESCRIP_WR_OWN_MASK) != 0) {
return p;
}
#ifdef LOCK_RX_THREAD
/* Get exclusive access */
sys_mutex_lock(&lpc_enet->TXLockMutex);
#endif
/* Determine if the received frame has an error */
if ((bdPtr->control & ENET_RXDESCRIP_WR_ERRSUM_MASK) != 0) {
LINK_STATS_INC(link.err);
LINK_STATS_INC(link.drop);
/* Re-use the same buffer in case of error */
update_read_buffer(bdPtr, NULL);
} else {
if (bdPtr->control & ENET_RXDESCRIP_WR_LD_MASK) {
length = (bdPtr->control & ENET_RXDESCRIP_WR_PACKETLEN_MASK);
} else {
length = rxBdRing->rxBuffSizeAlign;
}
/* Zero-copy */
p = rx_buff[rxBdRing->rxGenIdx];
p->len = length;
/* Attempt to queue new buffer */
temp_rxbuf = pbuf_alloc(PBUF_RAW, ENET_ALIGN(ENET_ETH_MAX_FLEN, ENET_BUFF_ALIGNMENT), PBUF_RAM);
if (NULL == temp_rxbuf) {
/* Drop frame (out of memory) */
LINK_STATS_INC(link.drop);
LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
("lpc546xx_low_level_input: Packet index %d dropped for OOM\n", rxBdRing->rxGenIdx));
/* Re-queue the same buffer */
update_read_buffer(bdPtr, NULL);
#ifdef LOCK_RX_THREAD
sys_mutex_unlock(&lpc_enet->TXLockMutex);
#endif
return NULL;
}
rx_buff[rxBdRing->rxGenIdx] = temp_rxbuf;
rx_ptr[rxBdRing->rxGenIdx] = (uint32_t)rx_buff[rxBdRing->rxGenIdx]->payload;
LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
("lpc_low_level_input: Packet received: %p, size %"PRIu32" (index=%d)\n", p, length, rxBdRing->rxGenIdx));
update_read_buffer(bdPtr, rx_buff[rxBdRing->rxGenIdx]->payload);
/* Save size */
p->tot_len = (u16_t)length;
LINK_STATS_INC(link.recv);
}
#ifdef LOCK_RX_THREAD
sys_mutex_unlock(&lpc_enet->TXLockMutex);
#endif
return p;
}
/** \brief Attempt to read a packet from the EMAC interface.
*
* \param[in] netif the lwip network interface structure
*/
void lpc546xx_enetif_input(struct netif *netif)
{
struct pbuf *p;
/* move received packet into a new pbuf */
p = lpc546xx_low_level_input(netif);
if (p == NULL)
return;
/* pass all packets to ethernet_input, which decides what packets it supports */
if (netif->input(p, netif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("lpc546xx_enetif_input: input error\n"));
/* Free buffer */
pbuf_free(p);
}
}
/** \brief Worker thread.
*
* Woken by thread flags to receive packets or clean up transmit
*
* \param[in] pvParameters pointer to the interface data
*/
static void lpc546xx_emac_thread(void* pvParameters)
{
struct lpc_enetdata *lpc_enet = pvParameters;
for (;;) {
uint32_t flags = osThreadFlagsWait(FLAG_RX | FLAG_TX, osFlagsWaitAny, PHY_TASK_PERIOD_MS);
if (flags == osFlagsErrorTimeout) {
// Rather than calling strictly every period, we call when idle
// for that period - hopefully good enough. We run this task
// from lwIP's thread rather than our RX/TX thread, as PHY reads can
// be slow, and we don't want them to interfere with data pumping.
// This is analogous to the way the PHY polling works in the Nanostack
// version of the driver
tcpip_callback_with_block(lpc546xx_phy_task, lpc_enet->netif, 0);
continue;
}
LWIP_ASSERT("osThreadFlagsWait error", !(flags & osFlagsError));
if (flags & FLAG_RX) {
lpc546xx_packet_rx(lpc_enet);
}
if (flags & FLAG_TX) {
lpc546xx_packet_tx(lpc_enet);
}
}
}
/** \brief Low level output of a packet. Never call this from an
* interrupt context, as it may block until TX descriptors
* become available.
*
* \param[in] netif the lwip network interface structure for this lpc_enetif
* \param[in] p the MAC packet to send (e.g. IP packet including MAC addresses and type)
* \return ERR_OK if the packet could be sent or an err_t value if the packet couldn't be sent
*/
static err_t lpc546xx_low_level_output(struct netif *netif, struct pbuf *p)
{
struct lpc_enetdata *lpc_enet = netif->state;
struct pbuf *q;
uint8_t *psend = NULL, *dst;
enet_tx_bd_ring_t *txBdRing = (enet_tx_bd_ring_t *)&g_handle.txBdRing[0];
uint32_t index = txBdRing->txGenIdx;
psend = (uint8_t *)calloc(1, ENET_ALIGN(p->tot_len, ENET_BUFF_ALIGNMENT));
if (NULL == psend)
return ERR_MEM;
if (p->len == p->tot_len) {
MEMCPY(psend, p->payload, p->len);
} else {
for (q = p, dst = psend; q != NULL; q = q->next) {
MEMCPY(dst, q->payload, q->len);
dst += q->len;
}
}
/* Check if a descriptor is available for the transfer. */
osStatus_t stat = osSemaphoreAcquire(lpc_enet->xTXDCountSem.id, 0);
if (stat != osOK)
return ERR_BUF;
/* Save the buffer so that it can be freed when transmit is done */
tx_buff[index] = psend;
if (ENET_SendFrame(ENET, &g_handle, psend, p->tot_len) != kStatus_Success) {
free(psend);
tx_buff[index] = NULL;
return ERR_IF;
}
LINK_STATS_INC(link.xmit);
return ERR_OK;
}
/** \brief Ethernet receive interrupt handler
*
* This function handles the receive interrupt of LPC546XX.
*/
void enet_mac_rx_isr()
{
osThreadFlagsSet(lpc_enetdata.thread, FLAG_RX);
}
void enet_mac_tx_isr()
{
osThreadFlagsSet(lpc_enetdata.thread, FLAG_TX);
}
void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event_t event, uint8_t channel, void *param)
{
switch (event)
{
case kENET_RxIntEvent:
enet_mac_rx_isr();
break;
case kENET_TxIntEvent:
enet_mac_tx_isr();
break;
default:
break;
}
}
#if NO_SYS == 0
/** \brief Packet reception task
*
* This task is called when a packet is received. It will
* pass the packet to the LWIP core.
*
* \param[in] lpc_enet pointer to the interface data
*/
static void lpc546xx_packet_rx(struct lpc_enetdata *lpc_enet)
{
enet_rx_bd_ring_t *rxBdRing = (enet_rx_bd_ring_t *)&g_handle.rxBdRing[0];
enet_rx_bd_struct_t *bdPtr = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
bool suspend = false;
/* Suspend and command for rx. */
if (ENET->DMA_CH[0].DMA_CHX_STAT & ENET_DMA_CH_DMA_CHX_STAT_RBU_MASK) {
suspend = true;
}
while ((bdPtr->control & ENET_RXDESCRIP_WR_OWN_MASK) == 0) {
lpc546xx_enetif_input(lpc_enet->netif);
/* rxGenIdx gets updated, gets the next receive buffer descriptor */
bdPtr = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
}
/* Set command for rx when it is suspend. */
if (suspend)
{
ENET->DMA_CH[0].DMA_CHX_RXDESC_TAIL_PTR = ENET->DMA_CH[0].DMA_CHX_RXDESC_TAIL_PTR;
}
}
/** \brief 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.
*
* \param[in] lpc_enet pointer to the interface data
*/
static void lpc546xx_packet_tx(struct lpc_enetdata *lpc_enet)
{
lpc546xx_tx_reclaim(lpc_enet);
}
#endif
/** \brief Low level init of the MAC and PHY.
*
* \param[in] netif Pointer to LWIP netif structure
*/
static err_t low_level_init(struct netif *netif)
{
status_t status;
uint8_t i;
uint32_t refClock;
phy_speed_t phy_speed;
phy_duplex_t phy_duplex;
uint32_t phyAddr = 0;
bool link = false;
enet_config_t config;
uint32_t timeout = 0xFFFU;
lpc546xx_init_eth_hardware();
refClock = CLOCK_GetFreq(kCLOCK_CoreSysClk);
status = PHY_Init(ENET, phyAddr, refClock);
if (status != kStatus_Success) {
return ERR_IF;
}
ENET_GetDefaultConfig(&config);
config.multiqueueCfg = NULL;
while ((!link) && timeout) {
PHY_GetLinkStatus(ENET, phyAddr, &link);
if (link) {
/* Get link information from PHY */
PHY_GetLinkSpeedDuplex(ENET, phyAddr, &phy_speed, &phy_duplex);
/* Change the MII speed and duplex for actual link status. */
config.miiSpeed = (enet_mii_speed_t)phy_speed;
config.miiDuplex = (enet_mii_duplex_t)phy_duplex;
}
timeout--;
}
if (!link) {
return ERR_CONN;
}
AT_NONCACHEABLE_SECTION_ALIGN(static enet_rx_bd_struct_t rx_desc_start_addr[ENET_RX_RING_LEN], ENET_BUFF_ALIGNMENT);
AT_NONCACHEABLE_SECTION_ALIGN(static enet_tx_bd_struct_t tx_desc_start_addr[ENET_TX_RING_LEN], ENET_BUFF_ALIGNMENT);
/* Create buffers for each receive BD */
for (i = 0; i < ENET_RX_RING_LEN; i++) {
rx_buff[i] = pbuf_alloc(PBUF_RAW, ENET_ALIGN(ENET_ETH_MAX_FLEN, ENET_BUFF_ALIGNMENT), PBUF_RAM);
if (NULL == rx_buff[i])
return ERR_MEM;
rx_ptr[i] = (uint32_t)rx_buff[i]->payload;
}
/* prepare the buffer configuration. */
enet_buffer_config_t buffCfg = {
ENET_RX_RING_LEN,
ENET_TX_RING_LEN,
&tx_desc_start_addr[0],
&tx_desc_start_addr[0],
&rx_desc_start_addr[0],
&rx_desc_start_addr[ENET_RX_RING_LEN],
rx_ptr,
ENET_ALIGN(ENET_ETH_MAX_FLEN, ENET_BUFF_ALIGNMENT),
};
ENET_Init(ENET, &config, netif->hwaddr, refClock);
/* Enable the tx & rx interrupt. */
ENET_EnableInterrupts(ENET, kENET_DmaTx | kENET_DmaRx);
/* Create the handler. */
ENET_CreateHandler(ENET, &g_handle, &config, &buffCfg, ethernet_callback, netif);
/* Initialize Descriptor. */
ENET_DescriptorInit(ENET, &config, &buffCfg);
return ERR_OK;
}
/**
* This function is the ethernet IPv4 packet send function. It calls
* etharp_output after checking link status.
*
* \param[in] netif the lwip network interface structure for this lpc_enetif
* \param[in] q Pointer to pbug to send
* \param[in] ipaddr IP address
* \return ERR_OK or error code
*/
#if LWIP_IPV4
err_t lpc546xx_etharp_output_ipv4(struct netif *netif, struct pbuf *q,
const ip4_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;
}
#endif
/**
* This function is the ethernet IPv6 packet send function. It calls
* etharp_output after checking link status.
*
* \param[in] netif the lwip network interface structure for this lpc_enetif
* \param[in] q Pointer to pbug to send
* \param[in] ipaddr IP address
* \return ERR_OK or error code
*/
#if LWIP_IPV6
err_t lpc546xx_etharp_output_ipv6(struct netif *netif, struct pbuf *q,
const ip6_addr_t *ipaddr)
{
/* Only send packet is link is up */s
if (netif->flags & NETIF_FLAG_LINK_UP)
return ethip6_output(netif, q, ipaddr);
return ERR_CONN;
}
#endif
/*******************************************************************************
* PHY task: monitor link
*******************************************************************************/
#define STATE_UNKNOWN (-1)
typedef struct {
int connected;
phy_speed_t speed;
phy_duplex_t duplex;
} PHY_STATE;
int phy_link_status(void) {
bool connection_status;
uint32_t phyAddr = 0;
PHY_GetLinkStatus(ENET, phyAddr, &connection_status);
return (int)connection_status;
}
static void lpc546xx_phy_task(void *data) {
struct netif *netif = (struct netif*)data;
static PHY_STATE prev_state = {STATE_UNKNOWN, (phy_speed_t)STATE_UNKNOWN, (phy_duplex_t)STATE_UNKNOWN};
uint32_t phyAddr = 0;
// Get current status
PHY_STATE crt_state;
bool connection_status;
PHY_GetLinkStatus(ENET, phyAddr, &connection_status);
crt_state.connected = connection_status;
// Get the actual PHY link speed
PHY_GetLinkSpeedDuplex(ENET, phyAddr, &crt_state.speed, &crt_state.duplex);
// Compare with previous state
if (crt_state.connected != prev_state.connected) {
// We're called from lwIP's tcpip thread, so can call link functions directly
if (crt_state.connected) {
netif_set_link_up(netif);
} else {
netif_set_link_down(netif);
}
}
if (crt_state.speed != prev_state.speed) {
uint32_t fes = ENET->MAC_CONFIG;
fes &= ~ENET_MAC_CONFIG_FES_MASK;
if (prev_state.speed != (phy_speed_t)STATE_UNKNOWN) {
fes |= ENET_MAC_CONFIG_FES(!crt_state.speed);
} else {
fes |= ENET_MAC_CONFIG_FES(crt_state.speed);
}
ENET->MAC_CONFIG = fes;
}
prev_state = crt_state;
}
/**
* 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().
*
* @param[in] netif the lwip network interface structure for this lpc_enetif
* @return ERR_OK if the loopif is initialized
* ERR_MEM if private data couldn't be allocated
* any other err_t on error
*/
err_t eth_arch_enetif_init(struct netif *netif)
{
err_t err;
LWIP_ASSERT("netif != NULL", (netif != NULL));
lpc_enetdata.netif = netif;
/* set MAC hardware address */
#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
netif->hwaddr[0] = MBED_MAC_ADDR_0;
netif->hwaddr[1] = MBED_MAC_ADDR_1;
netif->hwaddr[2] = MBED_MAC_ADDR_2;
netif->hwaddr[3] = MBED_MAC_ADDR_3;
netif->hwaddr[4] = MBED_MAC_ADDR_4;
netif->hwaddr[5] = MBED_MAC_ADDR_5;
#else
mbed_mac_address((char *)netif->hwaddr);
#endif
netif->hwaddr_len = ETH_HWADDR_LEN;
/* maximum transfer unit */
netif->mtu = 1500;
/* device capabilities */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET;
#ifdef LWIP_IGMP
netif->flags |= NETIF_FLAG_IGMP;
#endif
#if LWIP_IPV6_MLD
netif->flags |= NETIF_FLAG_MLD6;
#endif
/* 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 = "lwiplpc546xx";
#endif /* LWIP_NETIF_HOSTNAME */
netif->name[0] = 'e';
netif->name[1] = 'n';
#if LWIP_IPV4
netif->output = lpc546xx_etharp_output_ipv4;
#endif
#if LWIP_IPV6
netif->output_ip6 = lpc546xx_etharp_output_ipv6;
#endif
netif->linkoutput = lpc546xx_low_level_output;
/* CMSIS-RTOS, start tasks */
#if NO_SYS == 0
memset(&lpc_enetdata.xTXDCountSem.data, 0, sizeof(lpc_enetdata.xTXDCountSem.data));
lpc_enetdata.xTXDCountSem.attr.cb_mem = &lpc_enetdata.xTXDCountSem.data;
lpc_enetdata.xTXDCountSem.attr.cb_size = sizeof(lpc_enetdata.xTXDCountSem.data);
lpc_enetdata.xTXDCountSem.id = osSemaphoreNew(ENET_TX_RING_LEN, ENET_TX_RING_LEN, &lpc_enetdata.xTXDCountSem.attr);
LWIP_ASSERT("xTXDCountSem creation error", (lpc_enetdata.xTXDCountSem.id != NULL));
err = sys_mutex_new(&lpc_enetdata.TXLockMutex);
LWIP_ASSERT("TXLockMutex creation error", (err == ERR_OK));
/* Allow the PHY task to detect the initial link state and set up the proper flags */
tcpip_callback_with_block(lpc546xx_phy_task, netif, 1);
osDelay(10);
/* Worker thread */
lpc_enetdata.thread = sys_thread_new("lpc546xx_emac_thread", lpc546xx_emac_thread, netif->state, THREAD_STACKSIZE, THREAD_PRIORITY)->id;
#endif
/* Active TX/RX. */
ENET_StartRxTx(ENET, 1, 1);
return ERR_OK;
}
void eth_arch_enable_interrupts(void) {
}
void eth_arch_disable_interrupts(void) {
}
#endif /* LWIP_ARP || LWIP_ETHERNET */

View File

@ -0,0 +1,37 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LPC546XX_EMAC_CONFIG_H__
#define LPC546XX_EMAC_CONFIG_H__
#include "fsl_enet.h"
#define ENET_RX_RING_LEN (16)
#define ENET_TX_RING_LEN (8)
#define ENET_ETH_MAX_FLEN (ENET_FRAME_MAX_FRAMELEN)
#if defined(__cplusplus)
extern "C" {
#endif
int phy_link_status(void);
#if defined(__cplusplus)
}
#endif
#endif // #define LPC546XX_EMAC_CONFIG_H__

View File

@ -0,0 +1,29 @@
/* Copyright (C) 2012 mbed.org, MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef LWIPOPTS_CONF_H
#define LWIPOPTS_CONF_H
#include "lpc546xx_emac_config.h"
#define LWIP_TRANSPORT_ETHERNET 1
#define ETH_PAD_SIZE 0
#define MEM_SIZE (ENET_RX_RING_LEN * (ENET_ETH_MAX_FLEN + ENET_BUFF_ALIGNMENT) + ENET_TX_RING_LEN * ENET_ETH_MAX_FLEN)
#endif

View File

@ -0,0 +1,234 @@
/**********************************************************************
*
* Filename: crc.c
*
* Description: Slow and fast implementations of the CRC standards.
*
* Notes: The parameters for each supported CRC standard are
* defined in the header file crc.h. The implementations
* here should stand up to further additions to that list.
*
*
* Copyright (c) 2000 by Michael Barr. This software is placed into
* the public domain and may be used for any purpose. However, this
* notice must not be changed or removed and no warranty is either
* expressed or implied by its publication or distribution.
**********************************************************************/
#include "crc.h"
/*
* Derive parameters from the standard-specific parameters in crc.h.
*/
#define WIDTH (8 * sizeof(crc))
#define TOPBIT (1 << (WIDTH - 1))
#if (REFLECT_DATA == TRUE)
#undef REFLECT_DATA
#define REFLECT_DATA(X) ((unsigned char) reflect((X), 8))
#else
#undef REFLECT_DATA
#define REFLECT_DATA(X) (X)
#endif
#if (REFLECT_REMAINDER == TRUE)
#undef REFLECT_REMAINDER
#define REFLECT_REMAINDER(X) ((crc) reflect((X), WIDTH))
#else
#undef REFLECT_REMAINDER
#define REFLECT_REMAINDER(X) (X)
#endif
/*********************************************************************
*
* Function: reflect()
*
* Description: Reorder the bits of a binary sequence, by reflecting
* them about the middle position.
*
* Notes: No checking is done that nBits <= 32.
*
* Returns: The reflection of the original data.
*
*********************************************************************/
static unsigned long
reflect(unsigned long data, unsigned char nBits)
{
unsigned long reflection = 0x00000000;
unsigned char bit;
/*
* Reflect the data about the center bit.
*/
for (bit = 0; bit < nBits; ++bit)
{
/*
* If the LSB bit is set, set the reflection of it.
*/
if (data & 0x01)
{
reflection |= (1 << ((nBits - 1) - bit));
}
data = (data >> 1);
}
return (reflection);
} /* reflect() */
/*********************************************************************
*
* Function: crcSlow()
*
* Description: Compute the CRC of a given message.
*
* Notes:
*
* Returns: The CRC of the message.
*
*********************************************************************/
crc
crcSlow(unsigned char const message[], int nBytes)
{
crc remainder = INITIAL_REMAINDER;
int byte;
unsigned char bit;
/*
* Perform modulo-2 division, a byte at a time.
*/
for (byte = 0; byte < nBytes; ++byte)
{
/*
* Bring the next byte into the remainder.
*/
remainder ^= (REFLECT_DATA(message[byte]) << (WIDTH - 8));
/*
* Perform modulo-2 division, a bit at a time.
*/
for (bit = 8; bit > 0; --bit)
{
/*
* Try to divide the current data bit.
*/
if (remainder & TOPBIT)
{
remainder = (remainder << 1) ^ POLYNOMIAL;
}
else
{
remainder = (remainder << 1);
}
}
}
/*
* The final remainder is the CRC result.
*/
return (REFLECT_REMAINDER(remainder) ^ FINAL_XOR_VALUE);
} /* crcSlow() */
crc crcTable[256];
/*********************************************************************
*
* Function: crcInit()
*
* Description: Populate the partial CRC lookup table.
*
* Notes: This function must be rerun any time the CRC standard
* is changed. If desired, it can be run "offline" and
* the table results stored in an embedded system's ROM.
*
* Returns: None defined.
*
*********************************************************************/
void
crcInit(void)
{
crc remainder;
int dividend;
unsigned char bit;
/*
* Compute the remainder of each possible dividend.
*/
for (dividend = 0; dividend < 256; ++dividend)
{
/*
* Start with the dividend followed by zeros.
*/
remainder = dividend << (WIDTH - 8);
/*
* Perform modulo-2 division, a bit at a time.
*/
for (bit = 8; bit > 0; --bit)
{
/*
* Try to divide the current data bit.
*/
if (remainder & TOPBIT)
{
remainder = (remainder << 1) ^ POLYNOMIAL;
}
else
{
remainder = (remainder << 1);
}
}
/*
* Store the result into the table.
*/
crcTable[dividend] = remainder;
}
} /* crcInit() */
/*********************************************************************
*
* Function: crcFast()
*
* Description: Compute the CRC of a given message.
*
* Notes: crcInit() must be called first.
*
* Returns: The CRC of the message.
*
*********************************************************************/
crc
crcFast(unsigned char const message[], int nBytes)
{
crc remainder = INITIAL_REMAINDER;
unsigned char data;
int byte;
/*
* Divide the message by the polynomial, a byte at a time.
*/
for (byte = 0; byte < nBytes; ++byte)
{
data = REFLECT_DATA(message[byte]) ^ (remainder >> (WIDTH - 8));
remainder = crcTable[data] ^ (remainder << 8);
}
/*
* The final remainder is the CRC.
*/
return (REFLECT_REMAINDER(remainder) ^ FINAL_XOR_VALUE);
} /* crcFast() */

View File

@ -0,0 +1,77 @@
/**********************************************************************
*
* Filename: crc.h
*
* Description: A header file describing the various CRC standards.
*
* Notes:
*
*
* Copyright (c) 2000 by Michael Barr. This software is placed into
* the public domain and may be used for any purpose. However, this
* notice must not be changed or removed and no warranty is either
* expressed or implied by its publication or distribution.
**********************************************************************/
#ifndef _crc_h
#define _crc_h
#define FALSE 0
#define TRUE !FALSE
/*
* Select the CRC standard from the list that follows.
*/
#define CRC16
#if defined(CRC_CCITT)
typedef unsigned short crc;
#define CRC_NAME "CRC-CCITT"
#define POLYNOMIAL 0x1021
#define INITIAL_REMAINDER 0xFFFF
#define FINAL_XOR_VALUE 0x0000
#define REFLECT_DATA FALSE
#define REFLECT_REMAINDER FALSE
#define CHECK_VALUE 0x29B1
#elif defined(CRC16)
typedef unsigned short crc;
#define CRC_NAME "CRC-16"
#define POLYNOMIAL 0x8005
#define INITIAL_REMAINDER 0x0000
#define FINAL_XOR_VALUE 0x0000
#define REFLECT_DATA TRUE
#define REFLECT_REMAINDER TRUE
#define CHECK_VALUE 0xBB3D
#elif defined(CRC32)
typedef unsigned long crc;
#define CRC_NAME "CRC-32"
#define POLYNOMIAL 0x04C11DB7
#define INITIAL_REMAINDER 0xFFFFFFFF
#define FINAL_XOR_VALUE 0xFFFFFFFF
#define REFLECT_DATA TRUE
#define REFLECT_REMAINDER TRUE
#define CHECK_VALUE 0xCBF43926
#else
#error "One of CRC_CCITT, CRC16, or CRC32 must be #define'd."
#endif
void crcInit(void);
crc crcSlow(unsigned char const message[], int nBytes);
crc crcFast(unsigned char const message[], int nBytes);
#endif /* _crc_h */

View File

@ -0,0 +1,278 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o 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.
*
* o Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
*/
#include "fsl_phy.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @brief Defines the timeout macro. */
#define PHY_TIMEOUT_COUNT 0xFFFFFFU
/*******************************************************************************
* Prototypes
******************************************************************************/
/*!
* @brief Get the ENET instance from peripheral base address.
*
* @param base ENET peripheral base address.
* @return ENET instance.
*/
extern uint32_t ENET_GetInstance(ENET_Type *base);
/*******************************************************************************
* Variables
******************************************************************************/
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/*! @brief Pointers to enet clocks for each instance. */
#if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0)
extern clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_ENET_COUNT];
#elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0)
extern clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_LPC_ENET_COUNT];
#endif
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
/*******************************************************************************
* Code
******************************************************************************/
status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz)
{
uint32_t reg;
uint32_t idReg = 0;
uint32_t delay = PHY_TIMEOUT_COUNT;
uint32_t instance = ENET_GetInstance(base);
bool status = false;
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Set SMI first. */
CLOCK_EnableClock(s_enetClock[instance]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
#if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0)
ENET_SetSMI(base, srcClock_Hz, false);
#elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0)
ENET_SetSMI(base);
#endif
/* Initialization after PHY stars to work. */
while ((idReg != PHY_CONTROL_ID1) && (delay != 0))
{
PHY_Read(base, phyAddr, PHY_ID1_REG, &idReg);
delay --;
}
if (!delay)
{
return kStatus_Fail;
}
delay = PHY_TIMEOUT_COUNT;
/* Reset PHY and wait until completion. */
PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
do
{
PHY_Read(base, phyAddr, PHY_BASICCONTROL_REG, &reg);
} while (delay-- && reg & PHY_BCTL_RESET_MASK);
if (!delay)
{
return kStatus_Fail;
}
/* Set the ability. */
PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG, (PHY_ALL_CAPABLE_MASK | 0x1U));
/* Start Auto negotiation and wait until auto negotiation completion */
PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
delay = PHY_TIMEOUT_COUNT;
do
{
PHY_Read(base, phyAddr, PHY_SEPCIAL_CONTROL_REG, &reg);
delay --;
} while (delay && ((reg & PHY_SPECIALCTL_AUTONEGDONE_MASK) == 0));
if (!delay)
{
return kStatus_Fail;
}
/* Waiting a moment for phy stable. */
for (delay = 0; delay < PHY_TIMEOUT_COUNT; delay++)
{
__ASM("nop");
PHY_GetLinkStatus(base, phyAddr, &status);
if (status)
{
break;
}
}
return kStatus_Success;
}
status_t PHY_Write(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data)
{
#if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0)
uint32_t counter;
/* Clear the SMI interrupt event. */
ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
/* Starts a SMI write command. */
ENET_StartSMIWrite(base, phyAddr, phyReg, kENET_MiiWriteValidFrame, data);
/* Wait for SMI complete. */
for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--)
{
if (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)
{
break;
}
}
/* Check for timeout. */
if (!counter)
{
return kStatus_PHY_SMIVisitTimeout;
}
/* Clear MII interrupt event. */
ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
#elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0)
ENET_StartSMIWrite(base, phyAddr, phyReg, data);
while (ENET_IsSMIBusy(base))
;
#endif
return kStatus_Success;
}
status_t PHY_Read(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr)
{
#if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0)
assert(dataPtr);
uint32_t counter;
/* Clear the MII interrupt event. */
ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
/* Starts a SMI read command operation. */
ENET_StartSMIRead(base, phyAddr, phyReg, kENET_MiiReadValidFrame);
/* Wait for MII complete. */
for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--)
{
if (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)
{
break;
}
}
/* Check for timeout. */
if (!counter)
{
return kStatus_PHY_SMIVisitTimeout;
}
/* Get data from MII register. */
*dataPtr = ENET_ReadSMIData(base);
/* Clear MII interrupt event. */
ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
#elif defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0)
ENET_StartSMIRead(base, phyAddr, phyReg);
while (ENET_IsSMIBusy(base))
;
*dataPtr = ENET_ReadSMIData(base);
#endif
return kStatus_Success;
}
status_t PHY_GetLinkStatus(ENET_Type *base, uint32_t phyAddr, bool *status)
{
uint32_t reg;
status_t result = kStatus_Success;
/* Read the basic status register. */
result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &reg);
if (result == kStatus_Success)
{
if (reg & PHY_BSTATUS_LINKSTATUS_MASK)
{
/* link up. */
*status = true;
}
else
{
*status = false;
}
}
return result;
}
status_t PHY_GetLinkSpeedDuplex(ENET_Type *base, uint32_t phyAddr, phy_speed_t *speed, phy_duplex_t *duplex)
{
assert(duplex);
assert(speed);
uint32_t reg;
status_t result = kStatus_Success;
/* Read the control two register. */
result = PHY_Read(base, phyAddr, PHY_SEPCIAL_CONTROL_REG, &reg);
if (result == kStatus_Success)
{
if (reg & PHY_SPECIALCTL_DUPLEX_MASK)
{
/* Full duplex. */
*duplex = kPHY_FullDuplex;
}
else
{
/* Half duplex. */
*duplex = kPHY_HalfDuplex;
}
if (reg & PHY_SPECIALCTL_100SPEED_MASK)
{
/* 100M speed. */
*speed = kPHY_Speed100M;
}
else
{ /* 10M speed. */
*speed = kPHY_Speed10M;
}
}
return result;
}

View File

@ -0,0 +1,183 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o 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.
*
* o Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
*/
#ifndef _FSL_PHY_H_
#define _FSL_PHY_H_
#include "fsl_enet.h"
/*!
* @addtogroup phy_driver
* @{
*/
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @brief PHY driver version */
#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) /*!< Version 2.0.0. */
/*! @brief Defines the PHY registers. */
#define PHY_BASICCONTROL_REG 0x00U /*!< The PHY basic control register. */
#define PHY_BASICSTATUS_REG 0x01U /*!< The PHY basic status register. */
#define PHY_ID1_REG 0x02U /*!< The PHY ID one register. */
#define PHY_ID2_REG 0x03U /*!< The PHY ID two register. */
#define PHY_AUTONEG_ADVERTISE_REG 0x04U /*!< The PHY auto-negotiate advertise register. */
#define PHY_SEPCIAL_CONTROL_REG 0x1FU /*!< The PHY control two register. */
#define PHY_CONTROL_ID1 0x07U /*!< The PHY ID1*/
/*! @brief Defines the mask flag in basic control register. */
#define PHY_BCTL_DUPLEX_MASK 0x0100U /*!< The PHY duplex bit mask. */
#define PHY_BCTL_RESTART_AUTONEG_MASK 0x0200U /*!< The PHY restart auto negotiation mask. */
#define PHY_BCTL_AUTONEG_MASK 0x1000U /*!< The PHY auto negotiation bit mask. */
#define PHY_BCTL_SPEED_MASK 0x2000U /*!< The PHY speed bit mask. */
#define PHY_BCTL_LOOP_MASK 0x4000U /*!< The PHY loop bit mask. */
#define PHY_BCTL_RESET_MASK 0x8000U /*!< The PHY reset bit mask. */
/*!@brief Defines the mask flag of operation mode in special control register*/
#define PHY_SPECIALCTL_AUTONEGDONE_MASK 0x1000U /*!< The PHY auto-negotiation complete mask. */
#define PHY_SPECIALCTL_DUPLEX_MASK 0x0010U /*!< The PHY duplex mask. */
#define PHY_SPECIALCTL_100SPEED_MASK 0x0008U /*!< The PHY speed mask. */
#define PHY_SPECIALCTL_10SPEED_MASK 0x0004U /*!< The PHY speed mask. */
#define PHY_SPECIALCTL_SPEEDUPLX_MASK 0x001cU /*!< The PHY speed and duplex mask. */
/*! @brief Defines the mask flag in basic status register. */
#define PHY_BSTATUS_LINKSTATUS_MASK 0x0004U /*!< The PHY link status mask. */
/*! @brief Defines the mask flag in PHY auto-negotiation advertise register. */
#define PHY_ALL_CAPABLE_MASK 0x1e0U
/*! @brief Defines the PHY status. */
enum _phy_status
{
kStatus_PHY_SMIVisitTimeout = MAKE_STATUS(kStatusGroup_PHY, 0), /*!< ENET PHY SMI visit timeout. */
};
/*! @brief Defines the PHY link speed. This is align with the speed for ENET MAC. */
typedef enum _phy_speed {
kPHY_Speed10M = 0U, /*!< ENET PHY 10M speed. */
kPHY_Speed100M /*!< ENET PHY 100M speed. */
} phy_speed_t;
/*! @brief Defines the PHY link duplex. */
typedef enum _phy_duplex {
kPHY_HalfDuplex = 0U, /*!< ENET PHY half duplex. */
kPHY_FullDuplex /*!< ENET PHY full duplex. */
} phy_duplex_t;
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*!
* @name PHY Driver
* @{
*/
/*!
* @brief Initializes PHY.
*
* This function initialize the SMI interface and initialize PHY.
* The SMI is the MII management interface between PHY and MAC, which should be
* firstly initialized before any other operation for PHY.
*
* @param base ENET peripheral base address.
* @param phyAddr The PHY address.
* @param srcClock_Hz The module clock frequency - system clock for MII management interface - SMI.
* @retval kStatus_Success PHY initialize success
* @retval kStatus_Fail PHY initialize fail
*/
status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz);
/*!
* @brief PHY Write function. This function write data over the SMI to
* the specified PHY register. This function is called by all PHY interfaces.
*
* @param base ENET peripheral base address.
* @param phyAddr The PHY address.
* @param phyReg The PHY register.
* @param data The data written to the PHY register.
* @retval kStatus_Success PHY write success
* @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
*/
status_t PHY_Write(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data);
/*!
* @brief PHY Read function. This interface read data over the SMI from the
* specified PHY register. This function is called by all PHY interfaces.
*
* @param base ENET peripheral base address.
* @param phyAddr The PHY address.
* @param phyReg The PHY register.
* @param dataPtr The address to store the data read from the PHY register.
* @retval kStatus_Success PHY read success
* @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
*/
status_t PHY_Read(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr);
/*!
* @brief Gets the PHY link status.
*
* @param base ENET peripheral base address.
* @param phyAddr The PHY address.
* @param status The link up or down status of the PHY.
* - true the link is up.
* - false the link is down.
* @retval kStatus_Success PHY get link status success
* @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
*/
status_t PHY_GetLinkStatus(ENET_Type *base, uint32_t phyAddr, bool *status);
/*!
* @brief Gets the PHY link speed and duplex.
*
* @param base ENET peripheral base address.
* @param phyAddr The PHY address.
* @param speed The address of PHY link speed.
* @param duplex The link duplex of PHY.
* @retval kStatus_Success PHY get link speed and duplex success
* @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
*/
status_t PHY_GetLinkSpeedDuplex(ENET_Type *base, uint32_t phyAddr, phy_speed_t *speed, phy_duplex_t *duplex);
/* @} */
#if defined(__cplusplus)
}
#endif
/*! @}*/
#endif /* _FSL_PHY_H_ */

View File

@ -17,6 +17,10 @@
#include "clock_config.h"
#include "fsl_emc.h"
#include "fsl_power.h"
#include "fsl_flashiap.h"
#define CRC16
#include "crc.h"
/*******************************************************************************
* Definitions
@ -37,6 +41,18 @@
#define SDRAM_MODEREG_VALUE (0x23u)
#define SDRAM_DEV_MEMORYMAP (0x09u) /* 128Mbits (8M*16, 4banks, 12 rows, 9 columns)*/
uint32_t FLASHIAP_ReadUid(uint32_t *addr)
{
uint32_t command[5], result[5];
command[0] = kIapCmd_FLASHIAP_ReadUid;
iap_entry(command, result);
memcpy(addr, &result[1], (sizeof(uint32_t) * 4));
return result[0];
}
// called before main
void mbed_sdk_init()
{
@ -59,6 +75,38 @@ void rtc_setup_oscillator(void)
SYSCON->RTCOSCCTRL |= SYSCON_RTCOSCCTRL_EN_MASK;
}
// Provide ethernet devices with a semi-unique MAC address from the UUID
void mbed_mac_address(char *mac)
{
uint16_t MAC[3]; // 3 16 bits words for the MAC
uint32_t UID[4];
// get UID via ISP commands
FLASHIAP_ReadUid(UID);
// generate three CRC16's using different slices of the UUID
MAC[0] = crcSlow((const uint8_t *)UID, 8); // most significant half-word
MAC[1] = crcSlow((const uint8_t *)UID, 12);
MAC[2] = crcSlow((const uint8_t *)UID, 16); // least significant half word
// The network stack expects an array of 6 bytes
// so we copy, and shift and copy from the half-word array to the byte array
mac[0] = MAC[0] >> 8;
mac[1] = MAC[0];
mac[2] = MAC[1] >> 8;
mac[3] = MAC[1];
mac[4] = MAC[2] >> 8;
mac[5] = MAC[2];
// We want to force bits [1:0] of the most significant byte [0]
// to be "10"
// http://en.wikipedia.org/wiki/MAC_address
mac[0] |= 0x02; // force bit 1 to a "1" = "Locally Administered"
mac[0] &= 0xFE; // force bit 0 to a "0" = Unicast
}
void ADC_ClockPower_Configuration(void)
{
/* SYSCON power. */

View File

@ -194,6 +194,123 @@ typedef int32_t status_t;
#define COUNT_TO_MSEC(count, clockFreqInHz) (uint64_t)((uint64_t)count * 1000U / clockFreqInHz)
/* @} */
/*! @name Alignment variable definition macros */
/* @{ */
#if (defined(__ICCARM__))
/**
* Workaround to disable MISRA C message suppress warnings for IAR compiler.
* http://supp.iar.com/Support/?note=24725
*/
_Pragma("diag_suppress=Pm120")
#define SDK_PRAGMA(x) _Pragma(#x)
_Pragma("diag_error=Pm120")
/*! Macro to define a variable with alignbytes alignment */
#define SDK_ALIGN(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var
/*! Macro to define a variable with L1 d-cache line size alignment */
#if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)
#define SDK_L1DCACHE_ALIGN(var) SDK_PRAGMA(data_alignment = FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) var
#endif
/*! Macro to define a variable with L2 cache line size alignment */
#if defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE)
#define SDK_L2CACHE_ALIGN(var) SDK_PRAGMA(data_alignment = FSL_FEATURE_L2CACHE_LINESIZE_BYTE) var
#endif
#elif defined(__ARMCC_VERSION)
/*! Macro to define a variable with alignbytes alignment */
#define SDK_ALIGN(var, alignbytes) __align(alignbytes) var
/*! Macro to define a variable with L1 d-cache line size alignment */
#if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)
#define SDK_L1DCACHE_ALIGN(var) __align(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) var
#endif
/*! Macro to define a variable with L2 cache line size alignment */
#if defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE)
#define SDK_L2CACHE_ALIGN(var) __align(FSL_FEATURE_L2CACHE_LINESIZE_BYTE) var
#endif
#elif defined(__GNUC__)
/*! Macro to define a variable with alignbytes alignment */
#define SDK_ALIGN(var, alignbytes) var __attribute__((aligned(alignbytes)))
/*! Macro to define a variable with L1 d-cache line size alignment */
#if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)
#define SDK_L1DCACHE_ALIGN(var) var __attribute__((aligned(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)))
#endif
/*! Macro to define a variable with L2 cache line size alignment */
#if defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE)
#define SDK_L2CACHE_ALIGN(var) var __attribute__((aligned(FSL_FEATURE_L2CACHE_LINESIZE_BYTE)))
#endif
#else
#error Toolchain not supported
#define SDK_ALIGN(var, alignbytes) var
#if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)
#define SDK_L1DCACHE_ALIGN(var) var
#endif
#if defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE)
#define SDK_L2CACHE_ALIGN(var) var
#endif
#endif
/*! Macro to change a value to a given size aligned value */
#define SDK_SIZEALIGN(var, alignbytes) \
((unsigned int)((var) + ((alignbytes)-1)) & (unsigned int)(~(unsigned int)((alignbytes)-1)))
/* @} */
/*! @name Non-cacheable region definition macros */
/* For initialized non-zero non-cacheable variables, please using "AT_NONCACHEABLE_SECTION_INIT(var) ={xx};" or
* "AT_NONCACHEABLE_SECTION_ALIGN_INIT(var) ={xx};" in your projects to define them, for zero-inited non-cacheable variables,
* please using "AT_NONCACHEABLE_SECTION(var);" or "AT_NONCACHEABLE_SECTION_ALIGN(var);" to define them, these zero-inited variables
* will be initialized to zero in system startup.
*/
/* @{ */
#if (defined(__ICCARM__))
#if defined(FSL_FEATURE_L1ICACHE_LINESIZE_BYTE)
#define AT_NONCACHEABLE_SECTION(var) var @"NonCacheable"
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var @"NonCacheable"
#define AT_NONCACHEABLE_SECTION_INIT(var) var @"NonCacheable.init"
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var @"NonCacheable.init"
#else
#define AT_NONCACHEABLE_SECTION(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var
#define AT_NONCACHEABLE_SECTION_INIT(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var
#endif
#elif(defined(__ARMCC_VERSION))
#if defined(FSL_FEATURE_L1ICACHE_LINESIZE_BYTE)
#define AT_NONCACHEABLE_SECTION(var) __attribute__((section("NonCacheable"), zero_init)) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) \
__attribute__((section("NonCacheable"), zero_init)) __align(alignbytes) var
#define AT_NONCACHEABLE_SECTION_INIT(var) __attribute__((section("NonCacheable.init"))) var
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) \
__attribute__((section("NonCacheable.init"))) __align(alignbytes) var
#else
#define AT_NONCACHEABLE_SECTION(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) __align(alignbytes) var
#define AT_NONCACHEABLE_SECTION_INIT(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) __align(alignbytes) var
#endif
#elif(defined(__GNUC__))
/* For GCC, when the non-cacheable section is required, please define "__STARTUP_INITIALIZE_NONCACHEDATA"
* in your projects to make sure the non-cacheable section variables will be initialized in system startup.
*/
#if defined(FSL_FEATURE_L1ICACHE_LINESIZE_BYTE)
#define AT_NONCACHEABLE_SECTION_INIT(var) __attribute__((section("NonCacheable.init"))) var
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) \
__attribute__((section("NonCacheable.init"))) var __attribute__((aligned(alignbytes)))
#define AT_NONCACHEABLE_SECTION(var) __attribute__((section("NonCacheable,\"aw\",%nobits @"))) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) \
__attribute__((section("NonCacheable,\"aw\",%nobits @"))) var __attribute__((aligned(alignbytes)))
#else
#define AT_NONCACHEABLE_SECTION(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) var __attribute__((aligned(alignbytes)))
#define AT_NONCACHEABLE_SECTION_INIT(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) var __attribute__((aligned(alignbytes)))
#endif
#else
#error Toolchain not supported.
#define AT_NONCACHEABLE_SECTION(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) var
#define AT_NONCACHEABLE_SECTION_INIT(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) var
#endif
/* @} */
/*******************************************************************************
* API
******************************************************************************/

View File

@ -731,6 +731,7 @@
"inherits": ["Target"],
"detect_code": ["1056"],
"device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
"features": ["LWIP"],
"release_versions": ["2", "5"],
"device_name" : "LPC54618J512ET180"
},