Skip to content

Instantly share code, notes, and snippets.

@e-sr
Created November 7, 2023 13:13
Show Gist options
  • Save e-sr/54df1959a65d0980c6b193521fb04b0c to your computer and use it in GitHub Desktop.
Save e-sr/54df1959a65d0980c6b193521fb04b0c to your computer and use it in GitHub Desktop.
FreeRTOS-Plus TCP-msp432e401y-networkdrivers
/**
* @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