📄 emac_local_loopback_example.c
字号:
/* ============================================================================
* Copyright (c) Texas Instruments Inc 2002, 2003, 2004, 2005, 2006
*
* Use of this software is controlled by the terms and conditions found in the
* license agreement under which this software has been supplied.
* ===========================================================================
*/
/* ============================================================================
* @file Emac_example.c
*
* PATH: \$(CSLPATH)\\example\\emac\\src
*
* @brief Example for EMAC CSL
*
* ============================================================================
* @n Target Platform: TCI6486 on Quick Turn
* ============================================================================
* @n <b> Example Description </b>
* @n This example, is a simple loop back configured for core 0. If emac is configured
* no need to configure ECTL, EMAC src configures it. Here the EMAC src configures
* interrupts for single core i.e core 0, one Rx channel and one Tx channel.
* This example tested for core 0 for 100 packets.
*
* This example can be configured to test it on core 1 and core2 as well.
* Please do the below changes
* if user wants to dedicate receive channel 1 for core 1, he has to select
* core 0 channels as dummy and do not send any packet on this channel
* i.e configuration would be
* ecfg.ChannelInfo[0].TxChannels = 1;
* ecfg.ChannelInfo[0].RxChannels = 1;
* ecfg.ChannelInfo[1].TxChannels = 1;
* ecfg.ChannelInfo[1].RxChannels = 1;
* ecfg.ChannelInfo[2].TxChannels = 0;
* ecfg.ChannelInfo[2].RxChannels = 0;
*
* otherwise it selects receive channel 0 as default.
*
* if user wants to dedicate receive channel 2 for core 2, he has to select
* core 0 and core 1channels as dummy and do not send any packet on these channels
* i.e configuration would be
* ecfg.ChannelInfo[0].TxChannels = 1;
* ecfg.ChannelInfo[0].RxChannels = 1;
* ecfg.ChannelInfo[1].TxChannels = 1;
* ecfg.ChannelInfo[1].RxChannels = 1;
* ecfg.ChannelInfo[2].TxChannels = 1;
* ecfg.ChannelInfo[2].RxChannels = 1;
*
* otherwise it selects receive channel 0 as default.
*
* Note: Since it(C6486) is a six core divice, there is a separeate MAC address
* for each core. While doing configuration for other cores pass the specific
* core MAC address through MacAddr[6][6] 2-D array, a member of EMAC_Config structure.
*
* Choose TX packet channel accordingly while preparing the packet to send
* i.e pPkt->PktChannel = 0 (for core 0), 1 (for core 1), 2 (for core 2) in this example;
*
* Change the second argument(coreNum 0, 1 and 2 respectively for core 0, 1 and 2)in below functions
* EMAC_RxServiceCheck(hEMAC, coreNum)
* EMAC_TxServiceCheck(hEMAC, coreNum)
* EMAC_timerTick(hEMAC, coreNum)
*
* Please also ensure that proper Linker command file is used
* i.e use specific core global memory map for L2 (L2_GLOBAL in cmd file should be changed accordingly)
*
* LOCAL_LOOPBACK performs loopback in the MAC, however since this example
* also does not check for a LINK on the physical PHY as it does not configire MDIO.
*
* Note: This same example works for instance "one" also but with some changes listed
* 1. Use corresponding rx and tx interrupt event IDs to hook up the interrupts
* 2. While calling EMAC_Open, pass the instance number as 1.
* 3. Enable PSC for EMAC instance 1
* 4. And to work on mutli core the above said procedure can be followed
*
*
* =============================================================================
*
* <b> Procedure to run the example </b>
* @verbatim
* 1. Configure the CCS setup to work with.
* 2. Launch CCS window.
* 3. Open project Emac_local_loopback_example.pjt
* 4. Build the project and load the .out file of the project.
* 5. Run the example.
* @endverbatim
*
*/
#include <stdio.h>
#include <csl_emac.h>
#include <cslr_dev.h>
#define LOCAL_LOOPBACK 1 /* Loopback internal to the EMAC */
#define PHY_LOOPBACK 0 /* Loopback at the PHY device */
#define QUICKTURN 1 /* Quickturn test */
/*
* We'll use INT5 for the EMAC Rx and 6 for Tx- this is an arbitrary choice
*/
#define EMAC_INT_VAL 9
#define EMAC_INT_FLAG (3<<EMAC_INT_VAL)
/*
* Raw Data Buffers
*
* This example uses internal memory, so we could just use 1518 as our
* buffer size. However, if the buffers were in cacheable external
* memory, we'd have to make sure each was cache aligned, and
* thus use a size of at least 1536 because a buffer must fill an
* the entire cache line.
*/
#define PKT_MAX 32
#pragma DATA_SECTION(packet_header, ".src_buff");
EMAC_Pkt packet_header[PKT_MAX];
#pragma DATA_SECTION(packet_buffer, ".src_buff");
Uint8 packet_buffer[PKT_MAX][1536];
#pragma DATA_SECTION(packet_sourcedata, ".src_buff");
Uint8 packet_sourcedata[1536];
/*
* Packet Queue
*
* This simple queue object is just for our example packet
* queue. It is not requried for using EMAC/MDIO
*
*/
typedef struct app_pktq {
Uint32 Count; /**< Number of packets in queue */
EMAC_Pkt *pHead; /**< Pointer to first packet */
EMAC_Pkt *pTail; /**< Pointer to last packet */
} APP_PKTQ;
/*
* Queue Helper Functions
*/
static EMAC_Pkt *App_pqPop( APP_PKTQ *pq );
static void App_pqPush( APP_PKTQ *pq, EMAC_Pkt *pPktHdr );
/*
* Declare our packet queues
*/
APP_PKTQ FreeQueue; /* Free packets for RX or TX */
APP_PKTQ RxQueue; /* Received packets */
/*
* Declare some local status variables
*/
Handle hEMAC = 0; /* Handle to our EMAC instance */
volatile Uint32 LinkStatus = 0; /* Our current link status */
volatile Uint32 LocalTicks = 0; /* Current time in 100ms ticks */
extern cregister volatile unsigned int IER;
#define OUREMAC_enter() IER &= ~EMAC_INT_FLAG
#define OUREMAC_exit() IER |= EMAC_INT_FLAG
/*
* Declare some local functions
*/
static EMAC_Pkt *GetPacket(Handle hApplication);
static void FreePacket(Handle hApplication, EMAC_Pkt *pPKT);
static EMAC_Pkt *RxPacket( Handle hApplication, EMAC_Pkt *pPKT);
static void StatusUpdate(Handle hApplication);
static void StatisticsUpdate(Handle hApplication);
static int verify_packet( EMAC_Pkt *pPkt, Uint32 size );
static EMAC_Status status;
static char *LinkStr[] ={
"No Link",
"10Mb/s Half Duplex",
"10Mb/s Full Duplex",
"100Mb/s Half Duplex",
"100Mb/s Full Duplex",
"1000Mb/s Full Duplex"
};
/*
* Declare some external functions
*/
extern void DoTimerInitialization(void);
extern void DoInterruptsInitialization(void);
extern void DoInterruptEnd(void);
/*
* =============================================================================
* @func Main
*
* @desc
* Main Example Entry Point.
*
* @arg
* None
*
* @expected result
* If the example passes, it displays the message "Example Passed"
* If the example fails, it displays the messae "Example Failed"
*
* @eg
* exampleMain(); // Read description.
* =============================================================================
*/
void main()
{
EMAC_Config ecfg;
Uint32 i, size, j;
Uint32 TxCount=0;
Uint32 RxCount=0;
Uint32 count = (1514-60)+1;
EMAC_Pkt *pPkt;
/* test less packets since quickturn is slow */
if(QUICKTURN){
count = (160-60); // 100 packets
}
/*
* Basic Initialization
*/
printf("EMAC example\n");
/* Init packet data array */
for( i=0; i<1514; i++ ) {
packet_sourcedata[i] = i;
}
/* Initialize our buffer pool */
memset( &FreeQueue, 0, sizeof(APP_PKTQ) );
memset( &RxQueue, 0, sizeof(APP_PKTQ) );
for( i=0; i<PKT_MAX; i++ ) {
/*
* Init the buffer headers. Note that the buffer pointer
* and buffer length are fixed and to not change
*/
memset( &packet_header[i], 0, sizeof(EMAC_Pkt) );
packet_header[i].pDataBuffer = packet_buffer[i];
packet_header[i].BufferLen = 1518;
App_pqPush( &FreeQueue, &packet_header[i] );
}
/*
* Inialize Configuration and Open EMAC
*/
/* Not using the MDIO configuration */
ecfg.UseMdio = 0;
/* Setup the EMAC configuration */
#if LOCAL_LOOPBACK
ecfg.ModeFlags = EMAC_CONFIG_MODEFLG_MACLOOPBACK | EMAC_CONFIG_MODEFLG_FULLDUPLEX;
#else
ecfg.ModeFlags = 0;
#endif
#if PHY_LOOPBACK
ecfg.MdioModeFlags = MDIO_MODEFLG_FD1000 | MDIO_MODEFLG_LOOPBACK;
#else
ecfg.MdioModeFlags = MDIO_MODEFLG_FD1000;
#endif
ecfg.ChannelInfo[0].TxChannels = 1;
ecfg.ChannelInfo[0].RxChannels = 1;
for (i = 1; i < 6; i++) {
ecfg.ChannelInfo[i].TxChannels = 0;
ecfg.ChannelInfo[i].RxChannels = 0;
}
ecfg.RxMaxPktPool = 8;
ecfg.pfcbGetPacket = &GetPacket;
ecfg.pfcbFreePacket = &FreePacket;
ecfg.pfcbRxPacket = &RxPacket;
ecfg.pfcbStatus = &StatusUpdate;
ecfg.pfcbStatistics = &StatisticsUpdate;
/*
* For this example we'll set our EMAC address to be 00:01:02:03:04:05
* If this were a real driver, we'd have to read the EMAC
* address from where it is stored in hardware (board dependent)
*/
for (j=0; j<6; j++){
for (i=0; i<6; i++){
if (j==0)
ecfg.MacAddr[j][i] = i;
else
ecfg.MacAddr[j][i] = 0;
}
}
/* Enable PSC for EMAC instance 0*/
*(volatile unsigned int *)0x02ae0a1c = 0x03;
/* Open EMAC instance 0 */
printf("Calling EMAC_open()\n");
i = EMAC_open( 1, (Handle)0x12345678, 0, &ecfg, &hEMAC );
if(i)
{
printf("Returned error %08x\n",i);
goto exit;
}
/* Set the receive filter */
/* Use our re-entrancy gate to call EMAC functions */
printf("Calling EMAC_setReceiveFilter()\n");
OUREMAC_enter();
i = EMAC_setReceiveFilter( hEMAC, EMAC_RXFILTER_DIRECT );
OUREMAC_exit();
if(i)
{
printf("Returned error %08x\n",i);
goto close_emac;
}
/* Do timer intialization */
DoTimerInitialization();
/* Do interrupt setup */
DoInterruptsInitialization();
/*
* Wait for the device to link
*
* The device can not send or receive packets until its
* linked.
*
*/
printf("Waiting for link...\n");
LocalTicks = 0;
if(ecfg.UseMdio){
while( !LinkStatus && LocalTicks < 100 );
}
/* Need to print this here, as it's not possible from the callback function */
EMAC_getStatus( hEMAC, &status, 0);
LinkStatus = status.MdioLinkStatus;
if( LinkStatus <= 5 )
printf("Link Status : %s on PHY number %d\n",
LinkStr[LinkStatus],status.PhyDev);
printf("Packets Held : %d-RX %d-TX\n",
status.RxPktHeld, status.TxPktHeld);
if( status.FatalError )
printf("Fatal Error : %d\n",status.FatalError);
if( !LinkStatus )
printf("\nWARNING: No device LINK.\n");
/* Start the example */
printf("\nStarting packet transfer...\n");
LocalTicks = 0;
while( RxCount<count ) {
/* Check for timeout */
if(!QUICKTURN){
if( LocalTicks > 50 ) {
printf("ERROR: Timeout waiting for TX/RX\n");
break;
}
}
/* See if we should send a packet */
if( TxCount<count && TxCount<(RxCount+8) ) {
/*
* Send a packet
*/
/* First get a packet buffer from our private queue */
pPkt = App_pqPop( &FreeQueue );
if( pPkt ) {
/* Fill buffer with a pattern, using "count+60" for size */
size = TxCount + 60;
memcpy( pPkt->pDataBuffer, packet_sourcedata, size);
/* Send the packet */
pPkt->Flags = EMAC_PKT_FLAGS_SOP | EMAC_PKT_FLAGS_EOP;
pPkt->ValidLen = size;
pPkt->DataOffset = 0;
pPkt->PktChannel = 0;
pPkt->PktLength = size;
pPkt->PktFrags = 1;
/*
* IMPORTANT: If our data packet were in EXTERNAL memory,
* we would have to clean it from the CACHE before submitting
* it to the EMAC module!!!
*
* We should probably do the clean operation right here.
*/
/* Use our re-entrancy gate to call EMAC functions */
OUREMAC_enter();
i = EMAC_sendPacket(hEMAC, pPkt);
OUREMAC_exit();
if(i) {
printf("EMAC_sendPacket() returned error %08x\n",i);
break;
}
/* Bump the TX count */
TxCount++;
}
}
/*
* See if we received a packet
*/
if( pPkt = App_pqPop( &RxQueue ) ) {
/* Validate this packet */
if( !verify_packet( pPkt, RxCount + 60 ) ) {
printf("ERROR: Verify failure on packet %d\n",RxCount);
break;
}
/* Free the packet */
App_pqPush( &FreeQueue, pPkt );
/* Bump the RX count */
RxCount++;
}
}
printf("Sent %d of %d packets, received %d packets\n",
TxCount, count, RxCount);
/*
* Close EMAC
*/
close_emac:
/* Since we're done, we leave the interrupt disabled */
DoInterruptEnd();
printf("Calling EMAC_close()\n");
i = EMAC_close( hEMAC );
hEMAC = 0;
if(i) {
printf("Returned error %08x\n",i);
goto exit;
}
exit:
if( TxCount == count && RxCount == count )
printf("\nExample Passed\n");
else {
printf("\nExample Failed\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -