Created
November 7, 2023 13:13
-
-
Save e-sr/54df1959a65d0980c6b193521fb04b0c to your computer and use it in GitHub Desktop.
FreeRTOS-Plus TCP-msp432e401y-networkdrivers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @brief:Network Interface driver for the Texas Instruments MSP432E401Y | |
* This driver was written and tested with the MSP432E401Y, which includes a built-in MAC and PHY. | |
* It is Modified version of the tm4c driver written by jscott <jscott@hotstart.com>. see below. | |
* substantial changes are in the PHY linkup/down handling, In this modified version this is done by handling | |
* the PHY corresponding interrupt! | |
* this driver is conform to FreeRTOS-Plus-TCP v4.0.0 | |
* | |
* | |
* @file: NetworkInterface.c | |
* @author: jscott <jscott@hotstart.com> | |
* @date: Feb 1, 2022 | |
* @copyright: Hotstart 2022 Hotstart Thermal Management. All Rights Reserved. | |
* | |
* 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. | |
* | |
*/ | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdbool.h> | |
#include <stdlib.h> | |
#include <ti/devices/msp432e4/inc/msp432.h> | |
#include <ti/devices/msp432e4/driverlib/emac.h> | |
#include <ti/devices/msp432e4/driverlib/sysctl.h> | |
#include <ti/devices/msp432e4/driverlib/interrupt.h> | |
#include <ti/devices/msp432e4/driverlib/flash.h> | |
#include "FreeRTOS.h" | |
#include "task.h" | |
#include "queue.h" | |
#include "FreeRTOS_IP.h" | |
#include "FreeRTOS_Sockets.h" | |
#include "FreeRTOS_IP_Private.h" | |
#include "NetworkBufferManagement.h" | |
#include "NetworkInterface.h" | |
#define BUFFER_SIZE_WO_PADDING (ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER) | |
//#define BUFFER_SIZE_WO_PADDING (ipTOTAL_ETHERNET_FRAME_SIZE) // ipSIZE_OF_ETH_CRC_BYTES | |
#define BUFFER_SIZE (BUFFER_SIZE_WO_PADDING + ipBUFFER_PADDING) | |
#define BUFFER_SIZE_ROUNDED_UP ((BUFFER_SIZE + 7) & ~0x7UL) | |
#define PHY_PHYS_ADDR 0 | |
#ifndef niEMAC_SYSCONFIG_HZ | |
#define niEMAC_SYSCONFIG_HZ configCPU_CLOCK_HZ | |
#endif | |
#ifndef niEMAC_TX_DMA_DESC_COUNT | |
#define niEMAC_TX_DMA_DESC_COUNT 8 | |
#endif | |
#ifndef niEMAC_RX_DMA_DESC_COUNT | |
#define niEMAC_RX_DMA_DESC_COUNT 8 | |
#endif | |
#if ipconfigUSE_LINKED_RX_MESSAGES | |
#error Linked RX Messages are not supported by this driver | |
#endif | |
/* Default the size of the stack used by the EMAC deferred handler task to twice | |
* the size of the stack used by the idle task - but allow this to be overridden in | |
* FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */ | |
#ifndef configEMAC_TASK_STACK_SIZE | |
#define configEMAC_TASK_STACK_SIZE (2 * configMINIMAL_STACK_SIZE) | |
#endif | |
#ifndef niEMAC_HANDLER_TASK_PRIORITY | |
#define niEMAC_HANDLER_TASK_PRIORITY ipconfigIP_TASK_PRIORITY | |
#endif | |
#if !defined(ipconfigETHERNET_AN_ENABLE) | |
/* Enable auto-negotiation */ | |
#define ipconfigETHERNET_AN_ENABLE 1 | |
#endif | |
#if !defined(ipconfigETHERNET_USE_100MB) | |
#define ipconfigETHERNET_USE_100MB 1 | |
#endif | |
#if !defined(ipconfigETHERNET_USE_FULL_DUPLEX) | |
#define ipconfigETHERNET_USE_FULL_DUPLEX 1 | |
#endif | |
typedef struct | |
{ | |
uint32_t number_descriptors; | |
uint32_t write; | |
uint32_t read; | |
} tDescriptorList; | |
typedef enum | |
{ | |
eMACInit, /* Must initialise MAC. */ | |
eMACPass, /* Initialisation was successful. */ | |
eMACFailed, /* Initialisation failed. */ | |
} eMAC_INIT_STATUS_TYPE; | |
extern QueueHandle_t xNetworkEventQueue; | |
static eMAC_INIT_STATUS_TYPE _xMacInitStatus = eMACInit; | |
static tEMACDMADescriptor _tx_descriptors[niEMAC_TX_DMA_DESC_COUNT]; | |
static tEMACDMADescriptor _rx_descriptors[niEMAC_RX_DMA_DESC_COUNT]; | |
static tDescriptorList _tx_descriptor_list = {.number_descriptors = niEMAC_TX_DMA_DESC_COUNT, 0}; | |
static tDescriptorList _rx_descriptor_list = {.number_descriptors = niEMAC_RX_DMA_DESC_COUNT, 0}; | |
static uint8_t _network_buffers[ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS][BUFFER_SIZE_ROUNDED_UP] __attribute__((aligned(4))); | |
static TaskHandle_t _deferred_task_handle = NULL; | |
static StaticTask_t _xTaskBuffer; | |
static StackType_t _xStack[configEMAC_TASK_STACK_SIZE]; | |
static volatile uint32_t _linkup; | |
struct xNetworkInterface g_msp432e_Net; | |
extern uint32_t gulSystemClock; | |
static struct error_{ | |
uint32_t rx; | |
uint32_t tx; | |
} gxiferror={0,0}; | |
/** | |
* Reads the Ethernet MAC from user Flash. | |
* @param mac_address_bytes[out] The byte array which will hold the MAC address | |
* @return pdPASS on success, pdFAIL if the MAC is invalid from user Flash | |
*/ | |
BaseType_t ethernet_mac_get_from_flash(uint8_t *mac_address_bytes); | |
/** | |
* Initialize DMA descriptors | |
*/ | |
static void _dma_descriptors_init(void); | |
/** | |
* Frees previously sent network buffers | |
*/ | |
static void _process_transmit_complete(void); | |
/** | |
* Processes received packets and forwards those acceptable to the network stack | |
*/ | |
static BaseType_t _process_received_packet(NetworkInterface_t *pxDescriptor); | |
/** | |
* Processes PHY interrupts. | |
*/ | |
static void _process_phy_interrupts(void); | |
/** | |
* Thread to forward received packets from the ISR to the network stack | |
* @param parameters Not used | |
*/ | |
static void _deferred_rx_task(void *parameters); | |
static void _EMAC_isr(void); | |
BaseType_t port_pfInitialise(NetworkInterface_t *_if) | |
{ | |
uint8_t mac_address_bytes[6]; | |
uint16_t ui16Val; | |
BaseType_t xResult = pdFAIL; | |
if (_xMacInitStatus == eMACInit) | |
{ | |
/* Create the RX packet forwarding task */ | |
_deferred_task_handle = xTaskCreateStatic( | |
_deferred_rx_task, | |
"EMAC RX", | |
configEMAC_TASK_STACK_SIZE, | |
(void*) _if, | |
niEMAC_HANDLER_TASK_PRIORITY, | |
_xStack, | |
&_xTaskBuffer); | |
configASSERT(_deferred_task_handle) | |
/* Read the MAC from user Flash */ | |
if (pdPASS != ethernet_mac_get_from_flash(&mac_address_bytes[0])) | |
{ | |
_xMacInitStatus = eMACFailed; | |
return xResult; | |
} | |
SysCtlPeripheralEnable(SYSCTL_PERIPH_EMAC0); | |
SysCtlPeripheralReset(SYSCTL_PERIPH_EMAC0); | |
SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0); | |
SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0); | |
while (!SysCtlPeripheralReady(SYSCTL_PERIPH_EMAC0)) | |
{ | |
} | |
while (!SysCtlPeripheralReady(SYSCTL_PERIPH_EPHY0)) | |
{ | |
} | |
/*set Internal PHY as EMAC PHY and config the phy defaults, | |
detail config is done below */ | |
EMACPHYConfigSet(EMAC0_BASE, EMAC_PHY_TYPE_INTERNAL | | |
EMAC_PHY_INT_MDIX_EN | | |
EMAC_PHY_AN_100B_T_FULL_DUPLEX); | |
EMACInit(EMAC0_BASE, gulSystemClock, | |
EMAC_BCONFIG_MIXED_BURST | EMAC_BCONFIG_PRIORITY_FIXED, 4, | |
4, 0); | |
EMACConfigSet( | |
EMAC0_BASE, | |
( | |
EMAC_CONFIG_100MBPS | | |
EMAC_CONFIG_FULL_DUPLEX | | |
EMAC_CONFIG_CHECKSUM_OFFLOAD | | |
EMAC_CONFIG_7BYTE_PREAMBLE | | |
EMAC_CONFIG_IF_GAP_96BITS | | |
EMAC_CONFIG_USE_MACADDR0 | | |
EMAC_CONFIG_SA_FROM_DESCRIPTOR | | |
EMAC_CONFIG_BO_LIMIT_1024 | | |
EMAC_CONFIG_STRIP_CRC | |
), | |
( | |
EMAC_MODE_RX_STORE_FORWARD | | |
EMAC_MODE_TX_STORE_FORWARD | | |
EMAC_MODE_RX_THRESHOLD_64_BYTES | | |
EMAC_MODE_TX_THRESHOLD_64_BYTES), | |
0); | |
/*PHY config*/ | |
/* Clear any stray MISR1 PHY interrupts that may be set. */ | |
ui16Val = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1); | |
/* Enable link status change interrupts */ | |
ui16Val = | |
(EPHY_MISR1_LINKSTATEN | | |
EPHY_MISR1_SPEEDEN | | |
EPHY_MISR1_DUPLEXMEN | | |
EPHY_MISR1_ANCEN); | |
EMACPHYWrite(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1, ui16Val); | |
/* Clear any stray MISR2 PHY interrupts that may be set. */ | |
ui16Val = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR2); | |
/* Configure and enable PHY interrupts */ | |
ui16Val = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_SCR); | |
ui16Val |= (EPHY_SCR_INTEN_EXT | EPHY_SCR_INTOE_EXT); | |
EMACPHYWrite(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_SCR, ui16Val); | |
/* Read the PHY interrupt status to clear any stray events. */ | |
ui16Val = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1); | |
/* Set MAC filtering options. We receive all broadcast and mui32ticast */ | |
/* packets along with those addressed specifically for us. */ | |
EMACFrameFilterSet(EMAC0_BASE, (EMAC_FRMFILTER_HASH_AND_PERFECT | | |
EMAC_FRMFILTER_PASS_MULTICAST)); | |
/* Set the MAC address */ | |
EMACAddrSet(EMAC0_BASE, 0, &mac_address_bytes[0]); | |
/* Clears any previously asserted interrupts */ | |
EMACIntClear(EMAC0_BASE, EMACIntStatus(EMAC0_BASE, false)); | |
/* Initialize the DMA descriptors */ | |
_dma_descriptors_init(); | |
/* Set the interrupt to a lower priority than the OS scheduler interrupts */ | |
IntPrioritySet(INT_EMAC0, ((configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1) << (8 - configPRIO_BITS))); | |
_linkup = pdFALSE; | |
IntRegister(INT_EMAC0, _EMAC_isr); | |
/* Enable the Ethernet RX and TX interrupt source. */ | |
EMACIntClear(EMAC0_BASE, EMACIntStatus(EMAC0_BASE, false)); | |
EMACIntEnable(EMAC0_BASE, (EMAC_INT_RECEIVE | EMAC_INT_TRANSMIT | | |
EMAC_INT_TX_STOPPED | EMAC_INT_RX_NO_BUFFER | | |
EMAC_INT_RX_STOPPED | EMAC_INT_PHY)); | |
/* Enable EMAC interrupts */ | |
IntPendClear(INT_EMAC0); | |
IntEnable(INT_EMAC0); | |
_xMacInitStatus = eMACPass; | |
/* Enable TX/RX */ | |
EMACTxEnable(EMAC0_BASE); | |
EMACRxEnable(EMAC0_BASE); | |
xResult = pdPASS; | |
} | |
return xResult; | |
} | |
BaseType_t port_pfOutput(struct xNetworkInterface *pxDescriptor, | |
NetworkBufferDescriptor_t *const pxNetworkBuffer, | |
BaseType_t xReleaseAfterSend) | |
{ | |
BaseType_t success = pdTRUE; | |
tEMACDMADescriptor *dma_descriptor; | |
/* As this driver is strictly zero-copy, assert that the stack does not call this function with */ | |
/* xReleaseAfterSend as false */ | |
configASSERT(0 != xReleaseAfterSend); | |
dma_descriptor = &_tx_descriptors[_tx_descriptor_list.write]; | |
/* If the DMA controller still owns the descriptor, all DMA descriptors are in use, bail out */ | |
if (0U == (dma_descriptor->ui32CtrlStatus & DES0_RX_CTRL_OWN)) | |
{ | |
/* Assign the buffer to the DMA descriptor */ | |
dma_descriptor->pvBuffer1 = pxNetworkBuffer->pucEthernetBuffer; | |
/* Inform the DMA of the size of the packet */ | |
dma_descriptor->ui32Count = (pxNetworkBuffer->xDataLength & DES1_TX_CTRL_BUFF1_SIZE_M) << DES1_TX_CTRL_BUFF1_SIZE_S; | |
/* Inform the DMA that this is the first and last segment of the packet, calculate the checksums, the descriptors are */ | |
/* chained, and to use interrupts */ | |
dma_descriptor->ui32CtrlStatus = DES0_TX_CTRL_FIRST_SEG | DES0_TX_CTRL_IP_ALL_CKHSUMS | DES0_TX_CTRL_CHAINED | DES0_TX_CTRL_LAST_SEG | DES0_TX_CTRL_INTERRUPT | DES0_TX_CTRL_REPLACE_CRC; | |
/* Advance the index in the list */ | |
_tx_descriptor_list.write++; | |
/* Wrap around if required */ | |
if (_tx_descriptor_list.write == niEMAC_TX_DMA_DESC_COUNT) | |
{ | |
_tx_descriptor_list.write = 0; | |
} | |
/* Give the DMA descriptor to the DMA controller */ | |
dma_descriptor->ui32CtrlStatus |= DES0_TX_CTRL_OWN; | |
/* Inform the DMA it has a new descriptor */ | |
EMACTxDMAPollDemand(EMAC0_BASE); | |
iptraceNETWORK_INTERFACE_TRANSMIT(); | |
} | |
else | |
{ | |
/* Release the stack descriptor and buffer to prevent memory leaks. */ | |
vReleaseNetworkBufferAndDescriptor(pxNetworkBuffer); | |
success = pdFALSE; | |
gxiferror.tx++; | |
} | |
return success; | |
} | |
void vNetworkInterfaceAllocateRAMToBuffers(NetworkBufferDescriptor_t pxNetworkBuffers[ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS]) | |
{ | |
BaseType_t i; | |
for (i = 0; i < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; i++) | |
{ | |
/* Assign buffers to each descriptor */ | |
pxNetworkBuffers[i].pucEthernetBuffer = &_network_buffers[i][ipBUFFER_PADDING]; | |
/* Set the 'hidden' reference to the descriptor for use in DMA interrupts */ | |
*((uint32_t *)&_network_buffers[i][0]) = (uint32_t) & ((pxNetworkBuffers[i])); | |
} | |
} | |
BaseType_t ethernet_mac_get_from_flash(uint8_t *mac_address_bytes) | |
{ | |
BaseType_t success = pdPASS; | |
uint32_t mac_address_w0 = 0, mac_address_w1 = 0; | |
/* Attempt to read the MAC address */ | |
FlashUserGet(&mac_address_w0, &mac_address_w1); | |
/* If the MAC is not set, fail */ | |
if ((0xFFFFFFFF == mac_address_w0) || (0xFFFFFFFF == mac_address_w1)) | |
{ | |
success = pdFAIL; | |
} | |
else | |
{ | |
/* Otherwise return the MAC address in a usable format for the driver */ | |
mac_address_bytes[0] = (mac_address_w0 >> 0) & 0xFF; | |
mac_address_bytes[1] = (mac_address_w0 >> 8) & 0xFF; | |
mac_address_bytes[2] = (mac_address_w0 >> 16) & 0xFF; | |
mac_address_bytes[3] = (mac_address_w1 >> 0) & 0xFF; | |
mac_address_bytes[4] = (mac_address_w1 >> 8) & 0xFF; | |
mac_address_bytes[5] = (mac_address_w1 >> 16) & 0xFF; | |
} | |
return success; | |
} | |
static void _dma_descriptors_init(void) | |
{ | |
uint32_t i; | |
const size_t buffer_size_requested = BUFFER_SIZE_WO_PADDING; | |
NetworkBufferDescriptor_t *stack_descriptor; | |
/* Initialize the TX DMA descriptors */ | |
for (i = 0; i < niEMAC_TX_DMA_DESC_COUNT; i++) | |
{ | |
/* Clear the length of the packet */ | |
_tx_descriptors[i].ui32Count = 0; | |
/* Clear the reference to the buffer */ | |
_tx_descriptors[i].pvBuffer1 = NULL; | |
/* Set the next link in the DMA descriptor chain, either the next in the chain or the first descriptor in the event */ | |
/* that this is the last descriptor */ | |
_tx_descriptors[i].DES3.pLink = ((i == (niEMAC_TX_DMA_DESC_COUNT - 1)) ? &_tx_descriptors[0] : &_tx_descriptors[i + 1]); | |
_tx_descriptors[i].ui32CtrlStatus = DES0_TX_CTRL_INTERRUPT | DES0_TX_CTRL_CHAINED | DES0_TX_CTRL_IP_ALL_CKHSUMS; | |
} | |
/* Set the TX descriptor index */ | |
_tx_descriptor_list.write = 0; | |
_tx_descriptor_list.read = 0; | |
for (i = 0; i < niEMAC_RX_DMA_DESC_COUNT; i++) | |
{ | |
stack_descriptor = pxGetNetworkBufferWithDescriptor(ipTOTAL_ETHERNET_FRAME_SIZE, 0); | |
configASSERT(NULL != stack_descriptor); | |
/* Get a buffer from the stack and assign it to the DMA Descriptor */ | |
_rx_descriptors[i].pvBuffer1 = stack_descriptor->pucEthernetBuffer; | |
/* Inform the DMA controller that the descriptors are chained and the size of the buffer */ | |
_rx_descriptors[i].ui32Count = DES1_RX_CTRL_CHAINED | ((buffer_size_requested << DES1_TX_CTRL_BUFF1_SIZE_S) & DES1_TX_CTRL_BUFF1_SIZE_M); | |
/* Give the DMA descriptor to the DMA controller */ | |
_rx_descriptors[i].ui32CtrlStatus = DES0_RX_CTRL_OWN; | |
/* Set the next link the DMA descriptor chain */ | |
_rx_descriptors[i].DES3.pLink = ((i == (niEMAC_RX_DMA_DESC_COUNT - 1)) ? &_rx_descriptors[0] : &_rx_descriptors[i + 1]); | |
} | |
/* Set the RX descriptor index */ | |
_rx_descriptor_list.write = 0; | |
/* Set the head of the DMA descriptor list in the EMAC peripheral */ | |
EMACTxDMADescriptorListSet(EMAC0_BASE, &_tx_descriptors[0]); | |
EMACRxDMADescriptorListSet(EMAC0_BASE, &_rx_descriptors[0]); | |
} | |
static void _EMAC_isr(void) | |
{ | |
uint32_t status; | |
BaseType_t higher_priority_task_woken = pdFALSE; | |
/* Read the interrupt status */ | |
status = EMACIntStatus(EMAC0_BASE, true); | |
/* Handle power management interrupts */ | |
if (status & EMAC_INT_POWER_MGMNT) | |
{ | |
EMACTxEnable(EMAC0_BASE); | |
EMACRxEnable(EMAC0_BASE); | |
EMACPowerManagementStatusGet(EMAC0_BASE); | |
status &= ~(EMAC_INT_POWER_MGMNT); | |
} | |
if (status) | |
{ | |
EMACIntClear(EMAC0_BASE, status); | |
EMACIntDisable(EMAC0_BASE, (EMAC_INT_RECEIVE | EMAC_INT_TRANSMIT | | |
EMAC_INT_TX_STOPPED | EMAC_INT_RX_NO_BUFFER | | |
EMAC_INT_RX_STOPPED | EMAC_INT_PHY)); | |
/* Handle PHY interrupts */ | |
if (EMAC_INT_PHY & status) | |
{ | |
_process_phy_interrupts(); | |
} | |
/* Handle Transmit Complete interrupts */ | |
if (EMAC_INT_TRANSMIT & status) | |
{ | |
_process_transmit_complete(); | |
} | |
/* Handle Receive interrupts */ | |
if ((EMAC_INT_RECEIVE | EMAC_INT_RX_NO_BUFFER | EMAC_INT_RX_STOPPED) & status) | |
{ | |
vTaskNotifyGiveFromISR(_deferred_task_handle, &higher_priority_task_woken); | |
portYIELD_FROM_ISR(higher_priority_task_woken); | |
} | |
EMACIntEnable(EMAC0_BASE, (EMAC_INT_RECEIVE | EMAC_INT_TRANSMIT | | |
EMAC_INT_TX_STOPPED | EMAC_INT_RX_NO_BUFFER | | |
EMAC_INT_RX_STOPPED | EMAC_INT_PHY)); | |
} | |
} | |
static void _process_transmit_complete(void) | |
{ | |
uint32_t i; | |
tEMACDMADescriptor *dma_descriptor; | |
NetworkBufferDescriptor_t *pxstack_descriptor; | |
BaseType_t higher_priority_task_woken = pdFALSE; | |
for (i = 0; ((i < _tx_descriptor_list.number_descriptors) && (_tx_descriptor_list.read != _tx_descriptor_list.write)); i++) | |
{ | |
/* Get a reference to the current DMA descriptor */ | |
dma_descriptor = &_tx_descriptors[_tx_descriptor_list.read]; | |
/* If the descriptor is still owned by the DMA controller, exit */ | |
if (dma_descriptor->ui32CtrlStatus & DES0_TX_CTRL_OWN) | |
{ | |
break; | |
} | |
/* Get the 'hidden' reference to the stack descriptor from the buffer */ | |
pxstack_descriptor = pxPacketBuffer_to_NetworkBuffer(dma_descriptor->pvBuffer1); | |
configASSERT(NULL != pxstack_descriptor); | |
/* Release the stack descriptor */ | |
higher_priority_task_woken = vNetworkBufferReleaseFromISR(pxstack_descriptor); | |
vTaskNotifyGiveFromISR(_deferred_task_handle, &higher_priority_task_woken); | |
_tx_descriptor_list.read++; | |
if (_tx_descriptor_list.read == _tx_descriptor_list.number_descriptors) | |
{ | |
_tx_descriptor_list.read = 0; | |
} | |
} | |
} | |
static BaseType_t _process_received_packet(NetworkInterface_t *pxDescriptor) | |
{ | |
NetworkBufferDescriptor_t *new_stack_descriptor; | |
NetworkBufferDescriptor_t *cur_stack_descriptor; | |
tEMACDMADescriptor *dma_descriptor; | |
uint32_t i; | |
IPStackEvent_t event; | |
BaseType_t result = pdTRUE; | |
const TickType_t max_block_time = 0; // pdMS_TO_MIN_TICKS(1); | |
const size_t buffer_size_requested = BUFFER_SIZE_WO_PADDING; | |
/* Go through the list of RX DMA descriptors */ | |
for (i = 0; i < niEMAC_RX_DMA_DESC_COUNT; i++) | |
{ | |
/* Get a reference to the descriptor */ | |
dma_descriptor = &_rx_descriptors[_rx_descriptor_list.write]; | |
/* Make sure the buffer is non-null */ | |
configASSERT(NULL != dma_descriptor->pvBuffer1); | |
/* If the descriptor is still in use by DMA, stop processing here */ | |
if (DES0_RX_CTRL_OWN == (dma_descriptor->ui32CtrlStatus & DES0_RX_CTRL_OWN)) | |
{ | |
break; | |
} | |
/* If there is NOT an error in the frame */ | |
if (0U == (dma_descriptor->ui32CtrlStatus & DES0_RX_STAT_ERR)) | |
{ | |
/* Get a new empty descriptor */ | |
new_stack_descriptor = pxGetNetworkBufferWithDescriptor(ipTOTAL_ETHERNET_FRAME_SIZE, max_block_time); | |
/* If a descriptor was provided, else this packet is dropped */ | |
if (NULL != new_stack_descriptor) | |
{ | |
/* Get a reference to the current stack descriptor held by the DMA descriptor */ | |
cur_stack_descriptor = pxPacketBuffer_to_NetworkBuffer(dma_descriptor->pvBuffer1); | |
/* Set the length of the buffer on the current descriptor */ | |
cur_stack_descriptor->xDataLength = ((dma_descriptor->ui32CtrlStatus & DES0_RX_STAT_FRAME_LENGTH_M) >> DES0_RX_STAT_FRAME_LENGTH_S); | |
/* Assign the new stack descriptor to the DMA descriptor */ | |
dma_descriptor->pvBuffer1 = new_stack_descriptor->pucEthernetBuffer; | |
/* Ask the stack if it wants to process the frame. */ | |
if (eProcessBuffer == eConsiderFrameForProcessing(cur_stack_descriptor->pucEthernetBuffer)) | |
{ | |
cur_stack_descriptor->pxEndPoint = FreeRTOS_MatchingEndpoint(pxDescriptor, | |
cur_stack_descriptor->pucEthernetBuffer); | |
if (cur_stack_descriptor->pxEndPoint != NULL) | |
{ | |
/* Setup the event */ | |
event.eEventType = eNetworkRxEvent; | |
event.pvData = cur_stack_descriptor; | |
/* Forward the event */ | |
if (pdFALSE == xSendEventStructToIPTask(&event, max_block_time)) | |
{ | |
/* Release the buffer if an error was encountered */ | |
vReleaseNetworkBufferAndDescriptor(cur_stack_descriptor); | |
iptraceETHERNET_RX_EVENT_LOST(); | |
} | |
else | |
{ | |
iptraceNETWORK_INTERFACE_RECEIVE(); | |
result = pdTRUE; | |
} | |
} | |
} | |
else | |
{ | |
/* Free the descriptor */ | |
vReleaseNetworkBufferAndDescriptor(cur_stack_descriptor); | |
} | |
} /* end if descriptor is available */ | |
else | |
{ | |
/* No stack descriptor was available for the next RX DMA descriptor so this packet */ | |
/* is dropped */ | |
gxiferror.rx++; | |
/* Mark the RX event as lost */ | |
iptraceETHERNET_RX_EVENT_LOST(); | |
} | |
} /* end if frame had error. In this case, give the buffer back to the DMA for the next RX */ | |
/* Set up the DMA descriptor for the next receive transaction */ | |
dma_descriptor->ui32Count = DES1_RX_CTRL_CHAINED | ((buffer_size_requested << DES1_RX_CTRL_BUFF1_SIZE_S) & DES1_RX_CTRL_BUFF1_SIZE_M); | |
/* Give this descriptor back to the hardware */ | |
dma_descriptor->ui32CtrlStatus = DES0_RX_CTRL_OWN; | |
_rx_descriptor_list.write++; | |
if (_rx_descriptor_list.write == _rx_descriptor_list.number_descriptors) | |
{ | |
_rx_descriptor_list.write = 0; | |
} | |
} | |
return result; | |
} | |
/** | |
* This deferred interrupt handler process changes from the PHY auto-negotiation to configure the | |
* MAC as appropriate. | |
*/ | |
static void _process_phy_interrupts(void) | |
{ | |
uint16_t value; | |
uint16_t status; | |
uint32_t configuration; | |
uint32_t mode; | |
uint32_t max_frame_size; | |
/* | |
* Read the PHY interrupt status. This clears all interrupt sources. | |
* Note that we are only enabling sources in EPHY_MISR1 so we don't | |
* read EPHY_MISR2. | |
*/ | |
value = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_MISR1); | |
status = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_STS); | |
if (value & (EPHY_MISR1_SPEED | EPHY_MISR1_DUPLEXM | EPHY_MISR1_ANC)) | |
{ | |
/* If the speed or duplex has changed */ | |
EMACConfigGet(EMAC0_BASE, &configuration, &mode, &max_frame_size); | |
/* What speed is the interface running at now? */ | |
if (status & EPHY_STS_SPEED) | |
{ | |
configuration &= ~EMAC_CONFIG_100MBPS; | |
} | |
else | |
{ | |
configuration |= EMAC_CONFIG_100MBPS; | |
} | |
if (status & EPHY_STS_DUPLEX) | |
{ | |
configuration |= EMAC_CONFIG_FULL_DUPLEX; | |
} | |
else | |
{ | |
configuration &= ~EMAC_CONFIG_FULL_DUPLEX; | |
} | |
EMACConfigSet(EMAC0_BASE, configuration, mode, max_frame_size); | |
} | |
/* Has the link status changed? */ | |
if (value & EPHY_MISR1_LINKSTAT) | |
{ | |
/*IPStackEvent_t link_event; | |
BaseType_t xReturn; | |
Is link up or down now? */ | |
status = EMACPHYRead(EMAC0_BASE, PHY_PHYS_ADDR, EPHY_BMSR); | |
if (status & EPHY_BMSR_LINKSTAT) | |
{ | |
_linkup = pdTRUE; | |
// link_event.eEventType = eNetworkUp; | |
} | |
else | |
{ | |
_linkup = pdFALSE; | |
// FreeRTOS_NetworkDownFromISR(&g_msp432e_Net); | |
iptraceNETWORK_DOWN() | |
} | |
// link_event.pvData = NULL; | |
// xReturn = xQueueSendToBack(xNetworkEventQueue, &link_event, 0); | |
// if (xReturn == pdFAIL) | |
// { | |
// /* A message should have been sent to the IP task, but wasn't. */ | |
// iptraceSTACK_TX_EVENT_LOST(link_event.eEventType); | |
// } | |
} | |
} | |
static void _deferred_rx_task(void *parameters) | |
{ | |
struct xNetworkInterface *pxDescriptor=(struct xNetworkInterface *)parameters; | |
for (;;) | |
{ | |
ulTaskNotifyTake(pdTRUE, portMAX_DELAY); | |
_process_received_packet(pxDescriptor); | |
} | |
} | |
static BaseType_t portGetPhyLinkStatus(struct xNetworkInterface *pxDescriptor) | |
{ | |
return _linkup; | |
} | |
NetworkInterface_t *pxMSP432e401Y_FillInterfaceDescriptor(struct xNetworkInterface *pxInterface) | |
{ | |
pxInterface->pcName = "EMAC0 on PHY0"; | |
pxInterface->pvArgument = (void *)NULL; | |
pxInterface->pfInitialise = port_pfInitialise; | |
pxInterface->pfOutput = port_pfOutput; | |
pxInterface->pfGetPhyLinkStatus = portGetPhyLinkStatus; | |
pxInterface->bits.bInterfaceUp = 0; | |
pxInterface->bits.bCallDownEvent = 0; | |
FreeRTOS_AddNetworkInterface(pxInterface); | |
return pxInterface; | |
} | |
#if defined(ipconfigIPv4_BACKWARD_COMPATIBLE) && (ipconfigIPv4_BACKWARD_COMPATIBLE == 1) | |
networkdrivers | |
/* Do not call the following function directly. It is there for downward compatibility. | |
* The function FreeRTOS_IPInit() will call it to initialice the interface and end-point | |
* objects. See the description in FreeRTOS_Routing.h. */ | |
struct xNetworkInterface *pxFillInterfaceDescriptor(BaseType_t xEMACIndex, | |
NetworkInterface_t *pxInterface) | |
{ | |
return pxMSP432e401Y_FillInterfaceDescriptor(pxInterface); | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment