Цитата(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_битных данных. Не получается ...