|
LPC1788 Ethernet DMA драйвер - прерывания, Не работают прерывания от EMAC |
|
|
|
Jul 17 2012, 10:44
|
Местный
  
Группа: Свой
Сообщений: 311
Регистрация: 12-01-11
Из: Калининград (Koenigsberg)
Пользователь №: 62 182

|
Помогите осилить эзернет на 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] для длинного кода!!!
--------------------
typedef enum { no, yes, maybe } bool; | блог тут
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 15)
|
Jul 17 2012, 13:08
|
Местный
  
Группа: Свой
Сообщений: 311
Регистрация: 12-01-11
Из: Калининград (Koenigsberg)
Пользователь №: 62 182

|
Цитата(DmitryM @ Jul 17 2012, 15:43)  А разве частота RMII не задается PHY равной 50МГц? Или речь идет о MDC, MDIO? Да, о MDC, попутал чуток  Цитата 5:2 CLOCK SELECT This field is used by the clock divide logic in creating the MII Management Clock (MDC) which IEEE 802.3u defines to be no faster than 2.5 MHz. Some PHYs support clock rates up to 12.5 MHz, however. The AHB bus clock (HCLK) is divided by the specified amount. Refer to Table 160 below for the definition of values for this field. Насчёт отсутствия прерываний я соврал. После сброса и инициализации EMAC+PHY всего одно прерывание происходит если что-то было принято. Т.е. ставлю брейкпоинт на ENET_IRQHandler, запускаю программу - тишина. С компьютера пробую пинговать плату (на сетевом уровне широковещательный ARP запроспроходит) - срабатывает прерывание, в регистре IntStatus подняты флаги RxErrorInt и RxFinishedInt. Обработчик прерывания их не обрабатывает, а просто сбрасывает. Больше после этого никаких прерываний не происходит. Причём проверил на LPC1768 там тоже постоянно встаёт флагRxErrorInt, но всем пофиг и с ним хорошо работает. Значит приём всё же работает, а косяк по-видимому с дескрипторами DMA. Попробовал запустить пример EasyWeb из NXP-шной библиотеки. Заработало. Похоже есть хоть какая-то зацепка.
--------------------
typedef enum { no, yes, maybe } bool; | блог тут
|
|
|
|
|
Jul 17 2012, 15:53
|
Местный
  
Группа: Свой
Сообщений: 311
Регистрация: 12-01-11
Из: Калининград (Koenigsberg)
Пользователь №: 62 182

|
С дескрипторами вот что происходит: RxProduceIndex достигает 3 (максимум 4 фрагмента) и на этом останавливается, RxConsumeIndex стоит на 0. Буфер, определённый в дескрипторе приёма остаётся пустым TxProduceIndex останавливается на 1, TxConsumeIndex в 0. В буфере передачи появляется FFFF0012 13101511 08060001 08000604 00010012 13101511 C0A801C8 00000000 0000C0A8 01C80000 00000000 и дальше нули, похоже на один фрейм, 001213101511 - MAC адрес, с остальной структурой не разбирался. Получается что EMAC принимает фрагменты, инкрементирует индекс в дескрипторе, но не пишет ничего в буфер и потому не поднимает флаг прерывания.
--------------------
typedef enum { no, yes, maybe } bool; | блог тут
|
|
|
|
|
Jul 18 2012, 08:39
|
Местный
  
Группа: Свой
Сообщений: 311
Регистрация: 12-01-11
Из: Калининград (Koenigsberg)
Пользователь №: 62 182

|
Поллинг не поможет - проблема с самими дескрипторами, похоже, а не с прерываниями. В статусные дескрипторы ничего не записывается при приёме/передаче. Они как инициализируются в 0 так и остаются, НО RxProduceIndex инкрементируется будто всё ОК. Это не соответствует инфе из даташита: Цитата After receiving a fragment, the Rx DMA manager writes status information back to the StatusInfo and StatusHashCRC words of the status. The Ethernet block writes the size in bytes of a descriptor’s fragment buffer in the RxSize field of the Status word. The value of the RxProduceIndex is only updated after the fragment data and the fragment status information has been committed to memory, which is checked by an internal tag protocol in the memory interface. Т.е. RxProduceIndex инкрементируется только после успешной записи и проверки данных записанных в буфер и статусный дескриптор. Но у меня ничего не пишется ни в буфер ни в статус, а RxProduceIndex инкрементиуется пока не достигнет количество фрагментов-1 и выставляет прерывание RxFinishedInt. На этом всё останавливается.
--------------------
typedef enum { no, yes, maybe } bool; | блог тут
|
|
|
|
|
Jul 18 2012, 18:44
|
Местный
  
Группа: Свой
Сообщений: 311
Регистрация: 12-01-11
Из: Калининград (Koenigsberg)
Пользователь №: 62 182

|
Спасибо пребольшое! Кстати, нашёл где написано про это http://www.lpcware.com/content/project/lig...ffer-management курсивом Цитата Note: For the LPC17xx, the descriptors and buffers must be located only in peripheral RAM or external memory. For the LPC18xx/43xx, descriptors and buffers can be located anywhere. Только у LPC1768 можно
Сообщение отредактировал Cosmojam - Jul 18 2012, 20:59
--------------------
typedef enum { no, yes, maybe } bool; | блог тут
|
|
|
|
|
Oct 1 2012, 07:26
|
Участник

Группа: Участник
Сообщений: 63
Регистрация: 25-11-11
Пользователь №: 68 515

|
Цитата(Cosmojam @ Jul 18 2012, 22:44)  Спасибо пребольшое! Кстати, нашёл где написано про это http://www.lpcware.com/content/project/lig...ffer-management курсивом Только у LPC1768 можно Да,столкнулся с такой же петрушкой на 1788...Дело в том,что в примере дескрипторы уже описываются расположенными в AHB RAM.Я думал,что это не важно,сделал по-своему,разместив их в обычной RAM. потом сделал как в этом примере,и заработало,причем как и в прерывании,так и без,просто в опросе.Тут другое непонятно.NXP похоже,так и не устранили глюк-если объявляешь NUM_RX_FRAG=1 или NUM_ТX_FRAG=1.то есть типа,ты отпраил пакет,сделал условно TxProduce++,однако он не увеличивается,а на втором проходе этой же командой (TxProduce++)он сразу увеличивается на 2. Таким образом получается,что надо минимум NUM_RX_FRAG=2 и NUM_ТX_FRAG=2 и что 3 Кбайта памяти просто тратится впустую...
|
|
|
|
|
Oct 3 2012, 05:55
|
Частый гость
 
Группа: Свой
Сообщений: 131
Регистрация: 14-10-08
Из: г. Королев
Пользователь №: 40 940

|
Цитата(romas2010 @ Oct 1 2012, 11:26)  Тут другое непонятно.NXP похоже,так и не устранили глюк-если объявляешь NUM_RX_FRAG=1 или NUM_ТX_FRAG=1.то есть типа,ты отпраил пакет,сделал условно TxProduce++,однако он не увеличивается,а на втором проходе этой же командой (TxProduce++)он сразу увеличивается на 2. Таким образом получается,что надо минимум NUM_RX_FRAG=2 и NUM_ТX_FRAG=2 и что 3 Кбайта памяти просто тратится впустую... Нет, не тратится. Это происходит только первый раз после сброса. Просто после инициализации отошли пару пустых пакетов  В ERRATA этот момент описан
Сообщение отредактировал theBMV - Oct 3 2012, 05:56
|
|
|
|
|
Dec 5 2012, 20:40
|
Группа: Новичок
Сообщений: 1
Регистрация: 4-12-12
Пользователь №: 74 702

|
Немного не из этой темы, но связано с ней. Я новичок в ARM. И у меня проблема с работой ks8721 и LPC1778. Как я понял из этой ветки форума, проблема в размещении дескрипторов в RAM. Вопрос каким образом явно разместить их там.
|
|
|
|
|
Dec 6 2012, 18:04
|
Участник

Группа: Участник
Сообщений: 63
Регистрация: 25-11-11
Пользователь №: 68 515

|
Цитата(Kevlar @ Dec 5 2012, 23:40)  Немного не из этой темы, но связано с ней. Я новичок в ARM. И у меня проблема с работой ks8721 и LPC1778. Как я понял из этой ветки форума, проблема в размещении дескрипторов в RAM. Вопрос каким образом явно разместить их там. Скачиваешь с http://www.nxp.com/products/microcontrolle...rtex_m3/lpc1700 файл ...PDL.zip .Это типа примеры.Изучаешь файлы ...EMAC.c и ...EMAC.h там можно понять,что и как и более того ks8721 там тоже инициализируется
|
|
|
|
|
Dec 6 2012, 18:31
|
Местный
  
Группа: Свой
Сообщений: 311
Регистрация: 12-01-11
Из: Калининград (Koenigsberg)
Пользователь №: 62 182

|
Цитата(Kevlar @ Dec 5 2012, 23:40)  Немного не из этой темы, но связано с ней. Я новичок в ARM. И у меня проблема с работой ks8721 и LPC1778. Как я понял из этой ветки форума, проблема в размещении дескрипторов в RAM. Вопрос каким образом явно разместить их там. Это от компилятора (линкера) зависит. Что за проблема по-точнее? Какой компилятор, IDE?
--------------------
typedef enum { no, yes, maybe } bool; | блог тут
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|