Перейти к содержанию
    

ZYNQ 7000, DMA и Xil_In32, Xil_Out32

Здравствуйте!

Задача: передать в память DDR со счетчика, расположенного в PL, 512 32-разрядных слов (2 пакета по 256 слов), минимально задействовав процессор. Выбрала передачу через ядро DMA + InterConnect.

Режим работы DMA - не Scatter/Gather, а просто через регистры.

Инициализирую DMA так:

    unsigned int tmpVal;
    Xil_Out32( XPAR_PS7_GPIO_0_BASEADDR + (2 * XGPIOPS_DATA_MASK_OFFSET) + XGPIOPS_DATA_LSW_OFFSET, 0xFFFD0000); //reset fifo - reset it
    Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x30, (1<<RESET_DMA)); //start_DMA_control_reg_val);
        while(Xil_In32(XPAR_AXI_DMA_0_BASEADDR + 0x30) & (1<<RESET_DMA)) xil_printf("Reseting DMA...\n");
    tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x30);
    tmpVal |= 0x1001;  //dma unit enable. interrupt on complete enable
    Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x30, tmpVal);
    tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x30);
    xil_printf("value for DMA control reg is %x\n\r",tmpVal);
    Xil_Out32 (XPAR_AXI_DMA_0_BASEADDR + 0x48, addr);

Обработка прерываний от DMA:

        u32 tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x34);
    
***********
        xil_printf("DMA status %x\n",tmpVal);         //I can't understand, but without this line CPU reading the length of written bytes from DMA fails...
***********
        
         if((tmpVal&(1<<ERR_IRQ))||(tmpVal&(1<<4)))   //reset DMA if DMA Internal error
    {
            XGpioPs_WritePin(&my_Gpio, 54, 0);   //Закончить работу счетчика
            tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x30);
            tmpVal &= ~0x1001;  //dma unit disable. interrupt on complete disable
            Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x30, tmpVal);
            xil_printf("DMA stopped! Data weren't accepted! Sorry!\n");
            finished = 2;   //It would be good to stop DMA?
    }
    else
    {
        tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x58);

***********
        xil_printf("tmpVal is %d\n",tmpVal);
***********

        Max_num = Max_num + tmpVal;
        if((Max_num)<MAX_BYTE_NUMBERS)
        {
            addr = addr + tmpVal;
            StartDMATransfer(addr,MAX_BYTE_NUMBERS-Max_num);
        }
        else
        {
                //тут заканчиваем передачу
              XGpioPs_WritePin(&my_Gpio, 54, 0); //Закончить работу счетчика
         }

Если в коде нет строчек, выделенных **************, то передается не вся посылка, а примерно 280-290 слов. Если есть - передается всё. и в режиме Release, и в режиме Debug. DMA ошибок не выдает. Выполняется команда XGpioPs_WritePin(&my_Gpio, 54, 0); //Закончить работу счетчика

раньше того как будут переданы все слова. MAX_BYTE_NUMBERS = 2048.

Объясните пожалуйста, почему??? Шаманство "добавим вывод в uart и все заработает" мне не сильно нравится. Хотелось бы понять, сколько времени нужно на выполнение операции чтения-записи в память, и как обойтись без uart?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В system файле щёлкаете на example напротив dma контроллера и копируете оттуда poll_example. Там несколько строчек кода, заблудиться сложно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В system файле щёлкаете на example напротив dma контроллера и копируете оттуда poll_example. Там несколько строчек кода, заблудиться сложно.

Это не является ответом на мой вопрос. Возможно, это станет решением. Но я, даже после просмотра примера (а мой код создавался изначально на основе этого примера и еще каких-то найденных в сети), я не понимаю, ПОЧЕМУ у меня НОРМАЛЬНО ПЕРЕДАЮТСЯ данные после вставки двух функций вывода строк в uart.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Здравствуйте!

Я не разбираюсь в данном вопросе, но смею предположить, что ошибка может быть локализована не в этом коде.

 

Можете ли вы показать весь код и процессорный и проектный? Возможно это сможет вам помочь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

 

Это не является ответом на мой вопрос. Возможно, это станет решением. Но я, даже после просмотра примера (а мой код создавался изначально на основе этого примера и еще каких-то найденных в сети), я не понимаю, ПОЧЕМУ у меня НОРМАЛЬНО ПЕРЕДАЮТСЯ данные после вставки двух функций вывода строк в uart.
Скорее всего потому что добавляется задержка до момента когда вы останавливаете счетчик или DMA.

Вывод в uart или в printf это довольно медленные функции. Смотрите по какому событию у Вас настроено прерывание DMA.

Может оно срабатывает не на окончание пересылки данных, а например на окончание обработки дескриптора.

 

Удачи! Rob.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

 

Скорее всего потому что добавляется задержка до момента когда вы останавливаете счетчик или DMA.

Вывод в uart или в printf это довольно медленные функции. Смотрите по какому событию у Вас настроено прерывание DMA.

Может оно срабатывает не на окончание пересылки данных, а например на окончание обработки дескриптора.

 

Удачи! Rob.

На окончание работы дескриптора? Ой... А это как?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

 

На окончание работы дескриптора? Ой... А это как?
Сам не знаю :) Это только предположение. Я DMA-шками обычно напрямую в железе рулю а не программно через Zynq.

Поэтому Вам надо внимательно почитать-посмотреть как конфигурируются прерывания. Каков статус DMA в прерывании (какое событие вызывает прерывание) и.т.д.

 

Удачи! Rob.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

 

у dma контроллера только одна фича, которая не даёт завершить обмен - отсутствие tlast.
Нее .. tlast важен для пакетного режима. В этом случае по tlast закрывается текущий дескриптор со счетчиком реально принятых байт. А без tlast должно быть принято то число байт которое в поле len заданно.

 

Удачи! Rob.

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

 

Нее .. tlast важен для пакетного режима. В этом случае по tlast закрывается текущий дескриптор со счетчиком реально принятых байт. А без tlast должно быть принято то число байт которое в поле len заданно.

 

Удачи! Rob.

 

Гляньте форум на xilinx.com, так уже не раз обсуждали, что без tlast нет завершения, но похоже ещё и от версии корки зависит, в vivado 2017.4 точно так, проверял месяц назад.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

Гляньте форум на xilinx.com, так уже не раз обсуждали, что без tlast нет завершения, но похоже ещё и от версии корки зависит, в vivado 2017.4 точно так, проверял месяц назад.

У меня завершается при любом заданном числе байт, если хотя бы один тласт был. И при этом не обязательно в конце. 2017.1 версия. Только вечером этот эффект отловила - на анализаторе еще не смотрела, но похоже на то.

А можно конкретную ссылку на обсуждение на форуме, плиз?

 

Поэтому Вам надо внимательно почитать-посмотреть как конфигурируются прерывания. Каков статус DMA в прерывании (какое событие вызывает прерывание) и.т.д.

Статус - прерывание по завершению приема. Статус регистр содержит 1002 на первом tlast, и 1000 на втором прерывании. Оба числа представлены в десятичной форме .

 

Здравствуйте!

Я не разбираюсь в данном вопросе, но смею предположить, что ошибка может быть локализована не в этом коде.

 

Можете ли вы показать весь код и процессорный и проектный? Возможно это сможет вам помочь.

Здравствуйте!

Дизайн в pdf файле. Настройки: счетчик обнуляется раз в секунду, считает до заданного значения, генерирует два пакета. Когда счетчик обнуляется, вызывается прерывание, внутри которого настраивается на прием dma, очищается fifo, очищается буфер dma, запускается прием слов и передача их в ddr. Буфер работает в режиме packet fifo, но после первых 16 слов по понятным причинам переходит в режим data fifo, то есть по мере поступления новых слов выдвигает уже имевшиеся на линию своего мастера. Синхронизаторы служат исключительно для подключения ILA. Плата zedboard. Тактовый сигнал на порту clk 100 МГц, он по отношению к плис внешний. В clk wizard из этих внешних 100 я делаю 32 МГц. Master fifo, dma, smc тактируются 100 МГц.

2_5463105118117298362.pdf

Изменено пользователем sheynmanyu

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Данные с логического анализатора в файлах *.pdf. Два варианта - когда удалось передать все слова (в обработке прерывания от DMa был включен пустой цикл for, и когда цикл for был закомментирован и в результате были переданы не все слова. Но при этом DMA не ругалось, что не получило второго tlast, что меня совсем удивляет.

Поскольку в pdf не видно - сделала еще архив с файлами *.ila. Разработчики форума! А можно ли разрешить заливку не только картинок и pdf?

Пояснения:

START_STOP: обнуляем счетчик, говорим процессору, что появилась новая партия данных. В моем случае - два длинных пакета по 256 слов в каждом.

ENA_COUNTER меняется с 0 на 1: процессор дает добро, буферы fifo и DMA сброшены, DMA оповещен о том, что ему необходимо принять 2048 байт и находится в ожидании приема.

FIFO_RESET - сброс буфера fifo

FIFO_ - это данные, поступающие от счетчика в fifo (снимала с синхронизаторов, так как сам счетчик и блок, генерирующий старт-сигнал, тактируются от 32 МГц, а все, что идет между DMA и HP-портом - 100 МГц и эти тактовые домены никак не связаны между собой.

Далее подписи соответствуют дизайну - см. предыдущий пост.

Код программы:

Инициализация DMA

int InitializeAXIDma (void)
{
    unsigned int tmpVal;
    Xil_Out32( XPAR_PS7_GPIO_0_BASEADDR + (2 * XGPIOPS_DATA_MASK_OFFSET) + XGPIOPS_DATA_LSW_OFFSET, 0xFFFD0000); //reset fifo buffer. analog XGpioPs_WritePin(&my_Gpio, 54, 0);
    Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x30, (1<<RESET_DMA)); //reset DMA buffer;
        while(Xil_In32(XPAR_AXI_DMA_0_BASEADDR + 0x30) & (1<<RESET_DMA)) 
                xil_printf("Reseting DMA...\n");
    tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x30);
    tmpVal |= 0x1001;  //dma unit enable. interrupt on complete enable
    Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x30, tmpVal);
    Xil_Out32 (XPAR_AXI_DMA_0_BASEADDR + 0x48, addr);  //set start address for DMA

    return 0;
}

Обработка появления старт-сигнала (по возрастающему фронту START_STOP)

 void StartIntrHandler (void)   //I should clear interrupt status!
{

    static int y = 0;
    Xil_Out32( XPAR_PS7_GPIO_0_BASEADDR + (2 * XGPIOPS_DATA_MASK_OFFSET) + XGPIOPS_DATA_LSW_OFFSET, 0xFFFD0002); //enable fifo work after resetting
    Xil_Out32 (XPAR_AXI_DMA_0_BASEADDR + 0x58, MAX_BYTE_NUMBERS); //Start DMA - write down the whole bytes number

    XScuTimer_LoadTimer(&myTmr, XPAR_PS7_CORTEXA9_0_CPU_CLK_FREQ_HZ / 2);
    XScuTimer_EnableAutoReload(&myTmr);
    XScuTimer_Start(&myTmr);

    Xil_Out32( XPAR_PS7_GPIO_0_BASEADDR + (2 * XGPIOPS_DATA_MASK_OFFSET) + XGPIOPS_DATA_LSW_OFFSET, 0xFFFE0001); //enable counter work
        InterruptCounter = 0;
        Max_num = MAX_BYTE_NUMBERS;
    XScuGic_Disable(&InterruptController, START_INTR);
    XScuGic_Disconnect(&InterruptController, START_INTR); //disconnect START_INTR. Не буду обрабатывать прерывания во время передачи данных
    y++;
    xil_printf("Start interrupt! y = %d\n",y);
    xil_printf("finished while start interrupt = %d\n",finished);
}

Ну и обработка DMA прерываний

 void DMA_interrupt (void)
{
    u32 tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x34);   //считываю статус регистр DMA
    if(tmpVal&XAXIDMA_IRQ_ERROR_MASK)//reset DMA if DMA error
    {
            XGpioPs_WritePin(&my_Gpio, 54, 0);
            tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x30);
            tmpVal &= ~0x1001;  //dma unit disable. interrupt on complete disable
            Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x30, tmpVal);
            xil_printf("DMA stopped! Data weren't accepted! Sorry!\n");
            finished = 2;   //It would be good to stop DMA?
            return;
    }
    if(tmpVal&XAXIDMA_IRQ_DELAY_MASK)   //если прерывание вызвано не получением TLAST, а чем-то другим - просто вернемся к ожиданию новых слов. Ни разу не наблюдалось. Счетчик в DMA в моем режиме - register mode - не 
                                                                  //работает. Так что это чисто на всякий случай
    {
        StartDMATransfer(addr,Max_num);
    }

    if(tmpVal&XAXIDMA_IRQ_IOC_MASK)       //если у нас таки окончание приема - получили TLAST или что??? почему можно не принять последний TLAST и сброса DMA все равно не происходит???
    {
        tmpVal =  Xil_In32(XPAR_AXI_DMA_0_BASEADDR + 0x58);  //а сколько байт мы приняли? ожидается ли еще что-то?
        Max_num = Max_num - tmpVal;
        if(Max_num>0)
        {
            addr = addr + tmpVal;
            StartDMATransfer(addr,Max_num);    //Ожидается. Значит, запустим снова DMA на прием
        }
        else
        {
            Xil_Out32( XPAR_PS7_GPIO_0_BASEADDR + (2 * XGPIOPS_DATA_MASK_OFFSET) + XGPIOPS_DATA_LSW_OFFSET, 0xFFFE0000); //остановим счетчик - мы уже все слова получили
            DMA_fail = 0;
                   tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x30);
           finished = 1;   //выставим флаг готовности данных. Теперь процессор может с ними делать все, что захочет 
           tmpVal &= ~0x1001;  //dma unit disable. interrupt on complete disable
                Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x30, tmpVal);
        }
    }

  //  for(int t = 0; t < 600; t++); //так вот без этого самого for принимаются не все слова
}

DMA_good.pdf

DMA_not_good.pdf

ila_data_from_DMA.7z

Изменено пользователем sheynmanyu

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую всех!

Спасибо всем, кто помогал, и особенно airroman! Проблема решена.

В обработчике прерывания от DMA надо было очистить 12 бит в регистре S2MM DMA Status register:

if(tmpVal&XAXIDMA_IRQ_IOC_MASK)
    {
        u32 status_val = (tmpVal|((1<<IOC_IRQ)));    //those 2 lines were really key lines!!!
        Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x34, status_val); //clear interrupt on complete status for DMA
...

Тогда процессор не будет повторно выполнять процедуру обработки прерывания, и DMA сможет дождаться очередного TLAST.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Гость
Эта тема закрыта для публикации ответов.
×
×
  • Создать...