|
EMAC AT91SAM9260, Вопросы, касающиеся Ethernet MAC для AT91SAM9260 |
|
|
|
Oct 28 2010, 13:27
|
Местный
  
Группа: Свой
Сообщений: 264
Регистрация: 17-04-07
Из: Москва
Пользователь №: 27 102

|
Доброго всем здравия!!! Начал разбираться с EMAC для AT91SAM9260. Имеется документация на сам контроллер и тестовый пример для IAR под названием basic-emac-uip-webserver-project-at91sam9260-ek. В этой теме планируется задавать вопросы, которые касаются проблемы запуска Ethernet на вышеупомянутом контроллере и просто непонятные вещи. Первый вопрос заключается в следующем. В файле emac.h имеются некоторые указатели на функции: Код /// Callback used by send function typedef void (*EMAC_TxCallback)(unsigned int status); // EMAC_TxCallback - указатель на функцию, возвращающую void и принимающую unsigned int typedef void (*EMAC_RxCallback)(unsigned int status); // EMAC_RxCallback - указатель на функцию, возвращающую void и принимающую unsigned int typedef void (*EMAC_WakeupCallback)(void); // EMAC_WakeupCallback - указатель на функцию, возвращающую void и принимающую void Далее они используются, например в функции EMAC_Handler, которая управляет прерываниями, расположенной в emac.c: Код volatile EmacTxTDescriptor *pTxTd; volatile EMAC_TxCallback *pTxCb; Код if (rxTd.rxCb) { rxTd.rxCb(rxStatusFlag); } Код if (*pTxCb) { (*pTxCb)(txStatusFlag); } Я так понял это так называемые обратные функции, но что они делают нигде не определено (по-крайней мере я не нашел). Вопрос собственно для чего они нужны? Еще один вопрос, что выполняет следующий кусок кода в той же функции EMAC_Handler и для чего он нужен? Можно ли обойтись без всего этого? Код // Check the buffers while (CIRC_CNT(txTd.head, txTd.tail, TX_BUFFERS)) { pTxTd = txTd.td + txTd.tail; pTxCb = txTd.txCb + txTd.tail;
// Exit if buffer has not been sent yet if ((pTxTd->status & EMAC_TX_USED_BIT) == 0) { break; } // Notify upper layer that packet has been sent if (*pTxCb) { (*pTxCb)(txStatusFlag); } CIRC_INC( txTd.tail, TX_BUFFERS ); }
// If a wakeup has been scheduled, notify upper layer that it can send // other packets, send will be successfull. if( (CIRC_SPACE(txTd.head, txTd.tail, TX_BUFFERS) >= txTd.wakeupThreshold) && txTd.wakeupCb) { txTd.wakeupCb(); }
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 24)
|
Oct 29 2010, 06:35
|
Местный
  
Группа: Свой
Сообщений: 264
Регистрация: 17-04-07
Из: Москва
Пользователь №: 27 102

|
И еще один вопрос. В функции EMAC_Init, расположенной в emac.c есть следующие строки: Код // Инициализация дескриgторов передающего буфера. for(Index = 0; Index < TX_BUFFERS; Index++) {// Цикл по количеству передающих буферов // Инициализация адресов дескрипторов передающего буфера Address = (unsigned int)(&(pTxBuffer[Index * EMAC_TX_UNITSIZE])); txTd.td[Index].addr = Address; // Нет Маски, т.к. Слово 0 - адрес начала буфера txTd.td[Index].status = EMAC_TX_USED_BIT; // Установка для всех буферов бита used!!! } txTd.td[TX_BUFFERS - 1].status = EMAC_TX_USED_BIT | EMAC_TX_WRAP_BIT; Строка txTd.td[Index].status = EMAC_TX_USED_BIT; устанавливает биты 31 в слове 1 ВСЕХ дескрипторов в единицу, тогда как в документации сказано, что этот бит должен быть установлен только для первого буфера, а при инициализации все биты 31 из слова 1 должны быть сброшены: Цитата This bit is only set for the first buffer in a frame unlike receive where all buffers have the Used bit set once used.
Mark all entries in this list as owned by EMAC, i.e. bit 31 of word 1 set to 0. Вопрос: пример не рабочий получается или что?
|
|
|
|
|
Dec 10 2010, 08:44
|
Знающий
   
Группа: Validating
Сообщений: 838
Регистрация: 31-01-05
Пользователь №: 2 317

|
Цитата Один "специалист" мне когда-то сказал, что Ethernet у ARM есть, но никто не знает как он работает. После чего к арму был успешно прикручен модуль WIZNET. У нас тоже был такой "специалист" как только сказал что нужно поставить WIZNET, так сразу и пошел лесом. Счас работаю c SAM9XE(думаю мак контроллер ничем не отличается) LwIP и FREERTOS, могу сказать что МАС довольно примитивный и простой, посмотрел на примеры от атмела сразу отставил их в сторону, делал все по доке, все работает.
|
|
|
|
|
Dec 14 2010, 06:23
|
Профессионал
    
Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007

|
Пожалуйста. Сам u-boot вы можете скачать с его FTP: ftp://ftp.denx.de/pub/u-boot/Последняя версия : u-boot-2010.09.tar.bz2
|
|
|
|
|
Dec 14 2010, 08:19
|
Местный
  
Группа: Свой
Сообщений: 264
Регистрация: 17-04-07
Из: Москва
Пользователь №: 27 102

|
Спасибо, буду разбираться Мне кажется в U-boot еще больший треш, если честно. Тоже, что и в тестовом примере, только более все разбросано по отдельным файлам и без комментариев. Спасибо MALLOY2, но C++ я к сожалению не знаю  Но Вам огромное уважение, что Вы сам по доке разобрались и написали код!  Я вот никак не могу с этими дескрипторами разобраться.
|
|
|
|
|
Dec 14 2010, 09:22
|
Профессионал
    
Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007

|
Цитата(ZED @ Dec 14 2010, 11:19)  Спасибо, буду разбираться Мне кажется в U-boot еще больший треш, если честно. Тоже, что и в тестовом примере, только более все разбросано по отдельным файлам и без комментариев. Спасибо MALLOY2, но C++ я к сожалению не знаю  Но Вам огромное уважение, что Вы сам по доке разобрались и написали код!  Я вот никак не могу с этими дескрипторами разобраться. Ладно вам накатывать. Пример - он и в Африке пример. Но, по крайней мере, u-boot живой проект и работает. А то что голову придется все равно поднапрячь, так это работа наша такая. Насчет дескрипторов. Обратите внимание на: 1. Выравнивание. 2. Вы же, скорее всего кеши включили? Так вот приемо/передаточные буфера разместите в некешируемой области.
|
|
|
|
|
Dec 14 2010, 09:52
|
Местный
  
Группа: Свой
Сообщений: 264
Регистрация: 17-04-07
Из: Москва
Пользователь №: 27 102

|
Цитата Вы же, скорее всего кеши включили? Так вот приемо/передаточные буфера разместите в некешируемой области. Извините за глупость, я знаю, что в контроллере есть 2 Кэша ICache и DCache. Я так понял, что они нужны для ускорения работы ядра наряду с MMU. Но я с ними так и не разобрался, тем более не знаю как его включать/выключать. Тем более не знаю как вне кэша размещать переменные. И еще я вот тут начал с Вашим кодом разбираться. Вот в функции irq_handler() вызываются две не понятные функции: Код static void irq_handler() { portBASE_TYPE xYieldRequired = pdFALSE; uint32_t status = AT91C_BASE_EMAC->EMAC_ISR; if ( status & AT91C_EMAC_RCOMP) { xSemaphoreGiveFromISR(RxSem, &xYieldRequired); }; portEND_SWITCHING_ISR(&xYieldRequired); } Что должен делать EMAC по прерыванию? В примере он подсчитывает статистику тех или иных ситуаций и возвращает ее в регистр статистики (статуса передачи или приема). А еще какие-то операции с указателями, про которые я задавал вопрос вначале темы.
Сообщение отредактировал ZED - Dec 14 2010, 09:54
|
|
|
|
|
Dec 14 2010, 10:08
|
Знающий
   
Группа: Validating
Сообщений: 838
Регистрация: 31-01-05
Пользователь №: 2 317

|
Цитата Что должен делать EMAC по прерыванию? то что запрограммируете, мне пока статистика не нужна. Если у вас не используется ОС то можно обойтись и без прерываний. У меня используется ОС FreeRTOS и функции о которых вы спрашиваете являются функциями ОС. Цитата Извините за глупость, я знаю, что в контроллере есть 2 Кэша ICache и DCache. Я так понял, что они нужны для ускорения работы ядра наряду с MMU. Но я с ними так и не разобрался, тем более не знаю как его включать/выключать. Тем более не знаю как вне кэша размещать переменные. Если не разберетесь с MMU и кешами, то получите редкую черепаху. О работе с кешами все расписано в ARM926EJ-S™ Technical Reference Manual или на сайте
|
|
|
|
|
Dec 14 2010, 11:57
|
Местный
  
Группа: Свой
Сообщений: 264
Регистрация: 17-04-07
Из: Москва
Пользователь №: 27 102

|
А вот еще вопросик по приему пакетов (фреймов). Я так понял, что его осуществляет у вас функция task Что делает функция pbuf_alloc(PBUF_RAW,1536,PBUF_POOL)? Каков вообще алгоритм приема фрейма? Сначала мы проверяем бит Ownership Слова 0 дескриптора приемного буфера. Если он установлен, это значит, что этот буфер используется. Тогда мы проверяем бит начала фрейма SOF. Если он установлен, то в примере от IAR делается какая-то хитрая операция. Видимо связанная со сбросом предыдущего кадра и подсчетом кол-ва использованных буферов. По мимо всего прочего разрешается прием фрема: Код if ( RxIndx->status & EMAC_RX_SOF_BIT ) { ptr = static_cast<uint8_t*>(p->payload); flen = 0; sof = ~0; }; if ( sof ) ....................... Дальше я пока встрял. Пока пытаюсь разобраться.
|
|
|
|
|
Dec 22 2010, 11:45
|
Местный
  
Группа: Свой
Сообщений: 264
Регистрация: 17-04-07
Из: Москва
Пользователь №: 27 102

|
Я так понял, что когда кадр (фрейм) находится в приемном буфере, а точнее он может находиться сразу в нескольких буферах, то в дескрипторах этих буферах автоматически устанавливается бит used (Ownership = '1'). Помимо всего прочего, в дескрипторах начального буфера и в конечного буфера, где располагается принимаемый фрейм, установлены биты начала кадра SOF и конца кадра EOF. В дескрипторе буфера, где расположен бит конца кадра EOF в слове статуса в битах 0..11 содержится информация о длине фрейма. Тогда можно предложить следующий алгоритм принятия фрейма:
Среди всех буферов с установленным битом Ownership найти буфер с установленным битом начала кадра SOF и буфер с установленным битом конца кадра EOF. Для последнего считать длину. Если таковые не найдены - кадр не принимать! Если буферы с SOF и EOF найдены, значения из них и всех буферах между ними переписать в память функцией memcpy и сбросить бит Ownership.
Прошу Вас прокомментируйте мои соображения. Особенно хочется услышать мнение MALLOY2.
Сообщение отредактировал ZED - Dec 22 2010, 11:52
|
|
|
|
|
Dec 23 2010, 08:20
|
Местный
  
Группа: Свой
Сообщений: 264
Регистрация: 17-04-07
Из: Москва
Пользователь №: 27 102

|
Вы не могли бы прокомментировать мою функцию приема пакета: CODE //----------------------------------------------------------------------------- /// Прием пакета: // pFrame - Адрес области памяти, куда копировать фрейм; // pFrame_Size - Адрес, где расположено значение размера принимаемого кадра //----------------------------------------------------------------------------- void EMAC_Receive_Frame(unsigned char *pFrame, unsigned int *pFrame_Size) { unsigned int Rx_Index_tmp = Rx_Index; // Локальный номер приемных буферов unsigned char SOF_Enable = 0; // Обнаружен бит начала кадра SOF unsigned char EOF_Enable = 0; // Обнаружен бит конца кадра EOF unsigned int *Rx_Buffer_SOF = 0; // Адрес буфера с установленным битом начала кадра SOF // Пока бит Ownership = 1 (буфер используется и в нем есть данные) while (Rx_Descriptor[Rx_Index].addr & EMAC_RX_OWNERSHIP_BIT) { // Перебераем все буферы, чтобы найти буфер с установленным битом // Начала кадра EOF. // Если буфер с установленым битом начала кадра SOF найден // сбросить во всех дескрипторах предыдущих буферов бит Ownership: if (Rx_Descriptor[Rx_Index_tmp].addr & EMAC_RX_SOF_BIT) { // Сбросить предыдущий фрагмент кадра (буфер): while (Rx_Index_tmp != Rx_Index) { // Сбросить бит USED: Rx_Descriptor[Rx_Index].addr &= ~(EMAC_RX_OWNERSHIP_BIT); // Инкрементировать счетчик количества приемных буферов и, // если он равен количеству приемных буферов - обнулить его: if (++Rx_Index == RX_BUFFERS){ Rx_Index = 0; // Обнуление } } // Найдено начало кадра: SOF_Enable = 1; // Запомнить адрес буфера с установленным битом начала кадра SOF Rx_Buffer_SOF = (unsigned int)(&Rx_Buffer[Rx_Index_tmp]) & EMAC_ADDRESS_MASK; // Маска адреса; }
if (Rx_Descriptor[Rx_Index_tmp].addr & EMAC_RX_EOF_BIT) { // Найден конец кадра: EOF_Enable = 0
// Запомнить размер кадра *pFrame_Size = Rx_Descriptor[Rx_Index_tmp].status & EMAC_LENGTH_FRAME; } // Инкрементировать счетчик количества приемных буферов и, // если он равен количеству приемных буферов - обнулить его: if (++Rx_Index_tmp == RX_BUFFERS){ Rx_Index_tmp = 0; // Обнуление } } // Eсли обнаружены биты начала кадра и конца кадра, копировать данные // из буфера в память: if (SOF_Enable && EOF_Enable) { memcpy(pFrame, Rx_Buffer_SOF, *pFrame_Size); } // Обнуление счетчика приемных буферов Rx_Index = 0; // Сбросить бит Ownership во всех дескрипторах: while (Rx_Index != RX_BUFFERS) { // // Сбросить бит USED: Rx_Descriptor[Rx_Index].addr &= ~(EMAC_RX_OWNERSHIP_BIT); // Инкрементировать счетчик приемных буферов Rx_Index++; } // Обнуление счетчика приемных буферов Rx_Index = 0; } // End While } // End Function Я просто думаю, зачем принимать часть кадра? Если все равно его потом отбрасывать? Лучше сразу принимать только корректные фреймы. Жду с нетерпением Ваших комментариев, спасибо!
Сообщение отредактировал IgorKossak - Dec 23 2010, 12:23
Причина редактирования: Для длинного кода используйте теги codebox
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|