|
|
  |
SG-DMA в режиме Stream To Memoy |
|
|
|
Sep 18 2012, 19:57
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Выкладываю то, что получилось и вроде работает. Может кому пригодится. Хотя всеравно остались некоторые вопросы. Для того, чтобы быстро перебросить данные из пользовательской логики в память (например в SDRAM NIOS) вполне подошла sgdma. Спасибо alexPec, подсказал, что переброс данных осуществляется по фронту клока на котором работает sgdma. При этом должны быть в 1 сигналы ready (со стороны sgdma) и valid (со стороны пользовательской логики). Для проверки был создан небольшой модуль, типа источник на пользовательской логике который формирует по сигналу из программы Nios 18 пачек с 32 битными данными (vhdl код (работает) писан на скору руку в аттаче)
AvSource.rar ( 12.26 килобайт )
Кол-во скачиваний: 73. Конфигурация системы та же, что и ранее, только добавлен фифо. Ниже основные моменты программного кода. CODE 1. Переменные и функции (взяты из примера по sgdma alterawiki ) #define NUMBER_OF_BUFFERS 1 // количество буферов #define BUFFER_LENGTH 1152 // длина буфера // указатель на структуру alt_sgdma_dev alt_sgdma_dev *receive_DMA; // Счетчики alt_u32 buffer_counter = 0, contents_counter = 0, temp_length = BUFFER_LENGTH; // указатель на текущий заполненый буфер alt_u32 * receive_ptr; // массив для выдачи результата alt_u8 ethmass_ptr[BUFFER_LENGTH + 16]; // Флаг завершения ДМА операции alt_u8 rx_done = 0; // Дескрипторы alt_sgdma_descriptor *receive_descriptors1, *receive_descriptors_copy1; alt_sgdma_descriptor *receive_descriptors2, *receive_descriptors_copy2;
//--------------------------------------------------------------------------------------------- // Функции
// размещение десрипторов alt_u32 descriptor_allocation(alt_sgdma_descriptor ** receive_descriptors, alt_sgdma_descriptor ** receive_descriptors_copy, alt_u32 number_of_buffers) { /* Allocate some big buffers to hold all descriptors which will slide until * the first 32 byte boundary is found */ void * temp_ptr_2;
/************************************************************** * Allocation of the receive descriptors * * - First allocate a large buffer to the temporary pointer * * - Second check for sucessful memory allocation * * - Third put this memory location into the pointer copy * * to be freed before the program exits * * - Forth slide the tempory pointer until it lies on a 32 * * byte boundary (descriptor master is 256 bits wide) * ************************************************************/ temp_ptr_2 = malloc((number_of_buffers + 2) * ALTERA_AVALON_SGDMA_DESCRIPTOR_SIZE); if(temp_ptr_2 == NULL) { printf("Failed to allocate memory for the receive descriptors\n"); return 1; } *receive_descriptors_copy = (alt_sgdma_descriptor *)temp_ptr_2; while((((alt_u32)temp_ptr_2) % ALTERA_AVALON_SGDMA_DESCRIPTOR_SIZE) != 0) { temp_ptr_2++; // slide the pointer until 32 byte boundary is found } *receive_descriptors = (alt_sgdma_descriptor *)temp_ptr_2; /**************************************************************/ /* Clear out the null descriptor owned by hardware bit. These locations * came from the heap so we don't know what state the bytes are in (owned bit could be high).*/ receive_descriptors[number_of_buffers]->control = 0;
return 0; // no failures in allocation } //--------------------------------------------------------------------------------------------- /******************************************************************************** ** * This function is responsible for allocating the data buffer for each * * descriptor. A random buffer length will be generated if you set the minimum * * and maximum buffer lengths to be different. To run a more controlled test, set * * the minimum and maximum buffer lengths to be equal. * * * * Returns 0 for sucess, 1 for failure. * ******************************************************************************** **/
alt_u32 create_test_data(alt_sgdma_descriptor * receive_descriptors, alt_u32 number_of_buffers, alt_u32 buffer_length) {
alt_u32 buffer_counter, contents_counter, temp_length; alt_u32 *receive_ptr; alt_u8 *receive_ptr_copy; // will use these to fill up the tx buffers and clear the rx buffers
/* Initialization of the buffer memories and the transmit+receive descriptors */ for(buffer_counter = 0; buffer_counter < number_of_buffers; buffer_counter++) { /* Generate a random buffer length between within MINIMUM_BUFFER_LENGTH and MAXIMUM_BUFFER_LENGTH */ temp_length = buffer_length; receive_ptr = (alt_u32 *)malloc(temp_length); // since the same contents will be received the length is the same
/* This will populate sequential data (modulo 256) in each transmit buffer a byte at a time. * The recieve buffers are also cleared with zeros so that each time this software is run * the data can be reverified. Before this function returns a flush will be performed to * make sure none of these writes are still in the data cache. */ receive_ptr_copy = (alt_u8 *)receive_ptr; for(contents_counter = 0; contents_counter < temp_length; contents_counter++) { receive_ptr_copy[contents_counter] = 0; }
/* This will create a descriptor that is capable of transmitting data from an Avalon-ST FIFO * to an Avalon-MM buffer */ alt_avalon_sgdma_construct_stream_to_mem_desc(&receive_descriptors[buffer_counter], // descriptor &receive_descriptors[buffer_counter+1], // next descriptor receive_ptr, // write buffer location (alt_u16)temp_length, // length of the buffer 0); // writes are not to a fixed location
} alt_dcache_flush_all(); // make sure all the transmit buffers and cleared receive buffers go out to main memory return 0; // no failures creating data buffers }
//--------------------------------------------------------------------------------------------- // Обработчик прерываний SGDMA_0_IRQ static void receive_callback_function(void * context) { rx_done++; if(rx_done > 1) rx_done = 0;
}
//--------------------------------------------------------------------------------------------- // Задержка void Delay ( tick) { while(tick--); }
2. В main CODE int main (void) { // Открыть SGDMA receive_DMA = alt_avalon_sgdma_open("/dev/sgdma_0"); if(receive_DMA == NULL) { printf("Could not open the receive SG-DMA\n"); } else printf("Open the receive SG-DMA... success\n");
// размещение дескрипторов descriptor_allocation(&receive_descriptors1, &receive_descriptors_copy1, NUMBER_OF_BUFFERS); descriptor_allocation(&receive_descriptors2, &receive_descriptors_copy2, NUMBER_OF_BUFFERS);
// создание дескрипторов create_test_data(receive_descriptors1, NUMBER_OF_BUFFERS, BUFFER_LENGTH); create_test_data(receive_descriptors2, NUMBER_OF_BUFFERS, BUFFER_LENGTH);
// определение подпрограммы обработчика прерываний alt_avalon_sgdma_register_callback(receive_DMA, &receive_callback_function, (ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK), NULL); // главный цикл while (1) { Delay (0.1 сек)
// старт приема по sgdma if(rx_done) { // старт транзации во второй буфер alt_avalon_sgdma_do_async_transfer(receive_DMA, &receive_descriptors2[0]); // пуск пакета N 2 1152 байта из источника (пользовательской логики) IOWR_ALTERA_AVALON_PUSK(AVSOURCE_0_BASE); Delay(0x0007); IOWR_ALTERA_AVALON_STOP(AVSOURCE_0_BASE); } else { // старт транзации в первый буфер alt_avalon_sgdma_do_async_transfer(receive_DMA, &receive_descriptors1[0]); // пуск пакета N 1 1152 байта из источника (пользовательской логики) IOWR_ALTERA_AVALON_PUSK(AVSOURCE_0_BASE); Delay(0x0007); IOWR_ALTERA_AVALON_STOP(AVSOURCE_0_BASE); } // получение результата for(buffer_counter = 0; buffer_counter < NUMBER_OF_BUFFERS; buffer_counter++) { if(rx_done) receive_ptr = receive_descriptors1[buffer_counter].write_addr; else receive_ptr = receive_descriptors2[buffer_counter].write_addr; } for(contents_counter = 0; contents_counter < temp_length; contents_counter++) { // массив с результатом ethmass_ptr[contents_counter + 16] = IORD_8DIRECT((alt_u32)receive_ptr, contents_counter); ... далее выдача по ethenet... } }
} Механизм работает так, что когда стартует транзакция в первый буфер, со второго буфера данные перебрасываются в массив результата и наоборот. Смена стартующих дескрипторов должна происходить по смене флага в прерывании. Так оно вроде и происходит. Но смущают несколько моментов. 1. Не всегда последовательно сменяются буфера для транзакции и следовательно результата. 2. В дебагере почему-то прерывание возникает не после выдачи положенного количества байт из пользовательской логики, тоесть после заполнения одного из буферов-дескрипторов, а после заполнения буфера + очередного вызова функции alt_avalon_sgdma_do_async_transfer Когда все же возникает прерывание? После транзакции последнего байта(слова... др.) в текущий буфер?
Сообщение отредактировал Acvarif - Sep 18 2012, 20:01
|
|
|
|
|
Sep 19 2012, 16:15
|
Профессионал
    
Группа: Свой
Сообщений: 1 284
Регистрация: 9-04-06
Пользователь №: 15 968

|
Цитата 1. Не всегда последовательно сменяются буфера для транзакции и следовательно результата. А у вас обработка прерывания точно заканчивается до того как возникает новое? Цитата 2. В дебагере почему-то прерывание возникает не после выдачи положенного количества байт из пользовательской логики, тоесть после заполнения одного из буферов-дескрипторов, а после заполнения буфера + очередного вызова функции alt_avalon_sgdma_do_async_transfer Когда все же возникает прерывание? После транзакции последнего байта(слова... др.) в текущий буфер? А что у вас в регистре в control register? Там разрешаются разные прерывания, у вас какие разрешены? IE_Error - по ошибке IE_EOP_ENcountered - когда генерится EOP IE_descriptor completed - по завершению обработки дескриптора (после передачи последнего слова дескриптора) IE_descriptor chain completed - по завершению обработки цепочки дескрипторов (после последнего дескриптора в цепочке) IE_global - запрещает все/разрешает разрешенные В доке все это есть, можно подробней посмотреть...
|
|
|
|
|
Sep 19 2012, 17:29
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(alexPec @ Sep 19 2012, 19:15)  А у вас обработка прерывания точно заканчивается до того как возникает новое? Вроде да. Программно с периодом ~5 Герц делаю запуск пакета из пользовательской логики. Буфер sgdma точно выставлен на количество байт посылаемого из пользовательской логики пакета. Я так понимаю, что прерывание должно произойти после заполнения буфера. Похоже так оно и происходит. Еще немного все упростил и получилось так. В цикле (с задержкой - получается ~5 Гц) запускаю транзакцию в один буфер и передачу по ethernet из другого буфера. CODE #define NUMBER_OF_BUFFERS 1 #define BUFFER_LENGTH 16 alt_sgdma_descriptor *receive_descriptors1, *receive_descriptors_copy1; alt_sgdma_descriptor *receive_descriptors2, *receive_descriptors_copy2; alt_sgdma_descriptor *receive_descriptors_sw, *receive_descriptors_copy_sw; // если была передача по Ethernet if(!buff_done) { // запуск транзакции в чередной буфер alt_avalon_sgdma_do_async_transfer(receive_DMA, &receive_descriptors_sw[0]); // пуск пакета из пользовательской логики IOWR_ALTERA_AVALON_PUSK(AVSOURCE_0_BASE); Delay(0x000f); IOWR_ALTERA_AVALON_STOP(AVSOURCE_0_BASE); } // обработка и посылка пакета из предыдущего буфера if(buff_done) { for(buffer_counter = 0; buffer_counter < NUMBER_OF_BUFFERS; buffer_counter++) { receive_ptr = receive_descriptors_sw[buffer_counter].write_addr; for(contents_counter = 0; contents_counter < temp_length; contents_counter++) { // формирование пакетов COM и Ethernet chltemp_receive[contents_counter] = 0; chltemp_receive[contents_counter] = IORD_8DIRECT((alt_u32)receive_ptr, contents_counter); ethmass_ptr[contents_counter + 16] = chltemp_receive[contents_counter]; } IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, led); // послать сом и Ethernet пакет fprintf(fp, chltemp_receive); eth_ocm_raw_send(ethmass_ptr, sizeof(ethmass_ptr)); } // пакеты посланы buff_done = 0; }
В прерывании: CODE // Обработчик прерываний SGDMA_0_IRQ static void receive_callback_function(void * context) { rx_done++; if(rx_done > 1) rx_done = 0; if(rx_done) { receive_descriptors_sw = receive_descriptors1; receive_descriptors_copy_sw = receive_descriptors_copy1; } else { receive_descriptors_sw = receive_descriptors2; receive_descriptors_copy_sw = receive_descriptors_copy2; }
buff_done = 1; } Обработчик инициализируется так Код // определение подпрограммы обработчика прерываний alt_avalon_sgdma_register_callback(receive_DMA, &receive_callback_function, (ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK), NULL); Тоесть прерывание возникнет по биту завершения транзакции в цепочке буферов. Этот механизм вроде работает. Судя по данным на COM все работает попеременно и без сбоев. Но Ethernet сниффер фиксирует повторяющиеся пакеты. Похоже нужно будет поглубже разобраться с Ethernet. Спасибо. С Вашей помощью все постепенно становится на свои места. Не ясно пока до конца по поводу прерывания и количества буферов. Если допустим имеется не один буфер, типа: Код #define NUMBER_OF_BUFFERS 4 #define BUFFER_LENGTH 16 Запуск транзакции начинается по нулевому дескриптору типа Код alt_avalon_sgdma_do_async_transfer(receive_DMA, &receive_descriptors_sw[0]); То когда возникнет прерывание, если в контрольном регистре анализируется бит завершения транзакци цепочки (так определено в alt_avalon_sgdma_register_callback )? В данном случае цепочка состоит из 4_х буферов по 16 байт каждый. Я так понимаю кода будут посланы 4 пакета по 16 байт из пользовательской логики?
|
|
|
|
|
Sep 19 2012, 19:27
|
Профессионал
    
Группа: Свой
Сообщений: 1 284
Регистрация: 9-04-06
Пользователь №: 15 968

|
Цитата(Acvarif @ Sep 19 2012, 21:29)  Но Ethernet сниффер фиксирует повторяющиеся пакеты. Похоже нужно будет поглубже разобраться с Ethernet. Ну так сформируйте в дополнительный байтик в пакете - номер пакета. Пусть он по кругу крутится. Если будет повторяющийся с точностью до байта - то значит повторяется передача одного и того же пакета, а если номер отличается на 2 (или через сколько вы там повторяете) то значит есть пропуски пакетов. Дальше уже и думать. Цитата Не ясно пока до конца по поводу прерывания и количества буферов. В данном случае цепочка состоит из 4_х буферов ... Зачем вам цепочка из 4 буферов? Одного ведь должно хватать, 5 раз в сек. такие пакетики отправлять... Цепочку есть смысл делать (опять же мое мнение) если: 1. Большой размер пакета (больше 0xff00) - тут даже необходимо 2. Если у вас неравномерная обработка (по времени) от пакета к пакету или неравномерная передача пакетов (от источника), т.е. если за время обработки одного пакета может прийти 2 и более. Прерывание у вас правильно, по концу цепочки, но тогда надо делать 2 цепочки. Сейчас у вас заполнилась цепочка дескрипторов (4 пакета) - вы начинаете ее обрабатывать, а прием пакетов не ведется. Только когда обработаете, запускаете прием пакетов (иначе рискуете потерять пакеты). Я делал так: - формируем 2 цепочки. -принимаем первую цепочку, в это время обрабатываем вторую. -чтоб все было правильно, обработка завершается (должна) до заполнения первой цепочки,затем выходим из прерывания. -ждем (или че-то делаем) где-то в основной программе до возникновения прерывания завершения цепочки -в процедуре обработки прерывания ПЕРВЫМ ДЕЛОМ запускаем DMA приема второй цепочки -принимаем вторую, в это время обрабатываем первую цепочку. И так с начала. В этом случае более рационально используется время процессора и шина, поскольку ОДНОВРЕМЕННО ведется и обработка, и заполнение буфера.
|
|
|
|
|
Sep 20 2012, 06:40
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(alexPec @ Sep 19 2012, 22:27)  Ну так сформируйте в дополнительный байтик в пакете - номер пакета. Пусть он по кругу крутится. Если будет повторяющийся с точностью до байта - то значит повторяется передача одного и того же пакета, а если номер отличается на 2 (или через сколько вы там повторяете) то значит есть пропуски пакетов. Дальше уже и думать. Спасибо. Вы как в воду глядели. Действительно имеют место пропуски пакетов. Надо будет разбираться. Цитата Зачем вам цепочка из 4 буферов? Одного ведь должно хватать, 5 раз в сек. такие пакетики отправлять... Цепочку есть смысл делать (опять же мое мнение) если: 1. Большой размер пакета (больше 0xff00) - тут даже необходимо 2. Если у вас неравномерная обработка (по времени) от пакета к пакету или неравномерная передача пакетов (от источника), т.е. если за время обработки одного пакета может прийти 2 и более. Это я ради теста сделал так медленно и мало. В реальности пакеты из 48 слов (96 байт) будут идти через каждые 8 мкс непрерывно. Цитата Я делал так: - формируем 2 цепочки. -принимаем первую цепочку, в это время обрабатываем вторую. -чтоб все было правильно, обработка завершается (должна) до заполнения первой цепочки,затем выходим из прерывания. -ждем (или че-то делаем) где-то в основной программе до возникновения прерывания завершения цепочки -в процедуре обработки прерывания ПЕРВЫМ ДЕЛОМ запускаем DMA приема второй цепочки -принимаем вторую, в это время обрабатываем первую цепочку. И так с начала.
В этом случае более рационально используется время процессора и шина, поскольку ОДНОВРЕМЕННО ведется и обработка, и заполнение буфера. Спасибо. Уяснил. В прерывании запускаю новую транзакцию, а то, что имеется в предыдущем буфере выдаю по Ethernet. Выдать должен успеть до окончания текущей транзакции, тоесть до следующего прерывания. Судя по проведенному тесту sgdma работает правильно. Буфера меняются как положено. Транзакции идут без сбоев. Теперь придется копать Ethernet... А не может сниффер (Wireshark) пропускать пакеты? Маловероятно...
|
|
|
|
|
Sep 21 2012, 13:48
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(alexPec @ Sep 21 2012, 14:39)  Я бы сниферам не сильно доверял. Может комп не успевать, кривость снифера и т.д. Я бы простенькое приложение сделал, которое ловит пакеты на другом компе (куда отправляет ваш девайс) и проверяет номер, если пропуск - вываливает окошко с сообщением - делов на час. Да, Вы правы. Сниффер пропускает. Путем разных манипуляций удается его заставить работать без пропусков. Но в конечном итоге всеравно придется приложение делать. С приемом сырых пакетов (в Windows) вроде библиотека WinPcap справляется. И подключить ее удается только в Visual C. A у нас в основном Builder в ходу. Посоветуйте пожалуйста, может какой другой путь имеется.
|
|
|
|
|
Sep 28 2012, 07:44
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
При наращивании количества данных поступающих на sgdma попал в засаду. Если можно, прошу проследить основной код. При инициализации формирую цепочку из 4_х буферов по 1152 байта и 3 дескриптора (2 разных и один для их переключения ) Код #define NUMBER_OF_BUFFERS 4 #define BUFFER_LENGTH 1152 alt_sgdma_descriptor *receive_descriptors1, *receive_descriptors_copy1; alt_sgdma_descriptor *receive_descriptors2, *receive_descriptors_copy2; alt_sgdma_descriptor *receive_descriptors_sw, *receive_descriptors_copy_sw; В основном цикле main c периодом ~200 ms делаю запуск транзакции от пользовательской логики 16-ти пакетов по 1152 байта с предварительным вызовом alt_avalon_sgdma_do_async_transfer Код alt_avalon_sgdma_do_async_transfer(receive_DMA, &receive_descriptors_sw[0]); IOWR_ALTERA_AVALON_PUSK(FIRSOURCE_0_BASE); Delay(0x0002); IOWR_ALTERA_AVALON_STOP(FIRSOURCE_0_BASE); Delay(0x000f); В прерываниях по заполнению цепочки (в данном случае цепочка из 4_х буферов по 1152 байта) опять вызываю alt_avalon_sgdma_do_async_transfer(receive_DMA, &receive_descriptors_sw[0]); меняю дескрипторы и передаю по Ethernet (4 раза) то, что накопилось на предыдущем дескрипторе. Поскольку из пользовательской логики поступает 16 пакетов по 1152 байта то прерывания должны возникнуть 4 раза. CODE alt_avalon_sgdma_do_async_transfer(receive_DMA, &receive_descriptors_sw[0]);
rx_done++; if(rx_done == 2) rx_done = 0; if(rx_done) { rx_done = 0; receive_descriptors_sw = receive_descriptors1; receive_descriptors_copy_sw = receive_descriptors_copy1; } else { receive_descriptors_sw = receive_descriptors2; receive_descriptors_copy_sw = receive_descriptors_copy2; }
for(buffer_counter = 0; buffer_counter < NUMBER_OF_BUFFERS; buffer_counter++) { receive_ptr = receive_descriptors_sw[buffer_counter].write_addr;
// послать Ethernet пакет ethmass_ptr[15]++; ethmass_ptr[14] = eth_ocm_raw_send(receive_ptr, 1152);
} Почему то такая схема не работает. Выснет на прерываниях. Я уже и букварь по sgdma перечитывал. Вроде все должно работать. Похоже происходит чехарда с битами регистра управления. Но что конкретно не пойму...
|
|
|
|
|
Sep 28 2012, 10:33
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(alexPec @ Sep 28 2012, 12:37)  Регистр статуса и контрола в каком состоянии после зависания? ошибки не возникает (бит ошибки должен быть установлен)? Если прерывания по ошибке нет, то дма остановливается, прерывания не возникает и дальше прерываний уже не будет
Кстати, как виснет-то? Проц встает или прерываний просто нет? Попробую прочитать регистр статуса. Но думаю, там все нормально. Виснет, в смысле просто зацикливается на прерывании. Данные на sgma поступили один раз (первый пуск sgma из основного цикла). Далее по заполнению первой цепочки - прерывание - и далее все крутится в прерывании с выдачей по Ethernet имеющихся данных в буферах. пытаюсь использовать бит PARK (регистр управления) при пуске sgma и пуске каждого нового пакета Код // старт приема по sgdma
rx_done = 0;
receive_descriptors_sw = receive_descriptors1; receive_descriptors_copy_sw = receive_descriptors_copy1;
// чтение регистра управления control = IORD_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_0_BASE); // control |= ALTERA_AVALON_SGDMA_CONTROL_PARK_MSK; // запись регистра управления IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_0_BASE, control);
alt_avalon_sgdma_do_async_transfer(receive_DMA, &receive_descriptors_sw[0]); // запуск пакета из пользовательской логики IOWR_ALTERA_AVALON_PUSK(FIRSOURCE_0_BASE); Delay(0x0002); IOWR_ALTERA_AVALON_STOP(FIRSOURCE_0_BASE); Delay(0x000f); В прерываниях делаю так Код irq_count ++; if(irq_count == 4) irq_count = 0; // на последнем прерывании запуск sgdma не делать if(irq_count < 4) alt_avalon_sgdma_do_async_transfer(receive_DMA, &receive_descriptors_sw[0]);
rx_done++; if(rx_done == 2) rx_done = 0; if(!rx_done) { receive_descriptors_sw = receive_descriptors1; receive_descriptors_copy_sw = receive_descriptors_copy1; } else { receive_descriptors_sw = receive_descriptors2; receive_descriptors_copy_sw = receive_descriptors_copy2; }
for(buffer_counter = 0; buffer_counter < NUMBER_OF_BUFFERS; buffer_counter++) { receive_ptr = receive_descriptors_sw[buffer_counter].write_addr;
// послать Ethernet пакет ethmass_ptr[15]++; ethmass_ptr[14] = eth_ocm_raw_send(receive_ptr, 1152);
} Зависание прекращается, но происходит путаница с пакетами. Вместо данных с первого пакета (4 буфера по 1152 байт) идут предпоследние 4 буфера, затем все по очереди. Прочитал регистр статуса после 4_х прерываний (первая транзакция и прием 16 пакетов) = 0хС. Тоесть без ошибок. Дескрипторы и цепочка завершены. В следующие 4 прерывания (теперь все уже крутится в подпрограмме прерываний) = 0х8. Длее остается 0х8 А вот регистр управления после транзакции 16 пакетов содержит 0хFF78. При инициализации я устанавливаю биты MAX_DESC_PROCESSED = 0хff00.
Сообщение отредактировал Acvarif - Sep 28 2012, 11:46
|
|
|
|
|
Sep 28 2012, 13:17
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(alexPec @ Sep 28 2012, 15:43)  А покажите дамп сформированных дескрипторов Дескрипторы формирую так CODE // размещение дескрипторов return_code = descriptor_allocation(&receive_descriptors1, &receive_descriptors_copy1, NUMBER_OF_BUFFERS); return_code = descriptor_allocation(&receive_descriptors2, &receive_descriptors_copy2, NUMBER_OF_BUFFERS);
// создание дескрипторов return_code = create_test_data(receive_descriptors1, NUMBER_OF_BUFFERS, BUFFER_LENGTH); return_code = create_test_data(receive_descriptors2, NUMBER_OF_BUFFERS, BUFFER_LENGTH);
// определение подпрограммы обработчика прерываний alt_avalon_sgdma_register_callback(receive_DMA, &receive_callback_function, (ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK), NULL); Контролирую успешное их формирование (по каждому) так Код if(return_code == 1) { printf("Allocating the data buffers failed... exiting\n"); return 1; } else printf("Allocating the data buffers... success\n"); Функции тут: CODE // размещение десрипторов alt_u32 descriptor_allocation(alt_sgdma_descriptor ** receive_descriptors, alt_sgdma_descriptor ** receive_descriptors_copy, alt_u32 number_of_buffers) { /* Allocate some big buffers to hold all descriptors which will slide until * the first 32 byte boundary is found */ void * temp_ptr_2;
/************************************************************** * Allocation of the receive descriptors * * - First allocate a large buffer to the temporary pointer * * - Second check for sucessful memory allocation * * - Third put this memory location into the pointer copy * * to be freed before the program exits * * - Forth slide the tempory pointer until it lies on a 32 * * byte boundary (descriptor master is 256 bits wide) * ************************************************************/ temp_ptr_2 = malloc((number_of_buffers + 2) * ALTERA_AVALON_SGDMA_DESCRIPTOR_SIZE); if(temp_ptr_2 == NULL) { printf("Failed to allocate memory for the receive descriptors\n"); return 1; } *receive_descriptors_copy = (alt_sgdma_descriptor *)temp_ptr_2; while((((alt_u32)temp_ptr_2) % ALTERA_AVALON_SGDMA_DESCRIPTOR_SIZE) != 0) { temp_ptr_2++; // slide the pointer until 32 byte boundary is found } *receive_descriptors = (alt_sgdma_descriptor *)temp_ptr_2; /**************************************************************/ /* Clear out the null descriptor owned by hardware bit. These locations * came from the heap so we don't know what state the bytes are in (owned bit could be high).*/ receive_descriptors[number_of_buffers]->control = 0;
return 0; // no failures in allocation } //--------------------------------------------------------------------------------------------- /******************************************************************************** ** * This function is responsible for allocating the data buffer for each * * descriptor. A random buffer length will be generated if you set the minimum * * and maximum buffer lengths to be different. To run a more controlled test, set * * the minimum and maximum buffer lengths to be equal. * * * * Returns 0 for sucess, 1 for failure. * ******************************************************************************** **/
alt_u32 create_test_data(alt_sgdma_descriptor * receive_descriptors, alt_u32 number_of_buffers, alt_u32 buffer_length) {
alt_u32 buffer_counter, contents_counter, temp_length; alt_u32 *receive_ptr; alt_u8 *receive_ptr_copy; // will use these to fill up the tx buffers and clear the rx buffers
/* Initialization of the buffer memories and the transmit+receive descriptors */ for(buffer_counter = 0; buffer_counter < number_of_buffers; buffer_counter++) { /* Generate a random buffer length between within MINIMUM_BUFFER_LENGTH and MAXIMUM_BUFFER_LENGTH */ temp_length = buffer_length; receive_ptr = (alt_u32 *)malloc(temp_length); // since the same contents will be received the length is the same
/* This will populate sequential data (modulo 256) in each transmit buffer a byte at a time. * The recieve buffers are also cleared with zeros so that each time this software is run * the data can be reverified. Before this function returns a flush will be performed to * make sure none of these writes are still in the data cache. */ receive_ptr_copy = (alt_u8 *)receive_ptr; for(contents_counter = 0; contents_counter < temp_length; contents_counter++) { receive_ptr_copy[contents_counter] = 0; }
/* This will create a descriptor that is capable of transmitting data from an Avalon-ST FIFO * to an Avalon-MM buffer */ alt_avalon_sgdma_construct_stream_to_mem_desc(&receive_descriptors[buffer_counter], // descriptor &receive_descriptors[buffer_counter+1], // next descriptor receive_ptr, // write buffer location (alt_u16)temp_length, // length of the buffer 0); // writes are not to a fixed location
} alt_dcache_flush_all(); // make sure all the transmit buffers and cleared receive buffers go out to main memory return 0; // no failures creating data buffers } Подскажите пожалуйста как (увидеть) показать дамп.
Сообщение отредактировал Acvarif - Sep 28 2012, 13:22
|
|
|
|
|
Sep 29 2012, 09:23
|
Профессионал
    
Группа: Свой
Сообщений: 1 284
Регистрация: 9-04-06
Пользователь №: 15 968

|
Цитата(Acvarif @ Sep 28 2012, 23:42)  С дампом (как вывести на консоль) так и не разобрался. Опять перечитывал букварь по sgdma. Обратил внимание на бит PARK (режим паркинг). Если бит в 0, то после заполнения цепочки буферов (в моем случае 4 буфера, а значит 4 дескриптора) затем смены и заполнения другой цепочки, повторно эти цепочки уже работать не будут. Для того, чтобы ими воспользоваться снова, нужно установить бит PARK и вызвать функцию пуска транзакции. Или я не правильно все понял? Дамп - в ниосе window->show view->memory, выбираете адрес начала дескрипторов Насчет PARK- точно не помню, тоже долго с ним разбирался год назад, но он точно отвечает за повторные запуски, похоже вы правильно поняли.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|