Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: SG-DMA в режиме Stream To Memoy
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Системы на ПЛИС - System on a Programmable Chip (SoPC)
Страницы: 1, 2
Acvarif
Есть необходимость перегружать кучу байт из пользовательской двухпортовой памяти в SDRAM+NIOS. Для этой цели в пользовательсой логике имеются импульсы периодом ~ 100 нс по фронтам которых предполагается организовать пересылку данных (16 бит) в SDRAM. Далее все компонуется и по Ethernet должно идти далее в комп.
Для этого попытался сворганить в SOPC SG-DMA (Stream To Memory) + Avalon Straming Source. Получил непонятные ошибки. Разрядность нин в SG-DMA и Avalon Straming Source поставил 16 бит.
Нажмите для просмотра прикрепленного файлаНажмите для просмотра прикрепленного файлаНажмите для просмотра прикрепленного файлаНажмите для просмотра прикрепленного файла
Подскажите пожалуйста как правильно. Пробовал по разному (менял оличество бит источника приемника и др.) Не получается. Помог бы простой пример реализации в SOPC подобной схемы.
Нужен ли для этой цели еще и FIFO? Или можно будет обойтись только Avalon Straming Source+пользовательская логика полагаясь на внутреннюю FIFO SG-DMA?
barabek
Прошу прощенья, немного не в тему. А Вам точно нужемн SGdma? Может можно обойтись просто DMA? Ресурсов тратится значительно меньше. И проще в освоении. Не знаю, какая у Вас пользовательская логика, но иногда можно вообще пойти своим путем и сделать свой dma модуль. Например как-то делал для UART, чтобы он писал в кольцевой буфер. Пишется нараз. Не стал в Вашуих картинках разбираться, но непонятно пока как вяжется двухпортовая память со stream? Память вроде как чистая MamoryMap.
Acvarif
Цитата(barabek @ Aug 27 2012, 01:48) *
Прошу прощенья, немного не в тему. А Вам точно нужемн SGdma? Может можно обойтись просто DMA? Ресурсов тратится значительно меньше. И проще в освоении. Не знаю, какая у Вас пользовательская логика, но иногда можно вообще пойти своим путем и сделать свой dma модуль. Например как-то делал для UART, чтобы он писал в кольцевой буфер. Пишется нараз. Не стал в Вашуих картинках разбираться, но непонятно пока как вяжется двухпортовая память со stream? Память вроде как чистая MamoryMap.

Наверное все же SG-DMA. Она в свою очередь подключается либо непосредственно к стрим источнику либо к нему же через fifo буфер. Все это нужно для перегрузки результатов работы (данные идут потоком через двухпортовую RAM) многоканального фильтра в комп посредством Ethernet. На один порт RAM поступают данные с фильтра, а другой порт подключен к стрим источнику. Стрим источник подан на sg-dma. SG-DMA в свою очередь должно загружать данные в SDRAM. Далее уже работает процессор. В SOPC вроде сделал систему. Но в ней много неясностей.
Нажмите для просмотра прикрепленного файла
В частности пока не четко не представляю как выполнить диаграмму стрим источника
Нажмите для просмотра прикрепленного файла
У меня данные с выхода двухпортовой памяти 16 бит. Очевидно по фронту сигнала Valid данные должны появиться на data, а далее сигнал Ready заберет их в SDRAM. Не понятно пока с разрядностью. Как в нескольких словах описать работу этой диаграммы? Почему в ней данные разбиты на 8 бит?
ISK
Цитата(Acvarif @ Aug 27 2012, 12:23) *
У меня данные с выхода двухпортовой памяти 16 бит. Очевидно по фронту сигнала Valid данные должны появиться на data, а далее сигнал Ready заберет их в SDRAM. Не понятно пока с разрядностью. Как в нескольких словах описать работу этой диаграммы? Почему в ней данные разбиты на 8 бит?


У вас здесь же в настройках шины Data Symbols Width = 8, symbols per beat = 2. Вот и разбиты данные на 8 бит. А вообще-то в Avalon Interface Specifications всё написано.
Acvarif
Цитата(ISK @ Aug 28 2012, 09:11) *
У вас здесь же в настройках шины Data Symbols Width = 8, symbols per beat = 2. Вот и разбиты данные на 8 бит. А вообще-то в Avalon Interface Specifications всё написано.

Сразу немного озадачило то, что в SGDMA Symbols Width всегда только 8 бит. Пришлось Источник подстраивать под эту Data Symbols Width.
По поводу диаграммы:
Как теперь построить автомат передачи данных в SGDMA?
По диаграмме получается, что по фронту valid (который должна формировать моя пользовательская логика) нужно, чтобы все 16 бит данных из RAM появились на data. Я так понимаю, что в свою очередь по фронту сигнала ready (который будет исходить от SGDMA) данные из data будут посредством SGDMA помещены в SDRAM NIOS. Все произойдет за 2 такта clk. При этом непонятно в каком состоянии должны быть линии startofpacket, endofpacket, empty, которые опять же должна формировать пользовательская логика?
alexPec
Цитата(Acvarif @ Aug 28 2012, 14:59) *
Сразу немного озадачило то, что в SGDMA Symbols Width всегда только 8 бит. Пришлось Источник подстраивать под эту Data Symbols Width.
По поводу диаграммы:
Как теперь построить автомат передачи данных в SGDMA?
По диаграмме получается, что по фронту valid (который должна формировать моя пользовательская логика) нужно, чтобы все 16 бит данных из RAM появились на data. Я так понимаю, что в свою очередь по фронту сигнала ready (который будет исходить от SGDMA) данные из data будут посредством SGDMA помещены в SDRAM NIOS. Все произойдет за 2 такта clk. При этом непонятно в каком состоянии должны быть линии startofpacket, endofpacket, empty, которые опять же должна формировать пользовательская логика?


Ну наверно не по фронту valid и ready, а при единице на этих сигналах по фронту клока все таки. Там все по фронту клока защелкивается. Была похожая задача - SOP и EOP вообще не использовал, empty - тоже всегда на земле был.
Acvarif
Цитата(alexPec @ Aug 28 2012, 15:09) *
Ну наверно не по фронту valid и ready, а при единице на этих сигналах по фронту клока все таки. Там все по фронту клока защелкивается.

Да, судя по диаграмме - по спаду клока.
Цитата
Была похожая задача - SOP и EOP вообще не использовал, empty - тоже всегда на земле был.

Пробовал создать конфигурацию системы в SOPC без SOP, EOP, empty - не получалось (видно на картинке в самом начале этой темы). В смысле пытался создать компонент Typical Avalom Source без SOP, EOP, empty. Не стыковалось потому, как в SGDMA SOP, EOP, empty никак не отключаются. Или я чего-то недопонял. Как все-же сделать систему без SOP, EOP, empty? Или SOP, EOP, empty просто присутствуют в компоненте Avalom Source но никак не задействуются?
Можно пример из Вашей задачи (SOPC, драйвер..)?
alexPec
Цитата(Acvarif @ Aug 28 2012, 16:31) *
Да, судя по диаграмме - по спаду клока.

Пробовал создать конфигурацию системы в SOPC без SOP, EOP, empty - не получалось (видно на картинке в самом начале этой темы). В смысле пытался создать компонент Typical Avalom Source без SOP, EOP, empty. Не стыковалось потому, как в SGDMA SOP, EOP, empty никак не отключаются. Или я чего-то недопонял. Как все-же сделать систему без SOP, EOP, empty? Или SOP, EOP, empty просто присутствуют в компоненте Avalom Source но никак не задействуются?
Можно пример из Вашей задачи (SOPC, драйвер..)?


У меня проект большой, вытащить кусок проблемно, с отдать целиком права не имею sad.gif. Могу скриншот сделать участка схемы с SGDMA сопца (собстно сделал). Тут фифо снаружи, логика вот была для чего: чтоб прочитать из фифо все наверняка (пакетный режим), то когда заканчивается фифо, все равно генерируется сигнал datavalid, а в программе читаю больше на 2 байта чем длина пакета. Даже если в одном пакете потерялся (или образовался каким-то чудом) один байт - синхронизация поставщика данных и считывателя данных не сбивалась. Сумбурно, но этот узел родился в муках, без него иногда(очень редко) начиналось такое: первый байт - старого пакета, затем новый пакет без последнего байта. И так пока ресет не дернешь. Долго поймать не мог этот момент, потом плюнул, сделал так и все ок. Код инициализации тоже прицепляю.

Инициализация:
Код
adc_dma=adc_dma_init (
      "/dev/sgdma_0",            // char* sgdma_name
      580,/*1106-для qam, 60000 - для ацп*/                       // int width
      1,                      // int height
      8,                  // int color_depth
      -1,          // int buffer_location (malloc buffers)
      -1,          // int descriptor_location (malloc descriptors)
      4,
      (alt_avalon_sgdma_callback)&qam_recive_int); //4-для qam, 1-для ацп   // int num_buffer

И сама процедура инита:
Код
alt_video_display* adc_dma_init( char* sgdma_name,
                                           int width,
                                           int height,
                                           int color_depth,
                                           int buffer_location,
                                           int descriptor_location,
                                           int num_buffers,
                                           alt_avalon_sgdma_callback callbck)//////////////290811
{
  alt_video_display* display;
  unsigned int bytes_per_pixel, bytes_per_frame, descriptors_per_frame, i;
  int result;

  // We'll need these values more than once, so let's pre-calculate them.
  bytes_per_pixel = color_depth >> 3; // same as /8
  bytes_per_frame = (( width * height ) * bytes_per_pixel );

  // Calculate the number of descriptors needed for each frame
  if( bytes_per_frame <= ALT_VIDEO_DISPLAY_BYTES_PER_DESC ) {
    descriptors_per_frame = 1;
  }
  else if(( bytes_per_frame % ALT_VIDEO_DISPLAY_BYTES_PER_DESC) == 0) {
    descriptors_per_frame = bytes_per_frame / ALT_VIDEO_DISPLAY_BYTES_PER_DESC;
  }
  else {
    descriptors_per_frame =
      ( bytes_per_frame / ALT_VIDEO_DISPLAY_BYTES_PER_DESC ) + 1;
  }

  // Check for too many frame buffers
  if( num_buffers > ALT_VIDEO_DISPLAY_MAX_BUFFERS ) {
      num_buffers = ALT_VIDEO_DISPLAY_MAX_BUFFERS;
  }

  // Allocate our display struct
  display = (alt_video_display*) malloc(sizeof(alt_video_display));
  if(!display) {
    return NULL;
  }

  // Fill out the display structure
  display->width = width;
  display->height = height;
  display->color_depth = color_depth;
  display->num_frame_buffers = num_buffers;
  display->bytes_per_frame = bytes_per_frame;
  display->bytes_per_pixel = bytes_per_pixel;
  display->buffer_being_displayed = 0;
  display->buffer_being_written = (num_buffers > 1) ? 1:0;
  display->descriptors_per_frame = descriptors_per_frame;

  // Allocate our frame and descriptor buffers
  if(alt_video_display_allocate_buffers( display,
                                         bytes_per_frame,
                                         buffer_location,
                                         descriptor_location,
                                         num_buffers ) ) {
    return NULL;
  }

  // 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
  }

  // Clear all frame buffers to black
  for( i = 0; i < num_buffers; i++ ) {
    memset( (void*)(display->buffer_ptrs[i]->buffer),
      0, display->bytes_per_frame );
  }

  // Open the SGDMA
  display->sgdma = alt_avalon_sgdma_open(sgdma_name);
  if(!display->sgdma) {
    return NULL;
  }



  /////////////////////290811//////////////////////////
  alt_avalon_sgdma_register_callback(
          display->sgdma,
         callbck,
         (alt_u16)ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK|ALTERA_AVALON_SGDMA_CONTROL_IE_CHA
IN_COMPLETED_MSK,
         (void*)(display));

  /////////////////////////////////////////////////////


  /* Enable SGDMA "parking" mode */
  IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_0_BASE,
    ALTERA_AVALON_SGDMA_CONTROL_PARK_MSK);

  /* Now start the SGDMA */
  result = alt_avalon_sgdma_do_async_transfer(
    display->sgdma,
    display->buffer_ptrs[display->buffer_being_displayed]->desc_base);

  if(result) {
    return NULL;
  }

  return ( display );
}


Рестарт(запуск чтения нового пакета:
Код
unsigned char adc_dma_restart(alt_video_display *display)
{
//    while (IORD_ALTERA_AVALON_SGDMA_STATUS(display->sgdma->base) & ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK);
      /* Enable SGDMA "parking" mode */
    if (!(IORD_ALTERA_AVALON_SGDMA_STATUS(display->sgdma->base) & ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK))
    IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_0_BASE,
        ALTERA_AVALON_SGDMA_CONTROL_PARK_MSK);

      /* Now start the SGDMA */
return(      alt_avalon_sgdma_do_async_transfer(
        display->sgdma,
        display->buffer_ptrs[display->buffer_being_displayed]->desc_base));
}


За базу взят а инициализация дисплея из сэмплов альтеры, может еще чего допилил - точно не помню...
Acvarif
Спасибо.
Попробую разобраться.
Acvarif
Собрал систему с SGDMA, но без FIFO в надежде на внутренее FIFO SGDMA
Нажмите для просмотра прикрепленного файла Нажмите для просмотра прикрепленного файла
Для теста сформировал данные которые появляются на aso_out0_data при появлении фронта на aso_out0_valid
Нажмите для просмотра прикрепленного файла
Я так понимаю что сигналы aso_out0_startofpacket, aso_out0_endofpacket, aso_out0_empty можно вообще не задействовать.
Но совсем не понятна роль сигнала aso_out0_ready
Полагал, что он нужен со стороны SGDMA для переброски подготовленных данных из пользовательской прамяти на aso_out0_data.
Но в моем случае данные из пользовательской памяти и без того уже присутствуют на aso_out0_data по каждому фронту aso_out0_valid тесть на входе SGDMA. Какая же теперь роль сигнала aso_out0_ready который поступает из SGDMA на пользовательскую логику с памятью?
alexPec

В мануале же все написано. Реди - это сигнал готовности SGDMA принять данные. Т.е. если внутренняя шина, например, занята процессором в настоящий момент, то контроллер говорит этим сигналом что не может принять данные.
Acvarif
Цитата(alexPec @ Sep 3 2012, 08:56) *
В мануале же все написано. Реди - это сигнал готовности SGDMA принять данные. Т.е. если внутренняя шина, например, занята процессором в настоящий момент, то контроллер говорит этим сигналом что не может принять данные.

Спасибо. Понятно.
Значит механизм примерно такой: Из пользовательской логики на шину (на SGDMA) поступает сигнал valid который сообщает о том что данные готовы поступить на шину. Далее пользовательская логика ждет от SGDMA сигнала ready (сообщает пользовательсой логике, что шина готова принять данные). По приходу ready пользовательская логика выставляет данные на data , которые по клоку будут посредством SGDMA переброшены в SDRAM.
Ситуация такая, что я должен каждый последующий valid выставлять не раньше чем получу очередной ready.
Поскольку у меня каждый последующий valid отстоит от предыдущего примерно на 100 нс и я не жду ready то вполне может быть ситуация когда SGDMA какие-то данные может пропускать. Так ли это? Или 100 нс для SGDMA это вполне приемлимо?
ISK
Цитата
По приходу ready пользовательская логика выставляет данные на data , которые по клоку будут посредством SGDMA переброшены в SDRAM.


Данные должны подаваться на шину вместе с сигналом "Valid". По приходу "Ready" вы можете выставить на шину новые данные или снять сигнал "Valid". Все сигналы тактируются передним фронтом clk.

Цитата
Поскольку у меня каждый последующий valid отстоит от предыдущего примерно на 100 нс и я не жду ready то вполне может быть ситуация когда SGDMA какие-то данные может пропускать. Так ли это? Или 100 нс для SGDMA это вполне приемлимо?


Никакой гарантии здесь скорее всего нет. Всё зависит от построения системы, тактовой частоты, загруженности шины и т.д.. Лучше, на мой взгляд, использовать дополнительный фифо.
alexPec
Если есть фифо - то 100нс конечно не проблема ( при тактовой, например >40MHz). Если переполнится фифо - то тут бороться либо увеличением тактовой, либо увеличением фифо (при пакетном режиме). В случае сплошного потока увеличение фифо не поможет.
Если нет фифо - тогда нет гарантии что через каждые 100 нс шина будет свободна
Acvarif
Цитата
Данные должны подаваться на шину вместе с сигналом "Valid". По приходу "Ready" вы можете выставить на шину новые данные или снять сигнал "Valid". Все сигналы тактируются передним фронтом clk.

Теперь понял. Спасибо. Значит ready совсем не лишний. Для надежности его нужно все же использовать в автомате который готовит данные для sgdma.
Цитата
Если есть фифо - то 100нс конечно не проблема ( при тактовой, например >40MHz). Если переполнится фифо - то тут бороться либо увеличением тактовой, либо увеличением фифо (при пакетном режиме). В случае сплошного потока увеличение фифо не поможет.
Если нет фифо - тогда нет гарантии что через каждые 100 нс шина будет свободна

Да, спасибо. Добавлю фифо.

Инициализация почему-то не работает (пишет Failed to open receive channel)
CODE
// Размер буфера
#define BUFFER_SIZE 1168
int i;

alt_dma_rxchan rxchan;

unsigned char *rx_buffer = (void*)BUFFER_SIZE;

// обнуление приемника
for(i = 0; i < BUFFER_SIZE; i++)
{
rx_buffer[i] = 0;
}


/* Create the receive channel */
if ((rxchan = alt_dma_rxchan_open("/dev/sgdma_0")) == NULL)
{
printf ("Failed to open receive channel\n");
}
else printf ("Open receive channel.. success\n");
alt_dma_rxchan_ioctl(rxchan, ALT_DMA_SET_MODE_8, 0);

Кому не сложно ответить, еще вопрос. Как сообщения типа printf ("Failed to open receive channel\n"); выводить не на реальный UART, а на консоль NIOs II IDE?
Acvarif
Виноват. Ошибка вышла. Попутал 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.
Пока так и не врубился в последовательность операций для одной транзакции по заполнению буфера.
Как все происходит в нескольких словах? Что делать когда буфер заполнен? Куда помещать следующий пакет с данными?
Ответьте пожалуйста кому не лень.
alexPec
Штатными функциями все делается. (с небольшим допиливанием)

Код
// 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 стает неактивен.
Acvarif
Спасибо.

У Вас в коде несколько дисрипторов, тоесть несколько буферов. (Если я правильно все понял)
Для того, чтобы все хорошо понять пытаюсь написать небольшой код пока только с одним дискриптором. 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. Опять начнется транзакция? Если да то куда?
alexPec
Цитата(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 - там и про дескрипторы, и про регистры, и функции для создания дескрипторов, и запуск транзакций - все есть.



Acvarif
Цитата(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_битных данных. Не получается ...
alexPec
Код не смотрел, но первое что в голову приходит:

Надо считать не импульсы ready, а клоки, при которых ready в единице. Т.е. ready можно выставить в единицу один раз и продержать его в единице 4 клока, при этом каждый клок будут передаваться данные (если конечно valid в единице). Получаем: импульс ready один, а переброшено 4 слова. То же и с valid. Надо формировать не импульсы на valid, а ставить valid в 1 когда данные готовы (при этом смотреть, чтоб ready был в 1. Если вы выставили valid в 1, а ready при этом 0, то в этом цикле данные не перебрасываются в память. Чтоб их перебросить, надо valid держать в 1 до тех пор, пока ready в 1 не встанет).
Acvarif
Цитата(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 бит). Правильно ли я понял?
Нажмите для просмотра прикрепленного файла
Очевидно я до конца не уяснил механизм работы sgdma. Все завязано на клоке.
Придется переделать свой автомат.
Пока так и не понял по поводу ready. Точно видел (по осциллятору), что он устанавливается в 1 по вызову функции alt_avalon_sgdma_do_async_transfer. А вот когда он сбрасывается? После транзакции первого символа (и каждого последующего) или после транзакции 64 символов, или может сроситься во время цикла, если шина будет занята?
Получается что в своем автомате я должен при формировании valid учитывать сколько клоков его держать?

Сейчас у меня получается, что valid длинный (несколько десятков клоков) и данные не меняются до следующего valid. После того как появился ready появляется valid и держится несколько десятков клоков. Тоесть в этом случае (если ready будет также в 1) по каждому клоку будет транзакция одного и того-же символа, а значит буфер будет забит одним и тем же числом.
Так ли это?
alexPec

Цитата
Судя по диаграмме от 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.
Acvarif
Спасибо за клок.
Сделал все по правилам. Поставил фифо. Valid находится в 1 только на положительном фронте клока. Данные при этом на входе sgdma стабильны.
Нажмите для просмотра прикрепленного файла
Система заработала. Перемещает данные из пользовательской двухпортовой памяти в SDRAM. Пока сделал количество буферов 1(#define NUMBER_OF_BUFFERS 1) и длину буфера 16 (#define BUFFER_LENGTH 16)
Но всеравно есть непонятности. Не пойму как последняя пара байт оказывается на первом месте?
Нажмите для просмотра прикрепленного файла
Все более менее работает пока
Код
#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);

....

Просмотрите пожалуйста код. Может, что бросится в глаза, что не так.
alexPec
Цитата
Но всеравно есть непонятности. Не пойму как последняя пара байт оказывается на первом месте?


Возможно, тот случай о котором я говорил (я с этим тоже боролся).

Если при первой транзакции (самой первой) проскакивает (каким-то образом, всякое бывает) 1 лишнее слово, то:
- транзакция заканчивается, а в фифо лежит последнее слово
- при следующей транзакции сначала считывается из фифо последнее слово предыдущей транзакции (оно встает на первое место), затем слова из текущей транзакции все кроме последнего, поскольку нужное количество dma уже вычитал. И снова в фифо лежит последнее слово уже из текущей транзакции.

Сделайте разные данные для разных транзакций и точно увидите или это у вас последнее слово на первом месте у одной транзакции, или это последнее слово предыдущей трнанзакции+ текущая транзакция без последнего слова.
Можно еще в сигнал тапе посмотреть, после транзакции пустое у вас фифо или нет.

Код пока нет времени смотреть, чуть позже.

PS кстати, можете дамп памяти дескрипторов вывести после формирования оных? Что у вас там получается, как дескрипторы сформированы?
Acvarif
Цитата(alexPec @ Sep 11 2012, 23:49) *
Возможно, тот случай о котором я говорил (я с этим тоже боролся).

Если при первой транзакции (самой первой) проскакивает (каким-то образом, всякое бывает) 1 лишнее слово, то:
- транзакция заканчивается, а в фифо лежит последнее слово
- при следующей транзакции сначала считывается из фифо последнее слово предыдущей транзакции (оно встает на первое место), затем слова из текущей транзакции все кроме последнего, поскольку нужное количество dma уже вычитал. И снова в фифо лежит последнее слово уже из текущей транзакции.

Сделайте разные данные для разных транзакций и точно увидите или это у вас последнее слово на первом месте у одной транзакции, или это последнее слово предыдущей трнанзакции+ текущая транзакция без последнего слова.
Можно еще в сигнал тапе посмотреть, после транзакции пустое у вас фифо или нет.

Код пока нет времени смотреть, чуть позже.

PS кстати, можете дамп памяти дескрипторов вывести после формирования оных? Что у вас там получается, как дескрипторы сформированы?


Спасибо за Ваши подсказки. Похоже это остаток в фифо.
Как проверил? Просто выключил питание боарда, включил и запустил все по новой. Все данные стали на свои места. Почему в фифе иногда остается последнее слово пока не понятно.

В реальности у меня данные с многоканального фильтра будут вываливаться непрерывно с последующим перебросом их по Ethernet на комп.
Допустим буфер = 1400 байт (Утрировано конечно. В реальности я понимаю, что нужно 2 больших буфера. Пока один заполняется с другого идет передача на комп).
Когда начнет работать фильтр, пойдут данные через фифо и sgdma в sdram. Заполнится буфер 1400 байт. Я так понимаю, что SGDMA в этом случае остановится? Как запустить следующую транзакцию? Опять вызывать функцию alt_avalon_sgdma_do_async_transfer(...)? Этот момент как-то туманно себе представляю.
alexPec
Цитата(Acvarif @ Sep 12 2012, 09:53) *
Спасибо за Ваши подсказки. Похоже это остаток в фифо.
Как проверил? Просто выключил питание боарда, включил и запустил все по новой. Все данные стали на свои места. Почему в фифе иногда остается последнее слово пока не понятно.

В реальности у меня данные с многоканального фильтра будут вываливаться непрерывно с последующим перебросом их по Ethernet на комп.
Допустим буфер = 1400 байт (Утрировано конечно. В реальности я понимаю, что нужно 2 больших буфера. Пока один заполняется с другого идет передача на комп).
Когда начнет работать фильтр, пойдут данные через фифо и sgdma в sdram. Заполнится буфер 1400 байт. Я так понимаю, что SGDMA в этом случае остановится? Как запустить следующую транзакцию? Опять вызывать функцию alt_avalon_sgdma_do_async_transfer(...)? Этот момент как-то туманно себе представляю.

Ставите функцию-обработчик прерываний на завершение транзакции, в ней меняете буферы, запускаете отправку по эзернету, и запускаете следующую транзакцию.
Acvarif
Цитата(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 (...) Или как-то по другому?
Acvarif
Большое Спасибо alexPec за поддержку.
Заработало на двух буферах (по 64 байта).
Еще попробую на больших буферах в паре с Ethernet.
Если не появятся новые непонятности и все заработает добавлю в эту ветку конфигурацию системы с кодом.
Может кому пригодится.
alexPec
Цитата(Acvarif @ Sep 12 2012, 15:25) *
В обработчике receive_callback_function(...) я так понимаю нужно полностью переназначить (с другими именами) и переразместить дескрипторы
(при каждом вызове обработчика менять их местами)? Только потом опять вызывать alt_avalon_sgdma_do_async_transfer (...) Или как-то по другому?

Да зачем дескрипторы трогать? При инициализации дескрипторов готовите сразу дескриптор под один буфер и дескриптор под другой буфер. По прерыванию просто подсовываете дескриптор другого буфера (уже заранее созданный) и запускаете транзакцию. Времени машинного я думаю это займет не больше чем вход и выход в обработчик прерываний. Сами дескрипторы создаются один раз.

Цитата
Большое Спасибо alexPec за поддержку.


Чем смог... sm.gif Всегда пожалуйста
Acvarif
Выкладываю то, что получилось и вроде работает. Может кому пригодится. Хотя всеравно остались некоторые вопросы. Для того, чтобы быстро перебросить данные из пользовательской логики в память (например в SDRAM NIOS) вполне подошла sgdma. Спасибо alexPec, подсказал, что переброс данных осуществляется по фронту клока на котором работает sgdma. При этом должны быть в 1 сигналы ready (со стороны sgdma) и valid (со стороны пользовательской логики). Для проверки был создан небольшой модуль, типа источник на пользовательской логике который формирует по сигналу из программы Nios 18 пачек с 32 битными данными (vhdl код (работает) писан на скору руку в аттаче) Нажмите для просмотра прикрепленного файла. Конфигурация системы та же, что и ранее, только добавлен фифо. Ниже основные моменты программного кода.
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
Когда все же возникает прерывание? После транзакции последнего байта(слова... др.) в текущий буфер?
alexPec

Цитата
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 - запрещает все/разрешает разрешенные

В доке все это есть, можно подробней посмотреть...
Acvarif
Цитата(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 байт из пользовательской логики?
alexPec
Цитата(Acvarif @ Sep 19 2012, 21:29) *
Но Ethernet сниффер фиксирует повторяющиеся пакеты. Похоже нужно будет поглубже разобраться с Ethernet.


Ну так сформируйте в дополнительный байтик в пакете - номер пакета. Пусть он по кругу крутится. Если будет повторяющийся с точностью до байта - то значит повторяется передача одного и того же пакета, а если номер отличается на 2 (или через сколько вы там повторяете) то значит есть пропуски пакетов. Дальше уже и думать.

Цитата
Не ясно пока до конца по поводу прерывания и количества буферов.
В данном случае цепочка состоит из 4_х буферов ...


Зачем вам цепочка из 4 буферов? Одного ведь должно хватать, 5 раз в сек. такие пакетики отправлять... Цепочку есть смысл делать (опять же мое мнение) если:
1. Большой размер пакета (больше 0xff00) - тут даже необходимо
2. Если у вас неравномерная обработка (по времени) от пакета к пакету или неравномерная передача пакетов (от источника), т.е. если за время обработки одного пакета может прийти 2 и более.

Прерывание у вас правильно, по концу цепочки, но тогда надо делать 2 цепочки.
Сейчас у вас заполнилась цепочка дескрипторов (4 пакета) - вы начинаете ее обрабатывать, а прием пакетов не ведется. Только когда обработаете, запускаете прием пакетов (иначе рискуете потерять пакеты).

Я делал так:
- формируем 2 цепочки.
-принимаем первую цепочку, в это время обрабатываем вторую.
-чтоб все было правильно, обработка завершается (должна) до заполнения первой цепочки,затем выходим из прерывания.
-ждем (или че-то делаем) где-то в основной программе до возникновения прерывания завершения цепочки
-в процедуре обработки прерывания ПЕРВЫМ ДЕЛОМ запускаем DMA приема второй цепочки
-принимаем вторую, в это время обрабатываем первую цепочку. И так с начала.

В этом случае более рационально используется время процессора и шина, поскольку ОДНОВРЕМЕННО ведется и обработка, и заполнение буфера.
Acvarif
Цитата(alexPec @ Sep 19 2012, 22:27) *
Ну так сформируйте в дополнительный байтик в пакете - номер пакета. Пусть он по кругу крутится. Если будет повторяющийся с точностью до байта - то значит повторяется передача одного и того же пакета, а если номер отличается на 2 (или через сколько вы там повторяете) то значит есть пропуски пакетов. Дальше уже и думать.

Спасибо. Вы как в воду глядели.
Действительно имеют место пропуски пакетов. Надо будет разбираться.
Цитата
Зачем вам цепочка из 4 буферов? Одного ведь должно хватать, 5 раз в сек. такие пакетики отправлять... Цепочку есть смысл делать (опять же мое мнение) если:
1. Большой размер пакета (больше 0xff00) - тут даже необходимо
2. Если у вас неравномерная обработка (по времени) от пакета к пакету или неравномерная передача пакетов (от источника), т.е. если за время обработки одного пакета может прийти 2 и более.

Это я ради теста сделал так медленно и мало. В реальности пакеты из 48 слов (96 байт) будут идти через каждые 8 мкс непрерывно.
Цитата
Я делал так:
- формируем 2 цепочки.
-принимаем первую цепочку, в это время обрабатываем вторую.
-чтоб все было правильно, обработка завершается (должна) до заполнения первой цепочки,затем выходим из прерывания.
-ждем (или че-то делаем) где-то в основной программе до возникновения прерывания завершения цепочки
-в процедуре обработки прерывания ПЕРВЫМ ДЕЛОМ запускаем DMA приема второй цепочки
-принимаем вторую, в это время обрабатываем первую цепочку. И так с начала.

В этом случае более рационально используется время процессора и шина, поскольку ОДНОВРЕМЕННО ведется и обработка, и заполнение буфера.

Спасибо. Уяснил. В прерывании запускаю новую транзакцию, а то, что имеется в предыдущем буфере выдаю по Ethernet. Выдать должен успеть до окончания текущей транзакции, тоесть до следующего прерывания.
Судя по проведенному тесту sgdma работает правильно. Буфера меняются как положено. Транзакции идут без сбоев.
Теперь придется копать Ethernet... А не может сниффер (Wireshark) пропускать пакеты? Маловероятно...
alexPec
Цитата(Acvarif @ Sep 20 2012, 10:40) *
Теперь придется копать Ethernet... А не может сниффер (Wireshark) пропускать пакеты? Маловероятно...


Я бы сниферам не сильно доверял. Может комп не успевать, кривость снифера и т.д. Я бы простенькое приложение сделал, которое ловит пакеты на другом компе (куда отправляет ваш девайс) и проверяет номер, если пропуск - вываливает окошко с сообщением - делов на час.
Acvarif
Цитата(alexPec @ Sep 21 2012, 14:39) *
Я бы сниферам не сильно доверял. Может комп не успевать, кривость снифера и т.д. Я бы простенькое приложение сделал, которое ловит пакеты на другом компе (куда отправляет ваш девайс) и проверяет номер, если пропуск - вываливает окошко с сообщением - делов на час.

Да, Вы правы. Сниффер пропускает.
Путем разных манипуляций удается его заставить работать без пропусков.
Но в конечном итоге всеравно придется приложение делать.
С приемом сырых пакетов (в Windows) вроде библиотека WinPcap справляется. И подключить ее удается только в Visual C. A у нас в основном Builder в ходу.
Посоветуйте пожалуйста, может какой другой путь имеется.
alexPec
Цитата(Acvarif @ Sep 21 2012, 17:48) *
Да, Вы правы. Сниффер пропускает.
Путем разных манипуляций удается его заставить работать без пропусков.
Но в конечном итоге всеравно придется приложение делать.
С приемом сырых пакетов (в Windows) вроде библиотека WinPcap справляется. И подключить ее удается только в Visual C. A у нас в основном Builder в ходу.
Посоветуйте пожалуйста, может какой другой путь имеется.


Я в LabView делаю простенькие вещи (или не критичные к рил-тайму) - графическое программирование, все библиотеки для Ethernet есть для TCP, UDP, может еще что-то есть, я не пользовал. Если работали - такой софт написать там 15 минут. Ну если побыстрей надо - Visual Studio (С++).
Acvarif
При наращивании количества данных поступающих на 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 перечитывал. Вроде все должно работать.
Похоже происходит чехарда с битами регистра управления. Но что конкретно не пойму...

alexPec
Регистр статуса и контрола в каком состоянии после зависания? ошибки не возникает (бит ошибки должен быть установлен)? Если прерывания по ошибке нет, то дма остановливается, прерывания не возникает и дальше прерываний уже не будет

Кстати, как виснет-то? Проц встает или прерываний просто нет?
Acvarif
Цитата(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.
alexPec
А покажите дамп сформированных дескрипторов
Acvarif
Цитата(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
С дампом (как вывести на консоль) так и не разобрался.
Опять перечитывал букварь по sgdma. Обратил внимание на бит PARK (режим паркинг).
Если бит в 0, то после заполнения цепочки буферов (в моем случае 4 буфера, а значит 4 дескриптора) затем смены и заполнения другой цепочки, повторно эти цепочки уже работать не будут. Для того, чтобы ими воспользоваться снова, нужно установить бит PARK и вызвать функцию пуска транзакции. Или я не правильно все понял?
alexPec
Цитата(Acvarif @ Sep 28 2012, 23:42) *
С дампом (как вывести на консоль) так и не разобрался.
Опять перечитывал букварь по sgdma. Обратил внимание на бит PARK (режим паркинг).
Если бит в 0, то после заполнения цепочки буферов (в моем случае 4 буфера, а значит 4 дескриптора) затем смены и заполнения другой цепочки, повторно эти цепочки уже работать не будут. Для того, чтобы ими воспользоваться снова, нужно установить бит PARK и вызвать функцию пуска транзакции. Или я не правильно все понял?


Дамп - в ниосе window->show view->memory, выбираете адрес начала дескрипторов

Насчет PARK- точно не помню, тоже долго с ним разбирался год назад, но он точно отвечает за повторные запуски, похоже вы правильно поняли.
Acvarif
Цитата(alexPec @ Sep 29 2012, 12:23) *
Дамп - в ниосе window->show view->memory, выбираете адрес начала дескрипторов

Спасибо. С дампом понял.

Поскольку возникает ошибка размещения дескрипторов придется возвратиться назад.
Кажется я не до конца понял про формирование дескрипторов.
У меня в функции размещения (взято из примера alteraviki) имеется
Код
// количество буферов
#define NUMBER_OF_BUFFERS 4
// длина одного буфера
#define BUFFER_LENGTH 1152
// Каждый дескриптор имеет размер в 32 бита
#define ALTERA_AVALON_SGDMA_DESCRIPTOR_SIZE (0x20)
void * temp_ptr_2;
// выделение памяти под дескрипторы = 6 * 32 = 192 бита
temp_ptr_2 = malloc((number_of_buffers + 2) * ALTERA_AVALON_SGDMA_DESCRIPTOR_SIZE);
// инициализация указателя *receive_descriptors_copy - указывает на адрес начала памяти выделенной под дескрипторы
*receive_descriptors_copy = (alt_sgdma_descriptor *)temp_ptr_2;
// инициализация указателя *receive_descriptors - ???
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;
// очистка бита OWNED_BY_HW
receive_descriptors[number_of_buffers]->control = 0;

Подскажите пожалуйста почему память под дескрипторы выделяется на 2 больше чем количество буферов.
Не пойму в какое место будет указывать указатель *receive_descriptors?
alexPec
Написано же :

slide the pointer until 32 byte boundary is found.

Тут выравнивается начало дескриптора по 32-БАЙТНОЙ границе. Видимо SGDMA так надо, об этом в доке написано что так надо выравнивать. Насчет выделяется больше чем надо - не задумывался, наверно как раз запас на выравнивание по границе...
Acvarif
Цитата
Тут выравнивается начало дескриптора по 32-БАЙТНОЙ границе. Видимо SGDMA так надо, об этом в доке написано что так надо выравнивать. Насчет выделяется больше чем надо - не задумывался, наверно как раз запас на выравнивание по границе...
Понял. Спасибо.
В отладчике после размещения дампы памяти дескрипторов
Нажмите для просмотра прикрепленного файла
Нажмите для просмотра прикрепленного файла
Нажмите для просмотра прикрепленного файла
Нажмите для просмотра прикрепленного файла
Нажмите для просмотра прикрепленного файла
Как-то странно что 2_ые дескрипторы имеют один и тот же адрес.
Acvarif
Все работает. С одним буфером.
С двумя буферами не работает. После заполнения одного буфера
Запускается так:
Код
          if (!(IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_0_BASE) & ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK))
            IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_0_BASE, ALTERA_AVALON_SGDMA_CONTROL_PARK_MSK);

          alt_avalon_sgdma_do_async_transfer(receive_DMA, &receive_descriptors1[0]);

После заполнения первого буфера возникает прерывание в котором делается так:
Код
        while (IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_0_BASE) & ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK);
        // Enable SGDMA "parking" mode
        if (!(IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_0_BASE) & ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK))
          IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_0_BASE, ALTERA_AVALON_SGDMA_CONTROL_PARK_MSK);

        alt_avalon_sgdma_do_async_transfer(receive_DMA, &receive_descriptors2[0]);
.....
выдача данных из receive_descriptors1 по Ethernet

Тоесть в прерывании запускается прием данных по receive_descriptors2 и начинается выдача накопленных данных по receive_descriptors1
Вроде все должно работать как задумано. Но реально после входа в прерывание и
вызова функции alt_avalon_sgdma_do_async_transfer(receive_DMA, &receive_descriptors1[0]); буфер не переключается.
Посоветуйте пожалуйста куда копать?
alexPec
Честно говоря, не помню из-за чего, 2 года назад было, но сделал у себя так:
Код
unsigned char adc_dma_restart(alt_video_display *display)
{
//    while (IORD_ALTERA_AVALON_SGDMA_STATUS(display->sgdma->base) & ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK);
      /* Enable SGDMA "parking" mode */
    if (!(IORD_ALTERA_AVALON_SGDMA_STATUS(display->sgdma->base) & ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK))
    IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_0_BASE,
        ALTERA_AVALON_SGDMA_CONTROL_PARK_MSK);

      /* Now start the SGDMA */
return(      alt_avalon_sgdma_do_async_transfer(
        display->sgdma,
        display->buffer_ptrs[display->buffer_being_displayed]->desc_base));
}
Т.е. while закомментил, заменил на условие. Помню, вроде бывало он циклился на while

Перезапускаю в прерывании так:
Код
adc_dma->buffer_being_displayed=dmaindex&0x3;//след. буфер и старт транзакции
  dmaindex++;
  adc_dma_restart(adc_dma);


Вроде все просто без изысков. Работает стабильно, не виснет долго-долго (дольше суток не проверял). 4 буфера, как видно.

А на какой конкретно строчке циклится? Не на while ли? В пошаговом режиме проверте. Уберите для этого оптимизацию кода (в свойствах проекта Nios II Application properties, Optimization level), тогда дебажить будет строго по порядку строчек.
Попробуйте еще вывести в сигнал тап сигналы DMA и проследите, залетает ли в DMA последний байт пакета, меняется ли после последнего байта сигнал ready(софт при этом в пошаговом режиме). Ну а дальше по обстоятельствам...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.