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

Обращение к AXI_DMA приводит к зависанию

Нужно мне гнать поток данных из своей логики через AXI4-Stream. Написал я интерфейсный блок AXI4-Stream, добавил к своей логике, сделал ядро. Подключил к AXI_DMA. Взял драйвер отсюда https://github.com/Xilinx/embeddedsw/blob/m...e_simple_poll.c

Проходит инициализация DMA и виснет проц на строке

XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);

то есть ровно в том месте где идет попытка записи в регистры DMA.

 

Ну думаю - накосячил где-то со своим IP. Нашел пошаговую инструкцию подключения и работы с AXI_DMA

http://www.fpgadeveloper.com/2014/03/using...dma-engine.html

Там и vhdl код ядра взял, там и драйвер взял. Все по инструкции сделал. Снова виснет в ТОМ ЖЕ МЕСТЕ. Если закоментировать запрет прерываний, то виснет на строке

XAxiDma_SimpleTransfer(&AxiDma,(UINTPTR) RxBufferPtr, MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);

то есть опять в том месте где идет запись в DMA.

 

Понимаю что проблема элементарная и кроется в мелочи, но осилить не могу уже несколько дней. Прошу помощи.

 

P.S. Использую ISE 14.5, XPS, SDK.

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

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


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

Продолжим.

 

Описываю по шагам ход пробы работы с DMA.

 

1. Создаю в ISE проект на Zynq XC7Z020 CLG484. Головной файл в schematic. В него добавляю Embedded Processor. Запускается XPS, где я импортирую xml файл тестовой платы HW-Z7-ZC702 (рис.1)

 

2. Создаем своё ядро с названием my_dma(рис.2), интерфейсом AXI4-Stream(рис.3), оставляем размерность без изменений(рис.4), не генерим лишних файлов(рис.5).

 

3. Меняем код в VHDL файле ядра на прикрепленный

 

4. Вставляем наше ядро в процессор (рис.6)

 

5. Вставляем ядро AXI DMA Engine. Снимаем галку со строки Include Scatter Gather Engine (рис. 7). Все остальные параметры по умолчанию. Окончание настройки - добавляем ядро (рис.8)

 

6. Подключаем наше ядро к DMA через AXI4-Stream.(рис.9). Модули axi_intercoonect добавились и подключились автоматически.

Настройки не менял

 

7. Подключаем сигнал ACLK нашего ядра к тому же клоку что используют axi_intercoonect(рис.10)

 

8. Запускаем Generate Netlist

 

9. По окончании генерации возвращаемся в ISE. Вставляем символ проца. Подключаем все его выводы. Компилим проект. Создаем bit файл. Импортируем и запускаем SDK

 

10. В SDK создаем новый Application Project с шаблоном Hello World(рис. 11)

 

11. Копируем в него прикрепленный код

 

12. Грузим плис и запускаем проект(рис.12)

 

13. Получаем неизменное зависание на первой строке запрета прерываний(рис.13)

 

 

14. Еще можно перед запуском Generate Netlist открыть mhs файл проекта и в ручную прописать порт ARESETN нашего ядра(рис. 14), ибо не понятно подключился ли он автоматически (рис. 15).

 

На результат это никак не влияет. Зависание в том же месте.

 

Вопрос тот же. Что я делаю не так? Где ошибка?

 

VHDL Код ядра

 

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity dma_axis is
    port
    (
        -- DO NOT EDIT BELOW THIS LINE ---------------------
        -- Bus protocol ports, do not add or delete.
        ACLK    : in    std_logic;
        ARESETN : in    std_logic;
        S_AXIS_TREADY   : out   std_logic;
        S_AXIS_TDATA    : in    std_logic_vector(31 downto 0);
        S_AXIS_TLAST    : in    std_logic;
        S_AXIS_TVALID   : in    std_logic;
        M_AXIS_TVALID   : out   std_logic;
        M_AXIS_TDATA    : out   std_logic_vector(31 downto 0);
        M_AXIS_TLAST    : out   std_logic;
        M_AXIS_TREADY   : in    std_logic
        -- DO NOT EDIT ABOVE THIS LINE ---------------------
    );

attribute SIGIS : string;
attribute SIGIS of ACLK : signal is "Clk";

end dma_axis;

architecture EXAMPLE of dma_axis is

   -- Total number of input data.
   constant NUMBER_OF_INPUT_WORDS  : natural := 8;

   -- Total number of output data
   constant NUMBER_OF_OUTPUT_WORDS : natural := 8;

   type STATE_TYPE is (Idle, Read_Inputs, Write_Outputs);

   signal state        : STATE_TYPE;

   -- Accumulator to hold sum of inputs read at any point in time
   signal sum          : std_logic_vector(31 downto 0);

   -- Counters to store the number inputs read & outputs written
   signal nr_of_reads  : natural range 0 to NUMBER_OF_INPUT_WORDS - 1;
   signal nr_of_writes : natural range 0 to NUMBER_OF_OUTPUT_WORDS - 1;

   -- TLAST signal
   signal tlast : std_logic;

begin
   -- CAUTION:
   -- The sequence in which data are read in and written out should be
   -- consistent with the sequence they are written and read in the
   -- driver's axi_stream_generator.c file

   -- S_AXIS_TREADY  <= '1'   when state = Read_Inputs   else '0';
   S_AXIS_TREADY  <= '0' when state = Write_Outputs else '1';
   M_AXIS_TVALID <= '1' when state = Write_Outputs else '0';

   M_AXIS_TDATA <= sum;
   M_AXIS_TLAST <= tlast;

   The_SW_accelerator : process (ACLK) is
   begin  -- process The_SW_accelerator
    if ACLK'event and ACLK = '1' then     -- Rising clock edge
      if ARESETN = '0' then               -- Synchronous reset (active low)
        -- CAUTION: make sure your reset polarity is consistent with the
        -- system reset polarity
        state        <= Idle;
        nr_of_reads  <= 0;
        nr_of_writes <= 0;
        sum          <= (others => '0');
        tlast        <= '0';
      else
        case state is
          when Idle =>
            if (S_AXIS_TVALID = '1') then
              state       <= Read_Inputs;
              nr_of_reads <= NUMBER_OF_INPUT_WORDS - 1;
              sum         <= (others => '0');
            end if;

          when Read_Inputs =>
            if (S_AXIS_TVALID = '1') then
              -- Coprocessor function (Adding) happens here
              sum         <= std_logic_vector(unsigned(sum) + unsigned(S_AXIS_TDATA));
              if (S_AXIS_TLAST = '1') then
                state        <= Write_Outputs;
                nr_of_writes <= NUMBER_OF_OUTPUT_WORDS - 1;
              else
                nr_of_reads <= nr_of_reads - 1;
              end if;
            end if;

          when Write_Outputs =>
            if (M_AXIS_TREADY = '1') then
              if (nr_of_writes = 0) then
                state <= Idle;
                tlast <= '0';
              else
                -- assert TLAST on last transmitted word
                if (nr_of_writes = 1) then
                  tlast <= '1';
                end if;
                nr_of_writes <= nr_of_writes - 1;
              end if;
            end if;
        end case;
      end if;
    end if;
   end process The_SW_accelerator;
end architecture EXAMPLE;

 

 

СИ код прикладного проекта

 

#include <stdio.h>
#include "platform.h"
#include "xaxidma.h"
#include "xparameters.h"

/*
* Device hardware build related constants.
*/

#define DMA_DEV_ID        XPAR_AXIDMA_0_DEVICE_ID

//#define MEM_BASE_ADDR        (XPAR_PS7_DDR_0_S_AXI_BASEADDR + 0x1000000)
#define MEM_BASE_ADDR        (XPAR_PS7_DDR_0_S_AXI_BASEADDR + 0x10000000)

#define TX_BUFFER_BASE        (MEM_BASE_ADDR + 0x00100000)
#define RX_BUFFER_BASE        (MEM_BASE_ADDR + 0x00300000)
#define RX_BUFFER_HIGH        (MEM_BASE_ADDR + 0x004FFFFF)

#define MAX_PKT_LEN_WORDS    8
#define MAX_PKT_LEN            MAX_PKT_LEN_WORDS*4

#define TEST_START_VALUE    0xC

#define NUMBER_OF_TRANSFERS    10

/************************** Function Prototypes ******************************/

int XAxiDma_SimplePollExample(u16 DeviceId);
static int CheckData(void);

/************************** Variable Definitions *****************************/
/*
* Device instance definitions
*/
XAxiDma AxiDma;


int main()
{
    int Status;

    init_platform();
    xil_printf("\r\n--- Entering main() --- \r\n");

    /* Run the poll example for simple transfer */
    Status = XAxiDma_SimplePollExample(DMA_DEV_ID);

    if (Status != XST_SUCCESS) {

        xil_printf("XAxiDma_SimplePollExample: Failed\r\n");
        return XST_FAILURE;
    }

    xil_printf("XAxiDma_SimplePollExample: Passed\r\n");

    xil_printf("--- Exiting main() --- \r\n");

    return XST_SUCCESS;
}

/*****************************************************************************/
/**
* The example to do the simple transfer through polling. The constant
* NUMBER_OF_TRANSFERS defines how many times a simple transfer is repeated.
*
* @param    DeviceId is the Device Id of the XAxiDma instance
*
* @return
*        - XST_SUCCESS if example finishes successfully
*        - XST_FAILURE if error occurs
*
* @note        None
*
*
******************************************************************************/
int XAxiDma_SimplePollExample(u16 DeviceId)
{
    XAxiDma_Config *CfgPtr;
    int Status;
    int Tries = NUMBER_OF_TRANSFERS;
    int Index;
    u32 *TxBufferPtr;
    u32 *RxBufferPtr;
    u32 Value;

    TxBufferPtr = (u32 *)TX_BUFFER_BASE;
    RxBufferPtr = (u32 *)RX_BUFFER_BASE;

    /* Initialize the XAxiDma device.
     */
    CfgPtr = XAxiDma_LookupConfig(DeviceId);
    if (!CfgPtr) {
        xil_printf("No config found for %d\r\n", DeviceId);
        return XST_FAILURE;
    }


    Status = XAxiDma_CfgInitialize(&AxiDma, CfgPtr);
    if (Status != XST_SUCCESS) {
        xil_printf("Initialization failed %d\r\n", Status);
        return XST_FAILURE;
    }

    if(XAxiDma_HasSg(&AxiDma)){
        xil_printf("Device configured as SG mode \r\n");
        return XST_FAILURE;
    }

    xil_printf("1");

    /* Disable interrupts, we use polling mode
     */
    XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
                        XAXIDMA_DEVICE_TO_DMA);
    xil_printf("2");
    XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
                        XAXIDMA_DMA_TO_DEVICE);


    Value = 0;

    for(Index = 0; Index < MAX_PKT_LEN_WORDS; Index ++) {
            TxBufferPtr[Index] = Value;
            Value++;
    }
    /* Flush the SrcBuffer before the DMA transfer, in case the Data Cache
     * is enabled
     */
    Xil_DCacheFlushRange((u32)TxBufferPtr, MAX_PKT_LEN);

    for(Index = 0; Index < Tries; Index ++) {


        Status = XAxiDma_SimpleTransfer(&AxiDma,(u32) RxBufferPtr,
                    MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);

        if (Status != XST_SUCCESS) {
            return XST_FAILURE;
        }


        Status = XAxiDma_SimpleTransfer(&AxiDma,(u32) TxBufferPtr,
                    MAX_PKT_LEN, XAXIDMA_DMA_TO_DEVICE);

        if (Status != XST_SUCCESS) {
            return XST_FAILURE;
        }

        while (XAxiDma_Busy(&AxiDma,XAXIDMA_DMA_TO_DEVICE)) {
                /* Wait */
        }
        while (XAxiDma_Busy(&AxiDma,XAXIDMA_DEVICE_TO_DMA)) {
                /* Wait */
        }

        Status = CheckData();
        if (Status != XST_SUCCESS) {
            return XST_FAILURE;
        }

    }

    /* Test finishes successfully
     */
    return XST_SUCCESS;
}



/*****************************************************************************/
/*
*
* This function checks data buffer after the DMA transfer is finished.
*
* @param    None
*
* @return
*        - XST_SUCCESS if validation is successful.
*        - XST_FAILURE otherwise.
*
* @note        None.
*
******************************************************************************/
static int CheckData(void)
{
    u32 *RxPacket;
    int Index = 0;

    RxPacket = (u32 *) RX_BUFFER_BASE;

    /* Invalidate the DestBuffer before receiving the data, in case the
     * Data Cache is enabled
     */
    Xil_DCacheInvalidateRange((u32)RxPacket, MAX_PKT_LEN);

    xil_printf("Data received: ");
    for(Index = 0; Index < MAX_PKT_LEN_WORDS; Index++) {
        xil_printf("0x%X ", (unsigned int)RxPacket[Index]);
    }
    xil_printf("\r\n");

    return XST_SUCCESS;
}

post-57971-1520317385_thumb.jpg

post-57971-1520317398_thumb.jpg

post-57971-1520317425_thumb.jpg

post-57971-1520317575_thumb.jpg

post-57971-1520317580_thumb.jpg

post-57971-1520317584_thumb.jpg

post-57971-1520317589_thumb.jpg

post-57971-1520317594_thumb.jpg

post-57971-1520317600_thumb.jpg

post-57971-1520317604_thumb.jpg

post-57971-1520317609_thumb.jpg

post-57971-1520317613_thumb.jpg

post-57971-1520317618_thumb.jpg

post-57971-1520317622_thumb.jpg

post-57971-1520317626_thumb.jpg

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

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


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

Продолжим. Запустил под отладчиком построчно ассемблерный код. Функция XAxiDma_IntrDisable имеет вид

 

001005f8: movw r3, #32808 ; 0x8028

001005fc: movt r3, #16

00100600: ldr r3, [r3]; считали базовый адрес AXI DMA. Он верный 0х40400000

00100604: add r4, r3, #48 ; 0x30 добавили сдвиг 0х30 на регистр S2MM_DMACR = 0х40400030. Сохранили

00100608: movw r3, #32808 ; 0x8028

0010060c: movt r3, #16

00100610: ldr r3, [r3] считали базовый адрес AXI DMA. Он верный 0х40400000

00100614: add r3, r3, #48 ; 0x30 добавили сдвиг 0х30 на регистр S2MM_DMACR.

00100618: mov r0, r3

0010061c: ldr r0, [r0] считали значение регистра S2MM_DMACR = 0х00010002. Соответствует значению по умолчанию

00100620: mov r3, r0

00100624: bic r3, r3, #28672 ; 0x7000 обнулили 3 бита прерываний

00100628: mov r0, r4 ;записали адрес регистра S2MM_DMACR = 0х40400030

0010062c: mov r1, r3 ;записали все тоже значение по умолчанию 0х00010002

00100630: str r1, [r0] ; запись числа 0х00010002 по адресу 0х40400030 приводит к вылету в прерывание DataAbortInterrupt. Работа проца прекращается. При этом уходит в 0 сигнал DONE плис. Вместе с ним иногда еще сигнал INIT_B меняется.

 

Какие будут версии?

 

Вот еще что добавлю. Дописал кусок кода читающий все регистры управления DMA. Так вот все считанные значения соответствуют значениям по умолчанию из product guide на AXI DMA

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

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


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

 

И еще добавлю. Запись в любой настроечный регистр AXI DMA, того же значения что записано в нем сейчас, приводит к прерыванию DataAbortInterrupt

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


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

И еще добавлю. Запись в любой настроечный регистр AXI DMA, того же значения что записано в нем сейчас, приводит к прерыванию DataAbortInterrupt

Я бы для начала на Chipscope смотрел, что в железе происходит.

И работать на ISE 14.5 с Zynq я бы тоже не стал, больно стар он - хрен знает насколько актуальны используемые там модели этого Zynq.

 

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


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

Я бы для начала на Chipscope смотрел, что в железе происходит.

И работать на ISE 14.5 с Zynq я бы тоже не стал, больно стар он - хрен знает насколько актуальны используемые там модели этого Zynq.

Благодарю. Мне в XPS пользоваться чипскопом не приходилось. Только в ISE использовал.

Моя последовательность действий:

1. В шапке XPS выбираем DEBUG-- >Debug Configurations

2. Жму кнопку Add ChipScope Peripheral

3. Выбираю To monitor AXI Interconnect signals (adding AXI Monitor)

4. Выбираю одну из шин AXI4-Stream моего ядра

5. В MHS файле дописываю строку PORT MON_AXI_ARESETN = processing_system7_0_FCLK_RESET0

Без этой записи при компиляции выдает ошибку – не знает куда подключить порт RESET. Я его подключил к тому же сигналу сброса от которого мое ядро сбрасывается

6. Компилим. В SDK грузим плис.

7. Запускаем чипскоп. Затем JTAG_Chain находит два девайса – ARM_DAP и XC7Z020

И при этом пишет Found 0 Core Units in the JTAG device Chain

8. Импортирую сформированный chipscope_axi_monitor_0.cdc файл и получаю ошибку

No valid units or devices are available given this signal import file!

 

Что я не правильно сделал?

 

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


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

Проблему удалось временно отодвинуть. Установка ISE 14.7 конечно ничего не изменила.

Мне удалось достать другую отладочную плату с тем же цинком, а именно TE0720-02. Собрал абсолютно тот же проект на ней, только подгрузил соответствующий xml файл. И произошло чудо - проц успешно проскочил запрет прерываний и пр. команды работы с DMA и вошел в бесконечный цикл ожидания завершения приема данных. Значит проблема в AXI. По описанной выше проблеме чипскопом через XPS посмотреть ничего не смог. И тогда я сделал ход конем - создал буферное ядро которое пропускает через себя все линии AXI4-Stream на уровень логики ПЛИС. И уже в ISE я вставил текст ядра, указанный во 2-м посте. И все заработало сразу и без зависаний. Причем чипскоп подключенный в ISE работал странно - он показывает правильную времянку, потом все сигналы становятся на время =1, а потом снова правильную времянку. Пришлось смотреть сигналы осциллографом - все сигналы в точности такие как и должны быть. Чипскоп врет или виснет на время.

 

ИТОГ: абсолютно рабочие коды из второго поста, абсолютно рабочий проект...НО на одной отладочной плате не работают вообще, на другой код ядра работает только если его из XPS перенести в ISE. В общем МРАК!!! Я всегда был за идею объединения плис с процом, но то как это реализовано у Xilinx вызывает грусть и апатию, если не сказать хуже.

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


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

ИТОГ: абсолютно рабочие коды из второго поста, абсолютно рабочий проект...НО на одной отладочной плате не работают вообще, на другой код ядра работает только если его из XPS перенести в ISE. В общем МРАК!!! Я всегда был за идею объединения плис с процом, но то как это реализовано у Xilinx вызывает грусть и апатию, если не сказать хуже.

Всё там отлично реализовано, для начала возьмите Vivado, как и советовали выше.

 

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


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

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...