This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS570LS1227: Help Needed for Converting Ethernet Driver to HalCoGen Generated APIs

Part Number: TMS570LS1227
Other Parts Discussed in Thread: HALCOGEN

Tool/software:

/**
 * @file tms570_eth_driver.c
 * @brief TMS570 Ethernet MAC driver
 *
 * @section License
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 *
 * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
 *
 * This file is part of CycloneTCP Open.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * @author Oryx Embedded SARL (www.oryx-embedded.com)
 * @version 2.4.2
 **/

//Switch to the appropriate trace level
#define TRACE_LEVEL NIC_TRACE_LEVEL

//Platform-specific dependencies
#if defined(_TMS570LC43x_)
#include "hl_hw_reg_access.h"
#include "hl_hw_emac.h"
#include "hl_hw_emac_ctrl.h"
#include "hl_hw_mdio.h"
#include "hl_gio.h"
#include "hl_sys_vim.h"
#else
#include "hw_reg_access.h"
#include "hw_emac.h"
#include "hw_emac_ctrl.h"
#include "hw_mdio.h"
#include "gio.h"
#include "sys_vim.h"
#endif

//Dependencies
#include "core/net.h"
#include "drivers/mac/tms570_eth_driver.h"
#include "debug.h"

//MDIO input clock frequency
#define MDIO_INPUT_CLK 75000000
//MDIO output clock frequency
#define MDIO_OUTPUT_CLK 1000000

//Byte-swapped read/write accesses to CPPI memory?
#if defined(_TMS570LC43x_)
#define CPPI_SWAP(x) swapInt32((uint32_t) (x))
#else
#define CPPI_SWAP(x) ((uint32_t) (x))
#endif

//Underlying network interface
static NetInterface *nicDriverInterface;

//IAR EWARM compiler?
#if defined(__ICCARM__)

//Transmit buffer
#pragma data_alignment = 4
#pragma location = TMS570_ETH_RAM_SECTION
static uint8_t txBuffer[TMS570_ETH_TX_BUFFER_COUNT][TMS570_ETH_TX_BUFFER_SIZE];
//Receive buffer
#pragma data_alignment = 4
#pragma location = TMS570_ETH_RAM_SECTION
static uint8_t rxBuffer[TMS570_ETH_RX_BUFFER_COUNT][TMS570_ETH_RX_BUFFER_SIZE];
//Transmit buffer descriptors
#pragma data_alignment = 4
#pragma location = TMS570_ETH_RAM_CPPI_SECTION
static Tms570TxBufferDesc txBufferDesc[TMS570_ETH_TX_BUFFER_COUNT];
//Receive buffer descriptors
#pragma data_alignment = 4
#pragma location = TMS570_ETH_RAM_CPPI_SECTION
static Tms570RxBufferDesc rxBufferDesc[TMS570_ETH_RX_BUFFER_COUNT];

//GCC compiler?
#else

//Transmit buffer
static uint8_t txBuffer[TMS570_ETH_TX_BUFFER_COUNT][TMS570_ETH_TX_BUFFER_SIZE]
                                                    __attribute__((aligned(4), __section__(TMS570_ETH_RAM_SECTION)));
//Receive buffer
static uint8_t rxBuffer[TMS570_ETH_RX_BUFFER_COUNT][TMS570_ETH_RX_BUFFER_SIZE]
                                                    __attribute__((aligned(4), __section__(TMS570_ETH_RAM_SECTION)));
//Transmit buffer descriptors
static Tms570TxBufferDesc txBufferDesc[TMS570_ETH_TX_BUFFER_COUNT]
                                       __attribute__((aligned(4), __section__(TMS570_ETH_RAM_CPPI_SECTION)));
//Receive buffer descriptors
static Tms570RxBufferDesc rxBufferDesc[TMS570_ETH_RX_BUFFER_COUNT]
                                       __attribute__((aligned(4), __section__(TMS570_ETH_RAM_CPPI_SECTION)));

#endif

//Pointer to the current TX buffer descriptor
static Tms570TxBufferDesc *txCurBufferDesc;
//Pointer to the current RX buffer descriptor
static Tms570RxBufferDesc *rxCurBufferDesc;


/**
 * @brief TMS570 Ethernet MAC driver
 **/

const NicDriver tms570EthDriver =
{
 NIC_TYPE_ETHERNET,
 ETH_MTU,
 tms570EthInit,
 tms570EthTick,
 tms570EthEnableIrq,
 tms570EthDisableIrq,
 tms570EthEventHandler,
 tms570EthSendPacket,
 tms570EthUpdateMacAddrFilter,
 tms570EthUpdateMacConfig,
 tms570EthWritePhyReg,
 tms570EthReadPhyReg,
 FALSE,
 TRUE,
 TRUE,
 FALSE
};


/**
 * @brief TMS570 Ethernet MAC initialization
 * @param[in] interface Underlying network interface
 * @return Error code
 **/

error_t tms570EthInit(NetInterface *interface)
{
    error_t error;
    uint_t channel;
    uint32_t temp;

    //Debug message
    TRACE_INFO("Initializing TMS570 Ethernet MAC...\r\n");

    //Save underlying network interface
    nicDriverInterface = interface;

    //Select the interface mode (MII/RMII) and configure pin muxing
    tms570EthInitGpio(interface);

    //Reset the EMAC control module
    EMAC_CTRL_SOFTRESET_R = EMAC_SOFTRESET_SOFTRESET;
    //Wait for the reset to complete
    while((EMAC_CTRL_SOFTRESET_R & EMAC_SOFTRESET_SOFTRESET) != 0)
    {
    }

    //Reset the EMAC module
    EMAC_SOFTRESET_R = EMAC_SOFTRESET_SOFTRESET;
    //Wait for the reset to complete
    while((EMAC_SOFTRESET_R & EMAC_SOFTRESET_SOFTRESET) != 0)
    {
    }

    //Calculate the MDC clock divider to be used
    temp = (MDIO_INPUT_CLK / MDIO_OUTPUT_CLK) - 1;

    //Initialize MDIO interface
    MDIO_CONTROL_R = MDIO_CONTROL_ENABLE |
            MDIO_CONTROL_FAULTENB | (temp & MDIO_CONTROL_CLKDIV);

    //Valid Ethernet PHY or switch driver?
    if(interface->phyDriver != NULL)
    {
        //Ethernet PHY initialization
        error = interface->phyDriver->init(interface);
    }
    else if(interface->switchDriver != NULL)
    {
        //Ethernet switch initialization
        error = interface->switchDriver->init(interface);
    }
    else
    {
        //The interface is not properly configured
        error = ERROR_FAILURE;
    }

    //Any error to report?
    if(error)
    {
        return error;
    }

    //Clear the control registers
    EMAC_MACCONTROL_R = 0;
    EMAC_RXCONTROL_R = 0;
    EMAC_TXCONTROL_R = 0;

    //Initialize all 16 header descriptor pointer registers to 0
    for(channel = EMAC_CH0; channel <= EMAC_CH7; channel++)
    {
        //TX head descriptor pointer
        EMAC_TXHDP_R(channel) = 0;
        //TX completion pointer
        EMAC_TXCP_R(channel) = 0;
        //RX head descriptor pointer
        EMAC_RXHDP_R(channel) = 0;
        //RX completion pointer
        EMAC_RXCP_R(channel) = 0;
    }

    //Set the upper 32 bits of the source MAC address
    EMAC_MACSRCADDRHI_R = interface->macAddr.b[0] |
            (interface->macAddr.b[1] << 8) |
            (interface->macAddr.b[2] << 16) |
            (interface->macAddr.b[3] << 24);

    //Set the lower 16 bits of the source MAC address
    EMAC_MACSRCADDRLO_R = interface->macAddr.b[4] |
            (interface->macAddr.b[5] << 8);

    //Write the channel number to the MAC index register
    EMAC_MACINDEX_R = EMAC_CH0;

    //Set the upper 32 bits of the destination MAC address
    EMAC_MACADDRHI_R = interface->macAddr.b[0] |
            (interface->macAddr.b[1] << 8) |
            (interface->macAddr.b[2] << 16) |
            (interface->macAddr.b[3] << 24);

    //Set the lower 16 bits of the destination MAC address
    temp = interface->macAddr.b[4] |
            (interface->macAddr.b[5] << 8);

    //Use the current MAC address to match incoming packet addresses
    EMAC_MACADDRLO_R = EMAC_MACADDRLO_VALID | EMAC_MACADDRLO_MATCHFILT |
            (EMAC_CH0 << EMAC_MACADDRLO_CHANNEL_SHIFT) | temp;

    //Be sure to program all eight MAC address registers, whether the
    //receive channel is to be enabled or not
    for(channel = EMAC_CH1; channel <= EMAC_CH7; channel++)
    {
        //Write the channel number to the MAC index register
        EMAC_MACINDEX_R = channel;
        //The MAC address is not valid
        EMAC_MACADDRLO_R = (channel << EMAC_MACADDRLO_CHANNEL_SHIFT);
    }

    //Clear the MAC address hash registers
    EMAC_MACHASH1_R = 0;
    EMAC_MACHASH2_R = 0;

    //The RX buffer offset must be initialized to zero
    EMAC_RXBUFFEROFFSET_R = 0;

    //Clear all unicast channels
    EMAC_RXUNICASTCLEAR_R = 0xFF;

    //Accept unicast frames
    EMAC_RXUNICASTSET_R |= (1 << EMAC_CH0);

    //Received CRC is transferred to memory for all channels
    EMAC_RXMBPENABLE_R = EMAC_RXMBPENABLE_RXPASSCRC;

    //Accept broadcast frames
    EMAC_RXMBPENABLE_R |= EMAC_RXMBPENABLE_RXBROADEN |
            (EMAC_CH0 << EMAC_RXMBPENABLE_RXBROADCH_SHIFT);

    //Accept hash matching multicast frames
    EMAC_RXMBPENABLE_R |= EMAC_RXMBPENABLE_RXMULTEN |
            (EMAC_CH0 << EMAC_RXMBPENABLE_RXMULTCH_SHIFT);

    //Register TX interrupt handler
    vimChannelMap(TMS570_ETH_TX_IRQ_CHANNEL, TMS570_ETH_TX_IRQ_CHANNEL,
                  (t_isrFuncPTR) tms570EthTxIrqHandler);

    //Register RX interrupt handler
    vimChannelMap(TMS570_ETH_RX_IRQ_CHANNEL, TMS570_ETH_RX_IRQ_CHANNEL,
                  (t_isrFuncPTR) tms570EthRxIrqHandler);

    //Clear all unused channel interrupt bits
    EMAC_TXINTMASKCLEAR_R = 0xFF;
    EMAC_RXINTMASKCLEAR_R = 0xFF;

    //Enable the receive and transmit channel interrupt bits
    EMAC_TXINTMASKSET_R = (1 << EMAC_CH0);
    EMAC_RXINTMASKSET_R = (1 << EMAC_CH0);

    //Configure TX and RX buffer descriptors
    tms570EthInitBufferDesc(interface);

    //Write the RX DMA head descriptor pointer
    EMAC_RXHDP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc;

    //Enable the receive and transmit DMA controllers
    EMAC_TXCONTROL_R = EMAC_TXCONTROL_TXEN;
    EMAC_RXCONTROL_R = EMAC_RXCONTROL_RXEN;

    //Enable TX and RX
    EMAC_MACCONTROL_R = EMAC_MACCONTROL_GMIIEN;

    //Enable TX and RX completion interrupts
    EMAC_CTRL_CnTXEN_R(EMAC_CORE0) |= (1 << EMAC_CH0);
    EMAC_CTRL_CnRXEN_R(EMAC_CORE0) |= (1 << EMAC_CH0);

    //Accept any packets from the upper layer
    osSetEvent(&interface->nicTxEvent);

    //Successful initialization
    return NO_ERROR;
}


/**
 * @brief GPIO configuration
 * @param[in] interface Underlying network interface
 **/

__weak_func void tms570EthInitGpio(NetInterface *interface)
{
    //LAUNCHXL2-570LC43 evaluation board?
#if defined(USE_LAUNCHXL2_570LC43)
    //Configure PHY_INT (PA_3) as an input
    gioPORTA->DIR &= ~(1 << 3);
    gioPORTA->PSL |= (1 << 3);
    gioPORTA->PULDIS &= ~(1 << 3);

    //Configure PHY_RST (PA_4) as an output
    gioPORTA->DIR |= (1 << 4);
    gioPORTA->PDR &= ~(1 << 4);

    //Reset PHY transceiver
    gioPORTA->DCLR = (1 << 4);
    sleep(10);
    gioPORTA->DSET = (1 << 4);
    sleep(10);
#endif
}


/**
 * @brief Initialize buffer descriptor lists
 * @param[in] interface Underlying network interface
 **/

void tms570EthInitBufferDesc(NetInterface *interface)
{
    uint_t i;
    uint_t nextIndex;
    uint_t prevIndex;

    //Initialize TX buffer descriptor list
    for(i = 0; i < TMS570_ETH_TX_BUFFER_COUNT; i++)
    {
        //Index of the next buffer
        nextIndex = (i + 1) % TMS570_ETH_TX_BUFFER_COUNT;
        //Index of the previous buffer
        prevIndex = (i + TMS570_ETH_TX_BUFFER_COUNT - 1) % TMS570_ETH_TX_BUFFER_COUNT;

        //Next descriptor pointer
        txBufferDesc[i].word0 = CPPI_SWAP(NULL);
        //Buffer pointer
        txBufferDesc[i].word1 = CPPI_SWAP(txBuffer[i]);
        //Buffer offset and buffer length
        txBufferDesc[i].word2 = CPPI_SWAP(0);
        //Status flags and packet length
        txBufferDesc[i].word3 = CPPI_SWAP(0);

        //Form a doubly linked list
        txBufferDesc[i].next = &txBufferDesc[nextIndex];
        txBufferDesc[i].prev = &txBufferDesc[prevIndex];
    }

    //Point to the very first descriptor
    txCurBufferDesc = &txBufferDesc[0];

    //Mark the end of the queue
    txCurBufferDesc->prev->word3 = CPPI_SWAP(EMAC_TX_WORD3_SOP |
                                             EMAC_TX_WORD3_EOP | EMAC_TX_WORD3_EOQ);

    //Initialize RX buffer descriptor list
    for(i = 0; i < TMS570_ETH_RX_BUFFER_COUNT; i++)
    {
        //Index of the next buffer
        nextIndex = (i + 1) % TMS570_ETH_RX_BUFFER_COUNT;
        //Index of the previous buffer
        prevIndex = (i + TMS570_ETH_RX_BUFFER_COUNT - 1) % TMS570_ETH_RX_BUFFER_COUNT;

        //Next descriptor pointer
        rxBufferDesc[i].word0 = CPPI_SWAP(&rxBufferDesc[nextIndex]);
        //Buffer pointer
        rxBufferDesc[i].word1 = CPPI_SWAP(rxBuffer[i]);
        //Buffer offset and buffer length
        rxBufferDesc[i].word2 = CPPI_SWAP(TMS570_ETH_RX_BUFFER_SIZE);
        //Status flags and packet length
        rxBufferDesc[i].word3 = CPPI_SWAP(EMAC_RX_WORD3_OWNER);

        //Form a doubly linked list
        rxBufferDesc[i].next = &rxBufferDesc[nextIndex];
        rxBufferDesc[i].prev = &rxBufferDesc[prevIndex];
    }

    //Point to the very first descriptor
    rxCurBufferDesc = &rxBufferDesc[0];

    //Mark the end of the queue
    //   rxCurBufferDesc->prev->word0 = CPPI_SWAP(NULL);
}


/**
 * @brief TMS570 Ethernet MAC timer handler
 *
 * This routine is periodically called by the TCP/IP stack to handle periodic
 * operations such as polling the link state
 *
 * @param[in] interface Underlying network interface
 **/

void tms570EthTick(NetInterface *interface)
{
    //Valid Ethernet PHY or switch driver?
    if(interface->phyDriver != NULL)
    {
        //Handle periodic operations
        interface->phyDriver->tick(interface);
    }
    else if(interface->switchDriver != NULL)
    {
        //Handle periodic operations
        interface->switchDriver->tick(interface);
    }
    else
    {
        //Just for sanity
    }

    //Misqueued buffer condition?
    if(CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_OWNER)
    {
        if(EMAC_RXHDP_R(EMAC_CH0) == 0)
        {
            //The host acts on the misqueued buffer condition by writing the added
            //buffer descriptor address to the appropriate RX DMA head descriptor
            //pointer
            EMAC_RXHDP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc;
        }
    }
}


/**
 * @brief Enable interrupts
 * @param[in] interface Underlying network interface
 **/

void tms570EthEnableIrq(NetInterface *interface)
{
    //Enable Ethernet MAC interrupts
    vimEnableInterrupt(TMS570_ETH_TX_IRQ_CHANNEL, SYS_IRQ);
    vimEnableInterrupt(TMS570_ETH_RX_IRQ_CHANNEL, SYS_IRQ);

    //Valid Ethernet PHY or switch driver?
    if(interface->phyDriver != NULL)
    {
        //Enable Ethernet PHY interrupts
        interface->phyDriver->enableIrq(interface);
    }
    else if(interface->switchDriver != NULL)
    {
        //Enable Ethernet switch interrupts
        interface->switchDriver->enableIrq(interface);
    }
    else
    {
        //Just for sanity
    }
}


/**
 * @brief Disable interrupts
 * @param[in] interface Underlying network interface
 **/

void tms570EthDisableIrq(NetInterface *interface)
{
    //Disable Ethernet MAC interrupts
    vimDisableInterrupt(TMS570_ETH_TX_IRQ_CHANNEL);
    vimDisableInterrupt(TMS570_ETH_RX_IRQ_CHANNEL);

    //Valid Ethernet PHY or switch driver?
    if(interface->phyDriver != NULL)
    {
        //Disable Ethernet PHY interrupts
        interface->phyDriver->disableIrq(interface);
    }
    else if(interface->switchDriver != NULL)
    {
        //Disable Ethernet switch interrupts
        interface->switchDriver->disableIrq(interface);
    }
    else
    {
        //Just for sanity
    }
}


/**
 * @brief Ethernet MAC transmit interrupt
 **/

#if defined(__ICCARM__)
__irq __arm
#else
#pragma CODE_STATE(tms570EthTxIrqHandler, 32)
#pragma INTERRUPT(tms570EthTxIrqHandler, IRQ)
#endif

void tms570EthTxIrqHandler(void)
{
    bool_t flag;
    uint32_t status;
    uint32_t temp;
    Tms570TxBufferDesc *p;

    //Interrupt service routine prologue
    osEnterIsr();

    //This flag will be set if a higher priority task must be woken
    flag = FALSE;

    //Read the C0TXSTAT register to determine which channels caused the interrupt
    status = EMAC_CTRL_C0TXSTAT_R;

    //Packet transmitted on channel 0?
    if(status & (1 << EMAC_CH0))
    {
        //Point to the buffer descriptor
        p = (Tms570TxBufferDesc *) EMAC_TXCP_R(EMAC_CH0);

        //Read the status flags
        temp = CPPI_SWAP(p->word3) & (EMAC_TX_WORD3_SOP | EMAC_TX_WORD3_EOP |
                EMAC_TX_WORD3_OWNER | EMAC_TX_WORD3_EOQ);

        //Misqueued buffer condition?
        if(temp == (EMAC_TX_WORD3_SOP | EMAC_TX_WORD3_EOP | EMAC_TX_WORD3_EOQ))
        {
            //Check whether the next descriptor pointer is non-zero
            if(CPPI_SWAP(p->word0) != 0)
            {
                //The host corrects the misqueued buffer condition by writing the
                //misqueued packet�s buffer descriptor address to the appropriate
                //TX DMA head descriptor pointer
                EMAC_TXHDP_R(EMAC_CH0) = CPPI_SWAP(p->word0);
            }
        }

        //Write the TX completion pointer
        EMAC_TXCP_R(EMAC_CH0) = (uint32_t) p;

        //Check whether the TX buffer is available for writing
        if((CPPI_SWAP(txCurBufferDesc->word3) & EMAC_TX_WORD3_OWNER) == 0)
        {
            //Notify the TCP/IP stack that the transmitter is ready to send
            flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
        }
    }

    //Write the DMA end of interrupt vector
    EMAC_MACEOIVECTOR_R = EMAC_MACEOIVECTOR_C0TX;

    //Interrupt service routine epilogue
    osExitIsr(flag);
}


/**
 * @brief Ethernet MAC receive interrupt
 **/

#if defined(__ICCARM__)
__irq __arm
#else
#pragma CODE_STATE(tms570EthRxIrqHandler, 32)
#pragma INTERRUPT(tms570EthRxIrqHandler, IRQ)
#endif

void tms570EthRxIrqHandler(void)
{
    bool_t flag;
    uint32_t status;

    //Interrupt service routine prologue
    osEnterIsr();

    //This flag will be set if a higher priority task must be woken
    flag = FALSE;

    //Read the C0RXSTAT register to determine which channels caused the interrupt
    status = EMAC_CTRL_C0RXSTAT_R;

    //Packet received on channel 0?
    if(status & (1 << EMAC_CH0))
    {
        //Disable RX interrupts
        EMAC_CTRL_CnRXEN_R(EMAC_CORE0) &= ~(1 << EMAC_CH0);

        //Set event flag
        nicDriverInterface->nicEvent = TRUE;
        //Notify the TCP/IP stack of the event
        flag |= osSetEventFromIsr(&netEvent);
    }

    //Write the DMA end of interrupt vector
    EMAC_MACEOIVECTOR_R = EMAC_MACEOIVECTOR_C0RX;

    //Interrupt service routine epilogue
    osExitIsr(flag);
}


/**
 * @brief TMS570 Ethernet MAC event handler
 * @param[in] interface Underlying network interface
 **/

void tms570EthEventHandler(NetInterface *interface)
{
    error_t error;

    //Process all pending packets
    do
    {
        //Read incoming packet
        error = tms570EthReceivePacket(interface);

        //No more data in the receive buffer?
    } while(error != ERROR_BUFFER_EMPTY);

    //Re-enable RX interrupts
    EMAC_CTRL_CnRXEN_R(EMAC_CORE0) |= (1 << EMAC_CH0);
}


/**
 * @brief Send a packet
 * @param[in] interface Underlying network interface
 * @param[in] buffer Multi-part buffer containing the data to send
 * @param[in] offset Offset to the first data byte
 * @param[in] ancillary Additional options passed to the stack along with
 *   the packet
 * @return Error code
 **/

error_t tms570EthSendPacket(NetInterface *interface,
                            const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
{
    size_t length;
    uint32_t temp;

    //Retrieve the length of the packet
    length = netBufferGetLength(buffer) - offset;

    //Check the frame length
    if(length > TMS570_ETH_TX_BUFFER_SIZE)
    {
        //The transmitter can accept another packet
        osSetEvent(&interface->nicTxEvent);
        //Report an error
        return ERROR_INVALID_LENGTH;
    }

    //Make sure the current buffer is available for writing
    if(CPPI_SWAP(txCurBufferDesc->word3) & EMAC_TX_WORD3_OWNER)
    {
        return ERROR_FAILURE;
    }

    //Mark the end of the queue with a NULL pointer
    txCurBufferDesc->word0 = CPPI_SWAP(NULL);

    //Copy user data to the transmit buffer
    netBufferRead((uint8_t *) CPPI_SWAP(txCurBufferDesc->word1), buffer,
                  offset, length);

    //Set the length of the buffer
    txCurBufferDesc->word2 = CPPI_SWAP(length & EMAC_TX_WORD2_BUFFER_LENGTH);

    //Give the ownership of the descriptor to the DMA
    txCurBufferDesc->word3 = CPPI_SWAP(EMAC_TX_WORD3_SOP | EMAC_TX_WORD3_EOP |
                                       EMAC_TX_WORD3_OWNER | (length & EMAC_TX_WORD3_PACKET_LENGTH));

    //Link the current descriptor to the previous descriptor
    txCurBufferDesc->prev->word0 = CPPI_SWAP(txCurBufferDesc);

    //Read the status flags of the previous descriptor
    temp = CPPI_SWAP(txCurBufferDesc->prev->word3) & (EMAC_TX_WORD3_SOP |
            EMAC_TX_WORD3_EOP | EMAC_TX_WORD3_OWNER | EMAC_TX_WORD3_EOQ);

    //Misqueued buffer condition?
    if(temp == (EMAC_TX_WORD3_SOP | EMAC_TX_WORD3_EOP | EMAC_TX_WORD3_EOQ))
    {
        //Clear the misqueued buffer condition
        txCurBufferDesc->prev->word3 = CPPI_SWAP(0);

        //The host corrects the misqueued buffer condition by writing the
        //misqueued packet�s buffer descriptor address to the appropriate
        //TX DMA head descriptor pointer
        EMAC_TXHDP_R(EMAC_CH0) = (uint32_t) txCurBufferDesc;
    }

    //Point to the next descriptor in the list
    txCurBufferDesc = txCurBufferDesc->next;

    //Check whether the next buffer is available for writing
    if((CPPI_SWAP(txCurBufferDesc->word3) & EMAC_TX_WORD3_OWNER) == 0)
    {
        //The transmitter can accept another packet
        osSetEvent(&interface->nicTxEvent);
    }

    //Data successfully written
    return NO_ERROR;
}


/**
 * @brief Receive a packet
 * @param[in] interface Underlying network interface
 * @return Error code
 **/

error_t tms570EthReceivePacket(NetInterface *interface)
{
    static uint32_t buffer[TMS570_ETH_RX_BUFFER_SIZE / 4];
    error_t error;
    size_t n;
    uint32_t temp;

    //Current buffer available for reading?
    if((CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_OWNER) == 0)
    {
        //SOP and EOP flags should be set
        if((CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_SOP) != 0 &&
                (CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_EOP) != 0)
        {
            //Make sure no error occurred
            if((CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_ERROR_MASK) == 0)
            {
                //Retrieve the length of the frame
                n = CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_PACKET_LENGTH;
                //Limit the number of data to read
                n = MIN(n, TMS570_ETH_RX_BUFFER_SIZE);

                //Copy data from the receive buffer
                osMemcpy(buffer, (uint8_t *) CPPI_SWAP(rxCurBufferDesc->word1), n);

                //Valid packet received
                error = NO_ERROR;
            }
            else
            {
                //The received packet contains an error
                error = ERROR_INVALID_PACKET;
            }
        }
        else
        {
            //The packet is not valid
            error = ERROR_INVALID_PACKET;
        }

        //Mark the end of the queue with a NULL pointer
        rxCurBufferDesc->word0 = CPPI_SWAP(NULL);
        //Restore the length of the buffer
        rxCurBufferDesc->word2 = CPPI_SWAP(TMS570_ETH_RX_BUFFER_SIZE);
        //Give the ownership of the descriptor back to the DMA
        rxCurBufferDesc->word3 = CPPI_SWAP(EMAC_RX_WORD3_OWNER);

        //Link the current descriptor to the previous descriptor
        rxCurBufferDesc->prev->word0 = CPPI_SWAP(rxCurBufferDesc);

        //Read the status flags of the previous descriptor
        temp = CPPI_SWAP(rxCurBufferDesc->prev->word3) & (EMAC_RX_WORD3_SOP |
                EMAC_RX_WORD3_EOP | EMAC_RX_WORD3_OWNER | EMAC_RX_WORD3_EOQ);

        //Misqueued buffer condition?
        if(temp == (EMAC_RX_WORD3_SOP | EMAC_RX_WORD3_EOP | EMAC_RX_WORD3_EOQ))
        {
            //The host acts on the misqueued buffer condition by writing the added
            //buffer descriptor address to the appropriate RX DMA head descriptor
            //pointer
            EMAC_RXHDP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc;
        }

        //Write the RX completion pointer
        EMAC_RXCP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc;

        //Point to the next descriptor in the list
        rxCurBufferDesc = rxCurBufferDesc->next;
    }
    else
    {
        //No more data in the receive buffer
        error = ERROR_BUFFER_EMPTY;
    }

    //Check whether a valid packet has been received
    if(!error)
    {
        NetRxAncillary ancillary;

        //Additional options can be passed to the stack along with the packet
        ancillary = NET_DEFAULT_RX_ANCILLARY;

        //Pass the packet to the upper layer
        nicProcessPacket(interface, (uint8_t *) buffer, n, &ancillary);
    }

    //Return status code
    return error;
}


/**
 * @brief Configure MAC address filtering
 * @param[in] interface Underlying network interface
 * @return Error code
 **/

error_t tms570EthUpdateMacAddrFilter(NetInterface *interface)
{
    uint_t i;
    uint_t k;
    uint8_t *p;
    uint32_t hashTable[2];
    MacFilterEntry *entry;

    //Debug message
    TRACE_DEBUG("Updating MAC filter...\r\n");

    //Clear hash table
    hashTable[0] = 0;
    hashTable[1] = 0;

    //The MAC address filter contains the list of MAC addresses to accept
    //when receiving an Ethernet frame
    for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
    {
        //Point to the current entry
        entry = &interface->macAddrFilter[i];

        //Valid entry?
        if(entry->refCount > 0)
        {
            //Point to the MAC address
            p = entry->addr.b;

            //Apply the hash function
            k = (p[0] >> 2) ^ (p[0] << 4);
            k ^= (p[1] >> 4) ^ (p[1] << 2);
            k ^= (p[2] >> 6) ^ p[2];
            k ^= (p[3] >> 2) ^ (p[3] << 4);
            k ^= (p[4] >> 4) ^ (p[4] << 2);
            k ^= (p[5] >> 6) ^ p[5];

            //The hash value is reduced to a 6-bit index
            k &= 0x3F;

            //Update hash table contents
            hashTable[k / 32] |= (1 << (k % 32));
        }
    }

    //Write the hash table
    EMAC_MACHASH1_R = hashTable[0];
    EMAC_MACHASH2_R = hashTable[1];

    //Debug message
    TRACE_DEBUG("  MACHASH1 = %08" PRIX32 "\r\n", EMAC_MACHASH1_R);
    TRACE_DEBUG("  MACHASH2 = %08" PRIX32 "\r\n", EMAC_MACHASH2_R);

    //Successful processing
    return NO_ERROR;
}


/**
 * @brief Adjust MAC configuration parameters for proper operation
 * @param[in] interface Underlying network interface
 * @return Error code
 **/

error_t tms570EthUpdateMacConfig(NetInterface *interface)
{
    uint32_t config;

    //Read MAC control register
    config = EMAC_MACCONTROL_R;

    //100BASE-TX or 10BASE-T operation mode?
    if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
    {
        config |= EMAC_MACCONTROL_RMIISPEED;
    }
    else
    {
        config &= ~EMAC_MACCONTROL_RMIISPEED;
    }

    //Half-duplex or full-duplex mode?
    if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
    {
        config |= EMAC_MACCONTROL_FULLDUPLEX;
    }
    else
    {
        config &= ~EMAC_MACCONTROL_FULLDUPLEX;
    }

    //Update MAC control register
    EMAC_MACCONTROL_R = config;

    //Successful processing
    return NO_ERROR;
}


/**
 * @brief Write PHY register
 * @param[in] opcode Access type (2 bits)
 * @param[in] phyAddr PHY address (5 bits)
 * @param[in] regAddr Register address (5 bits)
 * @param[in] data Register value
 **/

void tms570EthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
                          uint8_t regAddr, uint16_t data)
{
    uint32_t temp;

    //Valid opcode?
    if(opcode == SMI_OPCODE_WRITE)
    {
        //Set up a write operation
        temp = MDIO_USERACCESS0_GO | MDIO_USERACCESS0_WRITE;
        //PHY address
        temp |= (phyAddr << MDIO_USERACCESS0_PHYADR_SHIFT) & MDIO_USERACCESS0_PHYADR;
        //Register address
        temp |= (regAddr << MDIO_USERACCESS0_REGADR_SHIFT) & MDIO_USERACCESS0_REGADR;
        //Register value
        temp |= data & MDIO_USERACCESS0_DATA;

        //Start a write operation
        MDIO_USERACCESS0_R = temp;
        //Wait for the write to complete
        while((MDIO_USERACCESS0_R & MDIO_USERACCESS0_GO) != 0)
        {
        }
    }
    else
    {
        //The MAC peripheral only supports standard Clause 22 opcodes
    }
}


/**
 * @brief Read PHY register
 * @param[in] opcode Access type (2 bits)
 * @param[in] phyAddr PHY address (5 bits)
 * @param[in] regAddr Register address (5 bits)
 * @return Register value
 **/

uint16_t tms570EthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
                             uint8_t regAddr)
{
    uint16_t data;
    uint32_t temp;

    //Valid opcode?
    if(opcode == SMI_OPCODE_READ)
    {
        //Set up a read operation
        temp = MDIO_USERACCESS0_GO | MDIO_USERACCESS0_READ;
        //PHY address
        temp |= (phyAddr << MDIO_USERACCESS0_PHYADR_SHIFT) & MDIO_USERACCESS0_PHYADR;
        //Register address
        temp |= (regAddr << MDIO_USERACCESS0_REGADR_SHIFT) & MDIO_USERACCESS0_REGADR;

        //Start a read operation
        MDIO_USERACCESS0_R = temp;
        //Wait for the read to complete
        while((MDIO_USERACCESS0_R & MDIO_USERACCESS0_GO) != 0)
        {
        }

        //Get register value
        data = MDIO_USERACCESS0_R & MDIO_USERACCESS0_DATA;
    }
    else
    {
        //The MAC peripheral only supports standard Clause 22 opcodes
        data = 0;
    }

    //Return the value of the PHY register
    return data;
}
tms570_eth_driver.h1588.emac.cemac.h

I need assistance converting our Ethernet driver for the TMS570LS1227 from the current implementation in tms570_eth_driver.c and tms570_eth_driver.h to the new APIs provided by HalCoGen in CCS.

Details:

  • Current Files: tms570_eth_driver.c, tms570_eth_driver.h
  • Target Platform: TMS570LS1227
  • Current Driver: Used with CycloneTCP

Assistance Required:

  1. API Mapping: Help with mapping existing functions to HalCoGen APIs, including initialization, interrupt handling, and packet operations.
  2. Example Code: Any examples or guidelines for using the new APIs effectively.
  3. Documentation: Relevant references or documentation.

Thank you for your support.