This section describes the programming interface of the ENET Peripheral Driver. The ENET driver receives data from and transmits data to the wired network. The enhanced 1588 feature supports clock synchronization.
ENET device data structure
The ENET device data structure, enet_dev_if_t, includes configuration structure, application structure, and data context structure. This structure should be initialized before the ENET device initialization function. Then, the data structure is passed from the API layer to the device.
ENET Configuration structure
The ENET device data structure uses the enet_mac_config_t and the enet_phy_config_t configuration structure for MAC and PHY configurations. This allows users to configure the most common settings of the ENET peripheral. The enet_mac_config_t mac configuration structure includes the Mac mode, MII/RMII mode configuration, MAC controller configuration, receive and transmit accelerator, receive and transmit FIFO, special Mac configuration to receive maximum frame length, receive truncate length, pause duration for pause frame and the PTP slave mode. The enet_phy_config_t PHY configuration structure includes the PHY address and PHY loop mode, which needs to be configured. If the PHY address is unknown, use the isAutodiscoverEnabled flag to find the PHY address. Note:
- The default maximum frame length is 1518 or 1522(VLAN). The default IPG (inter-packet-gap) is 12 bytes, a sufficient amount for normal Ethernet use. If no special requirements are present, let the macSpecialCfg be NULL.
- The recommended receive and transmit buffer size is the maximum frame size: either 1518 or 1522(VLAN).
- If the kEnetTxAccelEnable and kEnetRxAccelEnable are set, ensure that the txAccelerCfg and rxAccelerCfg are configured.
ENET Buffer data structure
The ENET device data structure uses the enet_buff_config_t to configure the receive/transmit buffer descriptor numbers and address, the receive/transmit data buffer, the aligned receive/transmit buffer size, the extended receive data buffer queue address and 1588 PTP timestamp data buffer address, etc. Data receive and transmit is easily managed with this context structure.
ENET Initialization
To initialize the ENET module, follow these steps:
- First, initialize the ENET MAC and PHY configuration structures, and initialize the upper layer callback function for interrupt mode or initialize semaphore enetIfPtr->enetReceiveSync, create receive task for poll mode.
- Call the enet_mac_init() function with the enet_mac_api_t API structure in the enet_dev_if_t and pass in the enet_dev_if_t device data structure. This function enables the ENET module.
This is an example code to initialize the ENET device data structure:
uint32_t phyAddr;
#if !ENET_RECEIVE_ALL_INTERRUPT
#endif
#if FSL_FEATURE_ENET_SUPPORT_PTP
configMac.isSlaveMode = false;
bufferCfg.ptpTsRxDataPtr = &ptpTsRxData[0];
bufferCfg.ptpTsRxBuffNum = ENET_PTP_RXTS_RING_LEN;
bufferCfg.ptpTsTxDataPtr = &ptpTsTxData[0];
bufferCfg.ptpTsTxBuffNum = ENET_PTP_TXTS_RING_LEN;
#endif
enet_phy_config_t g_enetPhyCfg =
{{0, false }};
if(g_enetPhyCfg[device].isAutodiscoverEnabled)
{
uint32_t phyAddr;
result = PHY_DRV_Autodiscover(device, &phyAddr);
if(result != kStatus_ENET_Success)
return result;
enetIfPtr->phyAddr = phyAddr;
}
else
{
enetIfPtr->phyAddr = g_enetPhyCfg[device].phyAddr;
}
PHY_DRV_Init(device, enetIfPtr->phyAddr, g_enetPhyCfg[device].isLoopEnabled);
#if ENET_RECEIVE_ALL_INTERRUPT
#else
{
return osaFlag;
}
ENET Data Receive
ENET can receive data in two different ways. The MACRO ENET_RECEIVE_ALL_INTERRUPT selects the way in which data is received.
- interrupt and poll (define ENET_RECEIVE_ALL_INTERRUPT with 0)
- interrupt only (define ENET_RECEIVE_ALL_INTERRUPT with 1)
Poll approach (Interrupt add task poll) for Mac receive: The ENET driver receives data directly from the buffer descriptor to the upper layer. To shorten the receiving process time on the receive interrupt, the receive data uses the interrupt and poll combination:
- Receive interrupt: releases the receive synchronize signal (enetReceiveSync).
- Poll: receives task and waits for the receive synchronize signal when no data is received. The receive data returns the address and data length of the received data. To receive data from the ENET device, create a receive task as follows:
task_create(ENET_receive, ENET_TEST_TASK_PRIO, enetIfPtr, &revHandle);
.......................................
ENET_receive(void *param)
{
uint8_t *packet;
uint16_t length;
uint16_t counter;
while(1)
{
#if !USE_RTOS
{
status =
OSA_EventWait(&enetIfPtr->enetReceiveSync, flag,
false, 0, &flagCheck);
}
else if(result == kStatus_ENET_Success)
{
#else
{
}
#endif
....................
if (packetBuffer[0].data != NULL)
{
length = 0;
for(counter = 0; packetBuffer[counter].
length != 0 ; counter ++)
{
memcpy(packet + length, packetBuffer[counter].data, packetBuffer[counter].length);
length += packetBuffer[counter].
length;
(uint32_t *)(packetBuffer[counter].data) = 0;
packetBuffer[counter].
length = 0;
}
....................................
}
}
</code>
<code>
{
uint32_t baseAddr;
enetIfPtr = enetIfHandle[instance];
if (!enetIfPtr)
{
return;
}
{
}
}
Note: The extended receive buffer queue is required in the structure when using the receive polling mode. The data buffer in receive polling mode has to be enqueued by the end of each receive time.
Interrupt only approach for Mac receive: The ENET driver receives data directly from the buffer descriptor to the upper layer. In this case, data is received on the receive interrupt handler:
- Receive interrupt handler calls the receive peripheral driver.
- Receive peripheral driver calls the initialized callback function.
- The callback function checks the protocol and delivers the received data to the upper layer of the TCP/IP stack.
These are the details:
{
uint32_t baseAddr;
enetIfPtr = enetIfHandle[instance];
if (!enetIfPtr)
{
return;
}
{
}
}
</code>
.......................................
<code>
{
void *curBd;
uint32_t length;
uint8_t *packet;
uint32_t controlStatus;
if(!enetIfPtr)
{
}
...........
..........
return kStatus_ENET_Success;
}
</code>
<code>
{
uint32_t length = 0;
uint16_t type, counter = 0;
uint8_t *packet;
if(!packetBuffer[1].length)
{
packet = packetBuffer[0].
data;
length = packetBuffer[0].
length;
}
else
{
if(packet!=NULL)
{
for(counter = 0; packetBuffer[counter].
next != NULL ; counter ++)
{
memcpy(packet + length, packetBuffer[counter].data, packetBuffer[counter].length);
length += packetBuffer[counter].
length;
}
}
else
{
}
}
type = NTOHS(*(uint16_t *)&((enet_etherent_header_t *)packet)->type);
if(pcbPtr)
{
pcbPtr->FRAG[0].LENGTH = length;
pcbPtr->FRAG[0].FRAGMENT = packet;
pcbPtr->PRIVATE = (void *)enetIfPtr;
switch(type)
{
case ENETPROT_IP:
IPE_recv_IP((PCB *)pcbPtr,enetIfPtr->netIfPtr);
break;
case ENETPROT_ARP:
IPE_recv_ARP((PCB *)pcbPtr,enetIfPtr->netIfPtr);
break;
case ENETPROT_IP6:
IP6E_recv_IP((PCB *)pcbPtr,enetIfPtr->netIfPtr);
break;
case ENETPROT_ETHERNET:
enet_ptp_service_l2packet(enetIfPtr, packet, length);
break;
default:
PCB_free((PCB *)pcbPtr);
break;
}
}
else
{
enetIfPtr->
stats.statsRxMissed++;
}
}
Remember to enqueue the packet to the dataBuffQue and enqueue the pcbPtr to the packbuffer after the data is processed by the upper layer. This process is done in the ENET_free API and called by the RTCS. //
ENET Data Transmit
Data Transmit transmits data from the TCP/IP layer to the device and, then, to the network. The data transmit function should be used as follows: PCB_PTR is the data buffer structure of the frame which contains many PCB_FRAGMENT(including the data buffer and length).
uint32_t ENET_send(_enet_handle handle, PCB_PTR packet, uint32_t type, _enet_address dest, uint32_t flags)
{
uint8_t headerLen, *frame;
PCB_FRAGMENT *fragPtr;
uint16_t size = 0, lenTemp = 0, bdNumUsed = 0;
uint32_t result, lenoffset = 0;
if ((!handle) || (!packet))
{
}
for (fragPtr = packet->FRAG; fragPtr->LENGTH; fragPtr++)
{
size += fragPtr->LENGTH;
}
{
}
packetPtr->
type = HTONS(type);
if (flags & ENET_OPT_8021QTAG)
{
vlanHeadPtr->
tpidtag = HTONS(ENETPROT_8021Q);
vlanHeadPtr->
othertag = HTONS((ENET_GETOPT_8021QPRIO(flags) << 13));
vlanHeadPtr->
type = HTONS(type);
packet->FRAG[0].LENGTH = headerLen;
}
if (flags & ENET_OPT_8023)
{
enet_8022_header_ptr lcPtr = (enet_8022_header_ptr)(packetPtr->
type + 2);
packetPtr->
type = HTONS(size - headerLen);
lcPtr->dsap[0] = 0xAA;
lcPtr->ssap[0] = 0xAA;
lcPtr->command[0] = 0x03;
lcPtr->oui[0] = 0x00;
lcPtr->oui[1] = 0x00;
lcPtr->oui[2] = 0x00;
lcPtr->type = HTONS(type);
packet->FRAG[0].LENGTH = packet->FRAG[0].LENGTH+ sizeof(enet_8022_header_t);
}
if(size <= enetIfPtr->bdContext.txBuffSizeAlign)
{
bdNumUsed = 1;
for (fragPtr = packet->FRAG; fragPtr->LENGTH; fragPtr++)
{
memcpy(frame + lenTemp, fragPtr->FRAGMENT, fragPtr->LENGTH);
lenTemp += fragPtr->LENGTH;
}
}
memcpy(frame, packet->FRAG[0].FRAGMENT, packet->FRAG[0].LENGTH);
{
if(bdNumUsed == 0)
{
memcpy((
void *)(frame + packet->FRAG[0].LENGTH), (
void *)(packet->FRAG[1].FRAGMENT), enetIfPtr->
bdContext.
txBuffSizeAlign - packet->FRAG[0].LENGTH);
}
else
{
}
bdNumUsed ++;
}
memcpy((
void *)frame, (
void *)(packet->FRAG[1].FRAGMENT + lenoffset), size - bdNumUsed * enetIfPtr->
bdContext.
txBuffSizeAlign);
bdNumUsed ++;
PCB_free(packet);
return result;
}
ENET Note:
- TWR-MK70F120M Tower System module routes the RMII interface signals from the CPU board to the primary connectors. Hence, the rmiiCfgMode in the enet_mac_config_t should be set to the kEnetCfgRmii. TWR-MK64F120M module can configure both RMII and MII modes.
- Jumper settings When ENET is uses the RMII interface signals by default, the RMII input clock must be kept in phase with the clock supplied to the external PHY. Jumpers should be set as follows:
- TWR-SER J2 shunt across 3-4 , J3 shunt across 2-3, J12 shunt across 9-10
- TWR-MK64f120M board make sure J32 jumper is on to disable the OSC on the CPU board.
- TWR-MK70f120M board make sure J18 jumper is on to disable the OSC on the CPU board. When ENET chooses the MII interface signals, the jumper should be set as follows: TWR-SER J2 shunt across 1-2, J12 no shunt across 9-10.
- In case there exists the cache for memory, when do transfer data, user have to make sure the data’s consistence. That means, when reading the data from memory, application should be sure the data that from or to memory device is actually what it is to be and not cached.
|
enet_status_t | ENET_DRV_Init (enet_dev_if_t *enetIfPtr, const enet_user_config_t *userConfig) |
| Initializes the ENET with the basic configuration. More...
|
|
enet_status_t | ENET_DRV_Deinit (enet_dev_if_t *enetIfPtr) |
| De-initializes the ENET device. More...
|
|
enet_status_t | ENET_DRV_UpdateRxBuffDescrip (enet_dev_if_t *enetIfPtr, bool isBuffUpdate) |
| Updates the receive buffer descriptor. More...
|
|
enet_status_t | ENET_DRV_CleanupTxBuffDescrip (enet_dev_if_t *enetIfPtr) |
| ENET transmit buffer descriptor cleanup. More...
|
|
volatile enet_bd_struct_t * | ENET_DRV_IncrRxBuffDescripIndex (enet_dev_if_t *enetIfPtr, volatile enet_bd_struct_t *curBd) |
| Increases the receive buffer descriptor to the next one. More...
|
|
volatile enet_bd_struct_t * | ENET_DRV_IncrTxBuffDescripIndex (enet_dev_if_t *enetIfPtr, volatile enet_bd_struct_t *curBd) |
| Increases the transmit buffer descriptor to the next one. More...
|
|
bool | ENET_DRV_RxErrorStats (enet_dev_if_t *enetIfPtr, volatile enet_bd_struct_t *curBd) |
| Processes the ENET receive frame error statistics. More...
|
|
void | ENET_DRV_TxErrorStats (enet_dev_if_t *enetIfPtr, volatile enet_bd_struct_t *curBd) |
| Processes the ENET transmit frame statistics. More...
|
|
enet_status_t | ENET_DRV_ReceiveData (enet_dev_if_t *enetIfPtr) |
| Receives ENET packets. More...
|
|
enet_status_t | ENET_DRV_InstallNetIfCall (enet_dev_if_t *enetIfPtr, enet_netif_callback_t function) |
| Installs ENET TCP/IP stack net interface callback function. More...
|
|
enet_status_t | ENET_DRV_SendData (enet_dev_if_t *enetIfPtr, uint32_t dataLen, uint32_t bdNumUsed) |
| Transmits ENET packets. More...
|
|
void | ENET_DRV_RxIRQHandler (uint32_t instance) |
| The ENET receive interrupt handler. More...
|
|
void | ENET_DRV_TxIRQHandler (uint32_t instance) |
| The ENET transmit interrupt handler. More...
|
|
void | ENET_DRV_CalculateCrc32 (uint8_t *address, uint32_t *crcValue) |
| Calculates the CRC hash value. More...
|
|
enet_status_t | ENET_DRV_AddMulticastGroup (uint32_t instance, uint8_t *address, uint32_t *hash) |
| Adds the ENET device to a multicast group. More...
|
|
enet_status_t | ENET_DRV_LeaveMulticastGroup (uint32_t instance, uint8_t *address) |
| Moves the ENET device from a multicast group. More...
|
|
void | enet_mac_enqueue_buffer (void **queue, void *buffer) |
| ENET buffer enqueue. More...
|
|
void * | enet_mac_dequeue_buffer (void **queue) |
| ENET buffer dequeue. More...
|
|
struct enet_multicast_group_t |
Data Fields |
uint8_t | groupAdddr [kEnetMacAddrLen] |
| Multicast group address.
|
|
uint32_t | hash |
| Hash value of the multicast group address.
|
|
struct ENETMulticastGroup * | next |
| Pointer of the next group structure.
|
|
struct ENETMulticastGroup * | prv |
| Pointer of the previous structure.
|
|
struct enet_ethernet_header_t |
struct enet_8021vlan_header_t |
struct enet_buff_descrip_context_t |
Data Fields |
uint32_t | statsRxTotal |
| Total number of receive packets.
|
|
uint32_t | statsTxTotal |
| Total number of transmit packets.
|
|
struct enet_mac_packet_buffer_t |
Data Fields |
uint8_t * | data |
| Data buffer pointer.
|
|
uint16_t | length |
| Data length.
|
|
struct ENETMacPacketBuffer * | next |
| Next pointer.
|
|
struct enet_buff_config_t |
struct enet_user_config_t |
#define ENET_ENABLE_DETAIL_STATS 0 |
#define ENET_ORIGINAL_CRC32 0xFFFFFFFFU |
Enumerator |
---|
kEnetCrcOffset |
CRC-32 offset2.
|
kEnetCrcMask1 |
CRC-32 mask.
|
Enumerator |
---|
kEnetProtocoll2ptpv2 |
Packet type Ethernet ieee802.3.
|
kEnetProtocolIpv4 |
Packet type IPv4.
|
kEnetProtocolIpv6 |
Packet type IPv6.
|
kEnetProtocol8021QVlan |
Packet type VLAN.
|
kEnetPacketUdpVersion |
UDP protocol type.
|
kEnetPacketIpv4Version |
Packet IP version IPv4.
|
kEnetPacketIpv6Version |
Packet IP version IPv6.
|
- Parameters
-
enetIfPtr | The pointer to the basic Ethernet structure. |
userConfig | The ENET user configuration structure pointer. |
- Returns
- The execution status.
- Parameters
-
enetIfPtr | The ENET context structure. |
- Returns
- The execution status.
This function updates the used receive buffer descriptor ring to ensure that the used BDS is correctly used. It cleans the status region and sets the control region of the used receive buffer descriptor. If the isBufferUpdate flag is set, the data buffer in the buffer descriptor is updated.
- Parameters
-
enetIfPtr | The ENET context structure. |
isBuffUpdate | The data buffer update flag. |
- Returns
- The execution status.
First, store the transmit frame error statistic and PTP timestamp of the transmitted packets. Second, clean up the used transmit buffer descriptors. If the PTP 1588 feature is open, this interface captures the 1588 timestamp. It is called by the transmit interrupt handler.
- Parameters
-
enetIfPtr | The ENET context structure. |
- Returns
- The execution status.
- Parameters
-
enetIfPtr | The ENET context structure. |
curBd | The current buffer descriptor pointer. |
- Returns
- the increased received buffer descriptor.
- Parameters
-
enetIfPtr | The ENET context structure. |
curBd | The current buffer descriptor pointer. |
- Returns
- the increased transmit buffer descriptor.
This interface gets the error statistics of the received frame. Because the error information is in the last BD of a frame, this interface should be called when processing the last BD of a frame.
- Parameters
-
enetIfPtr | The ENET context structure. |
curBd | The current buffer descriptor. |
- Returns
- The frame error status.
- True if the frame has an error.
- False if the frame does not have an error.
This interface gets the error statistics of the transmit frame. Because the error information is in the last BD of a frame, this interface should be called when processing the last BD of a frame.
- Parameters
-
enetIfPtr | The ENET context structure. |
curBd | The current buffer descriptor. |
- Parameters
-
enetIfPtr | The ENET context structure. |
- Returns
- The execution status.
- Parameters
-
enetIfPtr | The ENET context structure. |
function | The ENET TCP/IP stack net interface callback function. |
- Returns
- The execution status.
- Parameters
-
enetIfPtr | The ENET context structure. |
dataLen | The frame data length to be transmitted. |
bdNumUsed | The buffer descriptor need to be used. |
- Returns
- The execution status.
void ENET_DRV_RxIRQHandler |
( |
uint32_t |
instance | ) |
|
- Parameters
-
instance | The ENET instance number. |
void ENET_DRV_TxIRQHandler |
( |
uint32_t |
instance | ) |
|
- Parameters
-
instance | The ENET instance number. |
void ENET_DRV_CalculateCrc32 |
( |
uint8_t * |
address, |
|
|
uint32_t * |
crcValue |
|
) |
| |
- Parameters
-
address | The ENET Mac hardware address. |
crcValue | The calculated CRC value of the Mac address. |
enet_status_t ENET_DRV_AddMulticastGroup |
( |
uint32_t |
instance, |
|
|
uint8_t * |
address, |
|
|
uint32_t * |
hash |
|
) |
| |
- Parameters
-
instance | The ENET instance number. |
address | The multicast group address. |
hash | The hash value of the multicast group address. |
- Returns
- The execution status.
enet_status_t ENET_DRV_LeaveMulticastGroup |
( |
uint32_t |
instance, |
|
|
uint8_t * |
address |
|
) |
| |
- Parameters
-
instance | The ENET instance number. |
address | The multicast group address. |
- Returns
- The execution status.
void enet_mac_enqueue_buffer |
( |
void ** |
queue, |
|
|
void * |
buffer |
|
) |
| |
- Parameters
-
queue | The buffer queue address. |
buffer | The buffer will add to the buffer queue. |
void* enet_mac_dequeue_buffer |
( |
void ** |
queue | ) |
|
- Parameters
-
queue | The buffer queue address. |
- Returns
- The buffer will be dequeued from the buffer queue.
ENET_Type* const g_enetBase[] |
const IRQn_Type g_enetTxIrqId[] |