lpcware

LPC1788 Ethernet DMA interrupt problem

Discussion created by lpcware Employee on Jun 15, 2016
Latest reply on Jun 15, 2016 by lpcware
Content originally posted in LPCWare by FlySnake on Mon Jul 16 15:00:21 MST 2012
Hi everyone!
I'm trying to launch FreeRTOS + LwIP on LPC1788 + KS8721B
This work is seems to be done http://www.lpcware.com/content/project/lightweight-ip-lwip-networking-stack but this port is too weird and complex.
I've started with http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_IO/Demo_Applications/LPCXpresso_LPC1769/NXP_LPC1769_Demo_Description.shtml FreeRTOS+IO featured demo #2
EMAC modules in LPC1768 and LPC1788 looks the same except that LPC1788 supports MII while LPC1768 only RMII.
EMAC initialization
Status EMAC_Init(EMAC_CFG_Type *EMAC_ConfigStruct)
{
/* Enable Ethernet Pins */
/*
* Enable P1 Ethernet Pins:
* P1.0 - ENET_TXD0
* P1.1 - ENET_TXD1
* P1.4 - ENET_TX_EN
* P1.8 - ENET_CRS
* P1.9 - ENET_RXD0
* P1.10 - ENET_RXD1
* P1.14 - ENET_RX_ER
* P1.15 - ENET_REF_CLK
* P1.16 - ENET_MDC
* P1.17 - ENET_MDIO
*/
PINSEL_ConfigPin(1, 0, 1);
PINSEL_ConfigPin(1, 1, 1);
PINSEL_ConfigPin(1, 4, 1);
PINSEL_ConfigPin(1, 9, 1);
PINSEL_ConfigPin(1, 10, 1);
PINSEL_ConfigPin(1, 8, 1);
PINSEL_ConfigPin(1, 14, 1);
PINSEL_ConfigPin(1, 17, 1);
PINSEL_ConfigPin(1, 16, 1);
PINSEL_ConfigPin(1, 15, 1);

/* Initialize the EMAC Ethernet controller. */
int32_t regv,tout, tmp;

/* Set up clock and power for Ethernet module */
CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, ENABLE);

/* Reset all EMAC internal modules */
LPC_EMAC->MAC1    = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX | EMAC_MAC1_RES_RX |
EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES | EMAC_MAC1_SOFT_RES;

LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES | EMAC_CR_PASS_RUNT_FRM;

/* A short delay after reset. */
vTaskDelay( 2 );

/* Enable Reduced MII interface. */
LPC_EMAC->Command = EMAC_CR_RMII | EMAC_CR_PASS_RUNT_FRM;

/* Reset Reduced MII Logic. */
LPC_EMAC->SUPP = EMAC_SUPP_RES_RMII;

/* Initialize MAC control registers. */
LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL;
LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN;
LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN;

/*
* Find the clock that close to desired target clock
*/
tmp = SystemCoreClock / EMAC_MCFG_MII_MAXCLK;
for (tout = 0; tout < sizeof (EMAC_clkdiv); tout++){
if (EMAC_clkdiv[tout] >= tmp) break;
}
tout++;

// Write to MAC configuration register and reset
LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(tout) | EMAC_MCFG_RES_MII;

// release reset
LPC_EMAC->MCFG &= ~(EMAC_MCFG_RES_MII);
LPC_EMAC->CLRT = EMAC_CLRT_DEF;
LPC_EMAC->IPGR = EMAC_IPGR_P2_DEF;

/* Enable Reduced MII interface. */
LPC_EMAC->Command = EMAC_CR_RMII | EMAC_CR_PASS_RUNT_FRM;

/* A short delay after reset. */
vTaskDelay( 2 );

//LPC_EMAC->SUPP = 0;

/* Put the DP83848C in reset mode */
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_RESET);

/* Wait for hardware reset to end. */
for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
regv = read_PHY (EMAC_PHY_REG_BMCR);
if (!(regv & (EMAC_PHY_BMCR_RESET | EMAC_PHY_BMCR_POWERDOWN))) {
/* Reset complete, device not Power Down. */
break;
}
if (tout == 0){
// Time out, return ERROR
return (ERROR);
}
vTaskDelay( 2 );
}

// Set PHY mode
if (EMAC_SetPHYMode(EMAC_ConfigStruct->Mode) < 0){
return (ERROR);
}

// Set EMAC address
setEmacAddr(EMAC_ConfigStruct->pbEMAC_Addr);

/* Initialize Tx and Rx DMA Descriptors */
rx_descr_init ();
tx_descr_init ();

// Set Receive Filter register: enable broadcast and multicast
LPC_EMAC->RxFilterCtrl = EMAC_RFC_MCAST_EN | EMAC_RFC_BCAST_EN | EMAC_RFC_PERFECT_EN;

/* Enable Rx Done and Tx Done interrupt for EMAC */
LPC_EMAC->IntEnable = EMAC_INT_RX_DONE | EMAC_INT_TX_DONE;

/* Reset all interrupts */
LPC_EMAC->IntClear  = 0xFFFF;

/* Enable receive and transmit mode of MAC Ethernet core */
LPC_EMAC->Command  |= (EMAC_CR_RX_EN | EMAC_CR_TX_EN);
LPC_EMAC->MAC1     |= EMAC_MAC1_REC_EN;

        NVIC_SetPriority( ENET_IRQn, configEMAC_INTERRUPT_PRIORITY );
        NVIC_EnableIRQ( ENET_IRQn );

return SUCCESS;
}

Set PHY mode
int32_t EMAC_SetPHYMode(uint32_t ulPHYMode)
{
int32_t id1, id2, tout, regv;

/* Check if this is a DP83848C PHY. */
id1 = read_PHY (EMAC_PHY_REG_IDR1);
id2 = read_PHY (EMAC_PHY_REG_IDR2);

if (((id1 << 16) | (id2 & 0xFFF0)) != 0 /*0x0007C0F0UL*/ ) { // stupid workaround for KS8721
switch(ulPHYMode){
case EMAC_MODE_AUTO:
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG);
/* Wait to complete Auto_Negotiation */
for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
regv = read_PHY (EMAC_PHY_REG_BMSR);
if (regv & EMAC_PHY_BMSR_AUTO_DONE) {
/* Auto-negotiation Complete. */
break;
}
if (tout == 0){
// Time out, return error
return (-1);
}

vTaskDelay( 1000 );
}
break;
case EMAC_MODE_10M_FULL:
/* Connect at 10MBit full-duplex */
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_10M);
break;
case EMAC_MODE_10M_HALF:
/* Connect at 10MBit half-duplex */
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_10M);
break;
case EMAC_MODE_100M_FULL:
/* Connect at 100MBit full-duplex */
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_100M);
break;
case EMAC_MODE_100M_HALF:
/* Connect at 100MBit half-duplex */
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_100M);
break;
default:
// un-supported
return (-1);
}
}
// It's not correct module ID
else {
return (-1);
}

// Update EMAC configuration with current PHY status
if (EMAC_UpdatePHYStatus() < 0){
return (-1);
}

// Complete
return (0);
}

Until now all is OK. PHY initializes as expected (btw, this code works with LPC1768 + KS8721B in another project)

Initialize RX descriptor

/** Rx Descriptor data array */
static volatile RX_Desc Rx_Desc[EMAC_NUM_RX_FRAG];

/** Rx Status data array - Must be 8-Byte aligned */
static volatile __attribute__ ((aligned (8))) RX_Stat Rx_Stat[EMAC_NUM_RX_FRAG];

/** Tx Descriptor data array */
static volatile TX_Desc Tx_Desc[EMAC_NUM_TX_FRAG];
/** Tx Status data array */
static volatile TX_Stat Tx_Stat[EMAC_NUM_TX_FRAG];

static void rx_descr_init (void)
{
/* Initialize Receive Descriptor and Status array. */
uint32_t i;
extern void *pvApplicationGetEMACRxBufferAddress( void );
xEMACRxBuffer_t *rx_buf;

rx_buf = ( xEMACRxBuffer_t * ) pvApplicationGetEMACRxBufferAddress();
for (i = 0; i < EMAC_NUM_RX_FRAG; i++) {
Rx_Desc.Packet  = (uint32_t)&(*rx_buf);
Rx_Desc.Ctrl    = EMAC_RCTRL_INT | (EMAC_ETH_MAX_FLEN - 1);
Rx_Stat.Info    = 0xFFFFFFFF;
Rx_Stat.HashCRC = 0xFFFFFFFF;
}

/* Set EMAC Receive Descriptor Registers. */
LPC_EMAC->RxDescriptor       = (uint32_t)&Rx_Desc[0];
LPC_EMAC->RxStatus           = (uint32_t)&Rx_Stat[0];
LPC_EMAC->RxDescriptorNumber = EMAC_NUM_RX_FRAG - 1;

/* Rx Descriptors Point to 0 */
LPC_EMAC->RxConsumeIndex  = 0;
}

void *pvApplicationGetEMACRxBufferAddress(void)
{

static volatile xEMACRxBuffer_t rxb __attribute__ ((aligned (4)));
return (void *)rxb;
}

typedef uint32_t xEMACRxBuffer_t[ EMAC_NUM_RX_FRAG ][ EMAC_ETH_MAX_FLEN >> 2 ];


The green led in RJ45 female connector blinks whenever PHY receives some broadcast traffic, but it does not assert interrupt for either receive or transmit done. I don't know what can be wrong :(

Outcomes