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

|
Виноват. Ошибка вышла. Попутал sgdma и dma. Пытаюсь запустить sgdma CODE // открыть sgdma alt_sgdma_dev * 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"); // определение подпрограммы обработчика прерываний 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); эта часть работает Я так понимаю, что далее нужно определить alt_sgdma_descriptor где будут определены все необходимые параметры для приема данных (куда помещать данные, размер буфера...). И далее уже можно делать запуск типа Код alt_avalon_sgdma_do_async_transfer(receive_DMA, &receive_descriptors); В этом совсем запутался. Подскажите пожалуйста как правильно описать alt_sgdma_descriptor. Пока так и не врубился в последовательность операций для одной транзакции по заполнению буфера. Как все происходит в нескольких словах? Что делать когда буфер заполнен? Куда помещать следующий пакет с данными? Ответьте пожалуйста кому не лень.
|
|
|
|
|
Sep 5 2012, 08:20
|
Профессионал
    
Группа: Свой
Сообщений: 1 284
Регистрация: 9-04-06
Пользователь №: 15 968

|
Штатными функциями все делается. (с небольшим допиливанием) Код // Now construct SGDMA descriptors for each frame buffer for( i = 0; i < num_buffers; i++ ) { setup_adc_descriptors( display, // our display display->buffer_ptrs[i], // frame display->buffer_ptrs[i]->buffer, // frame location display->buffer_ptrs[i]->desc_base ); // descriptor memory Код void setup_adc_descriptors( alt_video_display *display, alt_video_frame *frame, alt_u32 *buffer, alt_sgdma_descriptor *desc_base) { int i; alt_u16 length; alt_32 buffer_no_cache_bypass; alt_sgdma_descriptor *last_descriptor;
/* * We don't want the "uncached" bit set in the buffer address we hand * off to the SGDMA, so we mask it out here. */ buffer_no_cache_bypass = (alt_u32) alt_remap_cached(buffer, display->bytes_per_frame );
for(i=0; i<display->descriptors_per_frame; i++){ /* * Calculate the data length associated with each descriptor, taking * into account the edge cases */ if(i == (display->descriptors_per_frame-1)) { length = (display->bytes_per_frame % ALT_VIDEO_DISPLAY_BYTES_PER_DESC);
/* * The init routine calculated the number of desriptors per frame, * based on frame size (bytes) and bytes per descriptor. Being evenly * divisible on this last frame means a full-length sized frame. */ if(length == 0) { length = ALT_VIDEO_DISPLAY_BYTES_PER_DESC; } } else { length = ALT_VIDEO_DISPLAY_BYTES_PER_DESC; }
/* Construct the descriptor */ [b]alt_avalon_sgdma_construct_stream_to_mem_desc( (frame->desc_base + i), /* Descriptor */ ( frame->desc_base + i + 1 ), /* Next descriptor */ (alt_u32*)( (alt_u8*)buffer_no_cache_bypass + (ALT_VIDEO_DISPLAY_BYTES_PER_DESC*i) ), /* Write Address */ length, /* Transfer length */ 0 /* Don't write fixed addr */ );[/b]
/* * The last descriptor we created above requires a special modification: * Its "next" pointer should point back to the first descriptor in the * chain to create a loop. * * This was not done done in the above SGDMA descriptor creation routine * call because that routine always terminates the 'next' descriptor * pointer to prevent the SGDMA from continuing into unknown memory. */ if( i == ( display->descriptors_per_frame - 1 ) ) { last_descriptor = (alt_sgdma_descriptor *) (frame->desc_base + i);
// IOWR_32DIRECT((alt_u32)(&last_descriptor->next), 0, // (alt_u32)(frame->desc_base)); } } } По транзакциям - запускаете sgdma, он ждет данные (по первому дескриптору), т.е. данные приходят (количество байт указываете при создании каждого дескриптора) - он их записывает по адресам, начиная с WriteAddress. Когда примет и запишет заданное кол-во байт - либо останавливается (зависит от битика вроде в регистре control, точно не помню), либо переходит к следующему дескриптору автоматоматом - т.е. ждет следующую порцию байт и записывает их по write adress дескриптора. Если остановился - то надо запустить след. транзакцию функцией. Ну уж а куда распихивать - сами думайте. ДМА записывает данные которые приходят в память, которую вы указываете в дескрипторе, как организовать потом обработку (т.е. куда девать данные) - вам решать. Пока дма "знает" куда деть данные (т.е. пока дескрипторы не закончились и количество байт, указанное в дескрипторе не пришло) сигнал ready активен, как только пришел последний байт последнего дескриптора (дескрипторы закончились) - сигнал ready стает неактивен.
|
|
|
|
|
Sep 5 2012, 12:09
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Спасибо. У Вас в коде несколько дисрипторов, тоесть несколько буферов. (Если я правильно все понял) Для того, чтобы все хорошо понять пытаюсь написать небольшой код пока только с одним дискриптором. sgdma должна будет осуществлять транзакции от пользовательской логики в SDRAM, тоесть получается должен работать только receive_DMA в один и тот же буфер. Пока хотя-бы так, чтобы увидеть, что буфер (16 слов - 32 байта) заполнился. Пытаюсь понять механизм в простейшем варианте. Вот что получилось CODE // открыть sgdma alt_sgdma_dev * 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"); alt_sgdma_descriptor *receive_descriptors, *receive_descriptors_copy, *wraddr; alt_avalon_sgdma_construct_stream_to_mem_desc( &receive_descriptors, /* Descriptor */ &receive_descriptors_copy, /* Next descriptor */ &wraddr, /* Write Address */ 32, /* Transfer length */ 0 /* Don't write fixed addr */ );
// старт приема по sgdma alt_avalon_sgdma_do_async_transfer(receive_DMA, &receive_descriptors); Будет ли такая конструкция работать? Или в ней чего-то не хватает? Как можно прочитать данные из ячейки sdram зная SDRAM_BASE и wraddr? Также не врубаюсь, что будет после того как sgdma загрузит в sdram все 32 байта. Что будет когда прийдет 33_й сигнал valid. Опять начнется транзакция? Если да то куда?
Сообщение отредактировал Acvarif - Sep 5 2012, 13:20
|
|
|
|
|
Sep 6 2012, 05:03
|
Профессионал
    
Группа: Свой
Сообщений: 1 284
Регистрация: 9-04-06
Пользователь №: 15 968

|
Цитата(Acvarif @ Sep 5 2012, 16:09)  Спасибо.
У Вас в коде несколько дисрипторов, тоесть несколько буферов. (Если я правильно все понял) Буферов два: один заполняем, другой-обрабатываем. Иначе нет гарантии, что пока мы обрабатываем один буфер, туда уже на попадут данные со следующей транзакции (конечно ели она запущена). А вот дескрипторов может быть больше одного на буфер, поскольку один дескриптор может описать передачу максимум 0xFF00 байт. Если больше надо передать - создается цепочка дескрипторов. Работать вроде должно. Цитата Как можно прочитать данные из ячейки sdram зная SDRAM_BASE и wraddr? Да можно просто wraddr знать, адресация то не относительная, а абсолютная. Можно посмотреть например в дебагере window->show view -> memory. Забиваете свой адрес туда и смотрите что там есть. Цитата Также не врубаюсь, что будет после того как sgdma загрузит в sdram все 32 байта. Если не стартовать следующую транзакцию, я же писал, sgdma выставит на выходе ready лог.0 Цитата Что будет когда прийдет 33_й сигнал valid. Опять начнется транзакция? Если да то куда? Прийти то он может и придет, только sgdma принять его откажется, выставив лог.0 на выходе ready. Транзакция начнется только кода вы ее запустите, а куда - укажет первый дескриптор, адрес которого забит в регистр sgdma next_descriptor_pointer. Вообще почитайте у альтеры по ниос раздел Embedded periferals, про sgdma - там и про дескрипторы, и про регистры, и функции для создания дескрипторов, и запуск транзакций - все есть.
|
|
|
|
|
Sep 7 2012, 13:21
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(alexPec @ Sep 6 2012, 08:03)  Буферов два: один заполняем, другой-обрабатываем. Иначе нет гарантии, что пока мы обрабатываем один буфер, туда уже на попадут данные со следующей транзакции (конечно ели она запущена). А вот дескрипторов может быть больше одного на буфер, поскольку один дескриптор может описать передачу максимум 0xFF00 байт. Если больше надо передать - создается цепочка дескрипторов. Спасибо. Почти разобрался. Но осталась еще пара непонятностей. На базе пользовательской логики (Стрим источник) соединенной с SGDMA сделал автомат который работает следующим образом: 1. Программно (в цикле) по старту sgdma (функция alt_avalon_sgdma_do_async_transfer) в автомате устанавливается сигнал ready 2. C небольшой задержкой, после того как установился ready, автомат формирует 32 импульса valid по фронтам которых из двухпортовой памяти на вход data sgdma поступают известные данные (константы 16 бит типа 0x0102 0x0304 ...). Тоесть в общем 64 байта информации. Если при формировании дескрипторов для sgdma я установлю один буфер длиной 64 байта то я надеялся, что при каждом вызове alt_avalon_sgdma_do_async_transfer sgdma заберет 64 байта данных, тоесть сформирует 32 импульса ready в ответ на 32 импульса valid, и на последнем valid сбросит сигнал ready в 0. Но реально на осцилляторе видно только 4 первых ответа ready на valid. Получается что в sdram будут переброшены только 4 первых слова. В чем тут хитрость? Что у меня не так? Код ниже (сделан на базе примера sg-dma от altera viki): 1. Функции + переменные CODE /* each direction so double this for the total */ #define NUMBER_OF_BUFFERS 1 #define BUFFER_LENGTH 64 alt_u32 descriptor_allocation(alt_sgdma_descriptor ** receive_descriptors, alt_sgdma_descriptor ** receive_descriptors_copy, alt_u32 number_of_buffers);
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 = 32; alt_u32 * receive_ptr; alt_u8 *temp_receive; alt_u8 chltemp_receive[33]; // Флаг завершения ДМА операции static volatile alt_u8 rx_done = 0; //--------------------------------------------------------------------------------------------- // Функции
// размещение десрипторов 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 alt_u32 temp_data = 0;
/* 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; temp_data++; }
/* 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 } //--------------------------------------------------------------------------------------------- void receive_callback_function(void * context) { rx_done++; /* main will be polling for this value being 1 */ } 2. Инициализация CODE alt_sgdma_dev *receive_DMA;
// Открыть 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");
// alt_sgdma_descriptor дескрипторы alt_sgdma_descriptor *receive_descriptors, *receive_descriptors_copy; alt_u32 return_code;
// размещение дескрипторов return_code = descriptor_allocation(&receive_descriptors, &receive_descriptors_copy, NUMBER_OF_BUFFERS); if(return_code == 1) { printf("Allocating the descriptor memory failed... exiting\n"); return 1; } else printf("Allocating the descriptor memory... success\n");
// определение подпрограммы обработчика прерываний 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); Запуск SGDMA и получение результата CODE // старт приема по sgdma
return_code = create_test_data(receive_descriptors, NUMBER_OF_BUFFERS, BUFFER_LENGTH); if(return_code == 1) { printf("Allocating the data buffers failed... exiting\n"); return 1; } else printf("Allocating the data buffers... success\n"); // запуск SGDMA if(alt_avalon_sgdma_do_async_transfer(receive_DMA, &receive_descriptors[0]) != 0) { printf("Writing the head of the receive descriptor list to the DMA failed\n"); return 1; } else printf("Writing the head of the receive descriptor list to the DMA ... success\n"); // ожидание заполнения дискрипторов while(rx_done == 0) {} printf("The receive SGDMA has completed\n"); // получение результата /* loop through each descriptor */ for(buffer_counter = 0; buffer_counter < NUMBER_OF_BUFFERS; buffer_counter++) { receive_ptr = receive_descriptors[buffer_counter].write_addr; temp_length = receive_descriptors[buffer_counter].bytes_to_transfer; /* loop through each buffer to check the contents on each byte */ for(contents_counter = 0; contents_counter < temp_length; contents_counter++) { temp_receive = IORD_8DIRECT((alt_u32)receive_ptr, contents_counter); chltemp_receive[contents_counter] = temp_receive; chltemp_receive[32] = 0; fprintf(fp, chltemp_receive); } /* Done with these two, time to clean up after ourselves. */ free(receive_ptr); } alt_avalon_sgdma_stop(receive_DMA); free(receive_descriptors_copy); for(k = 0; k < 31; k++) uramres[k] = vldt[k]; uramres[32] = 0; fprintf(fp, uramres); Не понятно почему для того, чтобы запуск sgdma сработал, нужно всякий раз вызывать create_test_data (тоесть alt_avalon_sgdma_construct_stream_to_mem_desc) Пока хочу добиться в простейшем варианте, чтобы sgdma (по каждому вызову alt_avalon_sgdma_do_async_transfer) перебросило в один и тот же буфер 32 16_битных данных. Не получается ...
Сообщение отредактировал Acvarif - Sep 7 2012, 13:29
|
|
|
|
|
Sep 7 2012, 14:15
|
Профессионал
    
Группа: Свой
Сообщений: 1 284
Регистрация: 9-04-06
Пользователь №: 15 968

|
Код не смотрел, но первое что в голову приходит:
Надо считать не импульсы ready, а клоки, при которых ready в единице. Т.е. ready можно выставить в единицу один раз и продержать его в единице 4 клока, при этом каждый клок будут передаваться данные (если конечно valid в единице). Получаем: импульс ready один, а переброшено 4 слова. То же и с valid. Надо формировать не импульсы на valid, а ставить valid в 1 когда данные готовы (при этом смотреть, чтоб ready был в 1. Если вы выставили valid в 1, а ready при этом 0, то в этом цикле данные не перебрасываются в память. Чтоб их перебросить, надо valid держать в 1 до тех пор, пока ready в 1 не встанет).
|
|
|
|
|
Sep 7 2012, 15:47
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(alexPec @ Sep 7 2012, 17:15)  Код не смотрел, но первое что в голову приходит:
Надо считать не импульсы ready, а клоки, при которых ready в единице. Т.е. ready можно выставить в единицу один раз и продержать его в единице 4 клока, при этом каждый клок будут передаваться данные (если конечно valid в единице). Получаем: импульс ready один, а переброшено 4 слова. То же и с valid. Надо формировать не импульсы на valid, а ставить valid в 1 когда данные готовы (при этом смотреть, чтоб ready был в 1. Если вы выставили valid в 1, а ready при этом 0, то в этом цикле данные не перебрасываются в память. Чтоб их перебросить, надо valid держать в 1 до тех пор, пока ready в 1 не встанет). Спасибо. О клоке я совсем забыл. Похоже, что в этом какраз все дело. Судя по диаграмме от SOPC в моем случае 16 бит данных перебрасываются в SDRAM за 1 клок (2 символа шириной 8 бит). Правильно ли я понял?
 РЈРСВВВВеньшено Р В Р’В Р СћРІР‚ВВВР С• 59%
587 x 486 (29.49 килобайт)
|
Очевидно я до конца не уяснил механизм работы sgdma. Все завязано на клоке. Придется переделать свой автомат. Пока так и не понял по поводу ready. Точно видел (по осциллятору), что он устанавливается в 1 по вызову функции alt_avalon_sgdma_do_async_transfer. А вот когда он сбрасывается? После транзакции первого символа (и каждого последующего) или после транзакции 64 символов, или может сроситься во время цикла, если шина будет занята? Получается что в своем автомате я должен при формировании valid учитывать сколько клоков его держать? Сейчас у меня получается, что valid длинный (несколько десятков клоков) и данные не меняются до следующего valid. После того как появился ready появляется valid и держится несколько десятков клоков. Тоесть в этом случае (если ready будет также в 1) по каждому клоку будет транзакция одного и того-же символа, а значит буфер будет забит одним и тем же числом. Так ли это?
Сообщение отредактировал Acvarif - Sep 7 2012, 15:54
|
|
|
|
|
Sep 7 2012, 19:46
|
Профессионал
    
Группа: Свой
Сообщений: 1 284
Регистрация: 9-04-06
Пользователь №: 15 968

|
Цитата Судя по диаграмме от SOPC в моем случае 16 бит данных перебрасываются в SDRAM за 1 клок (2 символа шириной 8 бит). Правильно ли я понял? Ну какой разрядности у вас щина входная sgdma (из сопца наружу, к вашему автомату), столько бит и перебрасывается за 1 клок. Цитата А вот когда он сбрасывается? После транзакции первого символа (и каждого последующего) или после транзакции 64 символов, или может сроситься во время цикла, если шина будет занята? В любое время может уйти в ноль, чтоб освободить шину для выборки кода операции, операндов, данных и т.д. Ведь на той же шине и проц и периферия должна работать пока sgdma данные перебрасывает. Цитата После того как появился ready появляется valid и держится несколько десятков клоков. Тоесть в этом случае (если ready будет также в 1) по каждому клоку будет транзакция одного и того-же символа, а значит буфер будет забит одним и тем же числом. Так ли это? Совершенно верно. Всякий клок, когда valid=1 и ready=1 перебрасывается слово в очередную ячейку(и) памяти. Цитата Получается что в своем автомате я должен при формировании valid учитывать сколько клоков его держать? Я бы сделал так (вернее так и делал): как только у моего автомата готовы данные, выставляю valid=1 и держу его до тех пор, пока ready не будет выставлен в 1. Как только появляется цикл, где на фронте клока valid=1 и ready=1, автомат должен выставить следующие данные, ну или (если след. данные еще не готовы) убрать сигнал valid до тех пор пока автомат не подгонит новое слово. Это для случая, если ваш автомат можно тормознуть на несколько циклов при выдаче данных. Если у автомата выходные данные вываливаются регулярно и задерживать поток нельзя то надо ставить фифо. А из фифы вычитывать по готовности sgdma.
|
|
|
|
|
Sep 11 2012, 07:26
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Спасибо за клок. Сделал все по правилам. Поставил фифо. Valid находится в 1 только на положительном фронте клока. Данные при этом на входе sgdma стабильны.
 РЈРСВВВВеньшено Р В Р’В Р СћРІР‚ВВВР С• 66%
919 x 509 (123.79 килобайт)
|
Система заработала. Перемещает данные из пользовательской двухпортовой памяти в SDRAM. Пока сделал количество буферов 1(#define NUMBER_OF_BUFFERS 1) и длину буфера 16 (#define BUFFER_LENGTH 16) Но всеравно есть непонятности. Не пойму как последняя пара байт оказывается на первом месте?
 РЈРСВВВВеньшено Р В Р’В Р СћРІР‚ВВВР С• 52%
660 x 351 (45.92 килобайт)
|
Все более менее работает пока Код #define NUMBER_OF_BUFFERS 1 #define BUFFER_LENGTH 16 Стоит изменить количество буферов на 2 и более или длину буфера на 64 все останавливается. Похоже, что что-то не так в коде. CODE /* each direction so double this for the total */ #define NUMBER_OF_BUFFERS 2 #define BUFFER_LENGTH 64 alt_u32 buffer_counter = 0, contents_counter = 0, temp_length = BUFFER_LENGTH; alt_u32 * receive_ptr; alt_u8 chltemp_receive[BUFFER_LENGTH];
// Флаг завершения ДМА операции static volatile alt_u8 rx_done = 0;
//--------------------------------------------------------------------------------------------- // Функции
// размещение десрипторов 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 }
// Инициализация alt_sgdma_dev *receive_DMA;
// Открыть SGDMA receive_DMA = alt_avalon_sgdma_open("/dev/sgdma_0"); // alt_sgdma_descriptor дескрипторы alt_sgdma_descriptor *receive_descriptors, *receive_descriptors_copy; alt_u32 return_code;
// размещение дескрипторов return_code = descriptor_allocation(&receive_descriptors, &receive_descriptors_copy, NUMBER_OF_BUFFERS); // определение подпрограммы обработчика прерываний 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);
// Запуск sgdma и получение результата (для теста все в цикле через 1 секу)
while .... .... // старт приема по sgdma
return_code = create_test_data(receive_descriptors, NUMBER_OF_BUFFERS, BUFFER_LENGTH); // запуск SGDMA if(alt_avalon_sgdma_do_async_transfer(receive_DMA, &receive_descriptors[0]) != 0) { return 1; } // ожидание заполнения дискрипторов while(rx_done == 0) {}
// получение результата
/* loop through each descriptor */ for(buffer_counter = 0; buffer_counter < NUMBER_OF_BUFFERS; buffer_counter++) { receive_ptr = receive_descriptors[buffer_counter].write_addr; /* loop through each buffer to check the contents on each byte */ for(contents_counter = 0; contents_counter < temp_length; contents_counter++) { chltemp_receive[contents_counter] = 0; chltemp_receive[contents_counter] = IORD_8DIRECT((alt_u32)receive_ptr, contents_counter); } chltemp_receive[temp_length] = 0; fprintf(fp, chltemp_receive); /* Done with these two, time to clean up after ourselves. */ free(receive_ptr); } alt_avalon_sgdma_stop(receive_DMA); free(receive_descriptors_copy);
.... Просмотрите пожалуйста код. Может, что бросится в глаза, что не так.
Сообщение отредактировал Acvarif - Sep 11 2012, 07:27
|
|
|
|
|
Sep 11 2012, 20:49
|
Профессионал
    
Группа: Свой
Сообщений: 1 284
Регистрация: 9-04-06
Пользователь №: 15 968

|
Цитата Но всеравно есть непонятности. Не пойму как последняя пара байт оказывается на первом месте? Возможно, тот случай о котором я говорил (я с этим тоже боролся). Если при первой транзакции (самой первой) проскакивает (каким-то образом, всякое бывает) 1 лишнее слово, то: - транзакция заканчивается, а в фифо лежит последнее слово - при следующей транзакции сначала считывается из фифо последнее слово предыдущей транзакции (оно встает на первое место), затем слова из текущей транзакции все кроме последнего, поскольку нужное количество dma уже вычитал. И снова в фифо лежит последнее слово уже из текущей транзакции. Сделайте разные данные для разных транзакций и точно увидите или это у вас последнее слово на первом месте у одной транзакции, или это последнее слово предыдущей трнанзакции+ текущая транзакция без последнего слова. Можно еще в сигнал тапе посмотреть, после транзакции пустое у вас фифо или нет. Код пока нет времени смотреть, чуть позже. PS кстати, можете дамп памяти дескрипторов вывести после формирования оных? Что у вас там получается, как дескрипторы сформированы?
|
|
|
|
|
Sep 12 2012, 05:53
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(alexPec @ Sep 11 2012, 23:49)  Возможно, тот случай о котором я говорил (я с этим тоже боролся).
Если при первой транзакции (самой первой) проскакивает (каким-то образом, всякое бывает) 1 лишнее слово, то: - транзакция заканчивается, а в фифо лежит последнее слово - при следующей транзакции сначала считывается из фифо последнее слово предыдущей транзакции (оно встает на первое место), затем слова из текущей транзакции все кроме последнего, поскольку нужное количество dma уже вычитал. И снова в фифо лежит последнее слово уже из текущей транзакции.
Сделайте разные данные для разных транзакций и точно увидите или это у вас последнее слово на первом месте у одной транзакции, или это последнее слово предыдущей трнанзакции+ текущая транзакция без последнего слова. Можно еще в сигнал тапе посмотреть, после транзакции пустое у вас фифо или нет.
Код пока нет времени смотреть, чуть позже.
PS кстати, можете дамп памяти дескрипторов вывести после формирования оных? Что у вас там получается, как дескрипторы сформированы? Спасибо за Ваши подсказки. Похоже это остаток в фифо. Как проверил? Просто выключил питание боарда, включил и запустил все по новой. Все данные стали на свои места. Почему в фифе иногда остается последнее слово пока не понятно. В реальности у меня данные с многоканального фильтра будут вываливаться непрерывно с последующим перебросом их по Ethernet на комп. Допустим буфер = 1400 байт (Утрировано конечно. В реальности я понимаю, что нужно 2 больших буфера. Пока один заполняется с другого идет передача на комп). Когда начнет работать фильтр, пойдут данные через фифо и sgdma в sdram. Заполнится буфер 1400 байт. Я так понимаю, что SGDMA в этом случае остановится? Как запустить следующую транзакцию? Опять вызывать функцию alt_avalon_sgdma_do_async_transfer(...)? Этот момент как-то туманно себе представляю.
|
|
|
|
|
Sep 12 2012, 11:25
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(alexPec @ Sep 12 2012, 09:16)  Ставите функцию-обработчик прерываний на завершение транзакции, в ней меняете буферы, запускаете отправку по эзернету, и запускаете следующую транзакцию. Спасибо. С одним буфером вроде работает. По поводу обработчика При инициализации sgdma вызываю функцию Код 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); В обработчике receive_callback_function(...) я так понимаю нужно полностью переназначить (с другими именами) и переразместить дескрипторы (при каждом вызове обработчика менять их местами)? Только потом опять вызывать alt_avalon_sgdma_do_async_transfer (...) Или как-то по другому?
|
|
|
|
|
Sep 12 2012, 19:29
|
Профессионал
    
Группа: Свой
Сообщений: 1 284
Регистрация: 9-04-06
Пользователь №: 15 968

|
Цитата(Acvarif @ Sep 12 2012, 15:25)  В обработчике receive_callback_function(...) я так понимаю нужно полностью переназначить (с другими именами) и переразместить дескрипторы (при каждом вызове обработчика менять их местами)? Только потом опять вызывать alt_avalon_sgdma_do_async_transfer (...) Или как-то по другому? Да зачем дескрипторы трогать? При инициализации дескрипторов готовите сразу дескриптор под один буфер и дескриптор под другой буфер. По прерыванию просто подсовываете дескриптор другого буфера (уже заранее созданный) и запускаете транзакцию. Времени машинного я думаю это займет не больше чем вход и выход в обработчик прерываний. Сами дескрипторы создаются один раз. Цитата Большое Спасибо alexPec за поддержку. Чем смог...  Всегда пожалуйста
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|