Помогите осилить эзернет на LPC1788
За основу взят пример с FreeRTOS+LwIP для LPC1768 вместе с драйвером эзернет (судя по даташиту модули emac идентичны за исключением поддерки MII, но у меня всё равно используется RMII).
Проблема следующая: инициализация MAC и PHY проходит успешно, линк поднимается на 100мбит полный дуплекс, зелёный диод мыргает при получении широковещательного трафика, на выводах PHY RXD[0:1] присутствуют данные при приёме. Но не генерируется прерывание от EMAC ни на приём ни на передачу.
Инициализация EMAC:
CODE
Status EMAC_Init(EMAC_CFG_Type *EMAC_ConfigStruct)
{
/* 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 );
/* 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 = CLKPWR_GetCLK(CLKPWR_CLKTYPE_CPU) / 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;
return SUCCESS;
}
Инициализация дескрипторов DMA
CODE
/** 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];
#define EMAC_ETH_MAX_FLEN 1536
typedef uint32_t xEMACRxBuffer_t[ EMAC_NUM_RX_FRAG ][ EMAC_ETH_MAX_FLEN >> 2 ];
typedef uint32_t xEMACTxBuffer_t[ EMAC_NUM_TX_FRAG ][ EMAC_ETH_MAX_FLEN >> 2 ];
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[i].Packet = (uint32_t)&(*rx_buf)[i];
Rx_Desc[i].Ctrl = EMAC_RCTRL_INT | (EMAC_ETH_MAX_FLEN - 1);
Rx_Stat[i].Info = 0xFFFFFFFF;
Rx_Stat[i].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;
}
static void tx_descr_init (void) {
/* Initialize Transmit Descriptor and Status array. */
uint32_t i;
extern void *pvApplicationGetEMACTxBufferAddress( void );
xEMACTxBuffer_t *tx_buf;
tx_buf = ( xEMACTxBuffer_t * ) pvApplicationGetEMACTxBufferAddress();
for (i = 0; i < EMAC_NUM_TX_FRAG; i++) {
Tx_Desc[i].Packet = (uint32_t)&(*tx_buf)[i];
Tx_Desc[i].Ctrl = 0xFFFFFFFF;
Tx_Stat[i].Info = 0xFFFFFFFF;
}
/* Set EMAC Transmit Descriptor Registers. */
LPC_EMAC->TxDescriptor = (uint32_t)&Tx_Desc[0];
LPC_EMAC->TxStatus = (uint32_t)&Tx_Stat[0];
LPC_EMAC->TxDescriptorNumber = EMAC_NUM_TX_FRAG - 1;
/* Tx Descriptors Point to 0 */
LPC_EMAC->TxProduceIndex = 0;
}
void *pvApplicationGetEMACTxBufferAddress(void)
{
static volatile xEMACTxBuffer_t txb __attribute__ ((aligned (4)));
return (void *)txb;
}
void *pvApplicationGetEMACRxBufferAddress(void)
{
static volatile xEMACRxBuffer_t rxb __attribute__ ((aligned (4)));
return (void *)rxb;
}
Инициализация дескрипторов тоже вроде как проходит успешно, отладчиком вижу правильные адреса буферов приёма/передачи в регистрах EMAC. Прерывания RxDoneInt и TxDoneInt включены. Прерывание от EMAC в NVIC разрешено. Всё выглядит верно настроенным, но прерываний от EMAC нет вообще. Тот же самый код работает на LPC1768 с такой же PHY (KS8721B), прерывание бегают, LwIP работает. А тут вообще глухо, будто прерывания запрещены или он просто не принимает/не передаёт ничего, но на выводах RXD[0:1] чётко видны импульсы при приёме ARP пакетов. Пробовал подбирать чатсоту RMII от 2.5 до 15 МГц. Пробовал менять частоту проца от 80 до 120МГц. Никаких результатов.
Готовый порт
http://www.lpcware.com/content/project/lig...etworking-stack тоже запустить не удалось, но по-правде говоря не сильно углублялся в него - слишком наворочено. Внимательно посмотрел как там инициализация EMAC сделана, сравнил со своей - вроде всё так же. Кто сталкивался с эзернетом на этом проце подскажите что-нибудь вроде рабочиего кода инициалицации EMAC
Сообщение отредактировал IgorKossak - Jul 17 2012, 19:53
Причина редактирования: [codebox] для длинного кода!!!