Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: NIOSII и DMA
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Системы на ПЛИС - System on a Programmable Chip (SoPC)
Kuzmi4
Здравствуйте.
Счас пытаюсь освоить ДМА для ниоса.
Прочитал описание альтеры для компонента, на ниос-форуме посмотрел примеры и сваял свою реализацию..
В обсчем код выглядит так(звиняйте если большой, но коментарии присутствуют):
Код
//===ISR part===
static void dma_isr ( void * context2, alt_u32 irqnum2 )
{
    asm("nop");
    //set flag
    dmaf=1;
    /* Clear any pending interrupts and the DONE flag */
    IOWR_ALTERA_AVALON_DMA_STATUS (DMA_BASE, 0);
    
}
//===END ISR part===


//---MAIN---
int main (void)
{
    asm ("nop");
    //
    unsigned char i=0;
    // initial values
    cnt_val=0;
    ch=0;
    txf=0;
    dmaf=0;
    //
    for (i=0;i<12;i++)
    {
        inbuffer[i]=0;
        outbuffer[i]=i+1;
    }
    //
    //
    asm("nop");
    //register DMA ISR
    alt_irq_register(DMA_IRQ,(void*)DMA_BASE,dma_isr);
    asm("nop");
    asm("nop");
    //
    //DMA_Init
    /* Clear any pending interrupts and the DONE flag */
    IOWR_ALTERA_AVALON_DMA_STATUS (DMA_BASE, 0);
    asm("nop");
    asm("nop");
    //clear control register
    IOWR_ALTERA_AVALON_DMA_CONTROL (DMA_BASE, 0);
    asm("nop");
    asm("nop");
    /* Halt any current transactions (reset the device) */
    IOWR_ALTERA_AVALON_DMA_CONTROL (DMA_BASE, ALTERA_AVALON_DMA_CONTROL_SOFTWARERESET_MSK);    
    IOWR_ALTERA_AVALON_DMA_CONTROL (DMA_BASE, ALTERA_AVALON_DMA_CONTROL_SOFTWARERESET_MSK);
    asm("nop");
    asm("nop");
    asm("nop");
    //asm("nop");
    //set initial values for tranmit
    //byte orientating transfer
    alt_u32 control=0;
    control |= ALTERA_AVALON_DMA_CONTROL_BYTE_MSK;//byte transfer
    control |= ALTERA_AVALON_DMA_CONTROL_I_EN_MSK;//enable int
    control |= ALTERA_AVALON_DMA_CONTROL_LEEN_MSK;//enable end of transaction by reacing Len 0
    //1st try with mem massives -> no uart
    //control |= ALTERA_AVALON_DMA_CONTROL_RCON_MSK;//read from constant mem - we use uart, so mem == const
    //store control
    IOWR_ALTERA_AVALON_DMA_CONTROL (DMA_BASE, control);
    asm("nop");
    asm("nop");    
    //**
    //DMA_start((int)&inbuffer[0],(int)&outbuffer[0],10);
    //**
    waddr = (int)&inbuffer[0];
    raddr = (int)&outbuffer[0];
    len=10;
    //alt_u32 control;
    control=0;
    //wrire read addr
    IOWR_ALTERA_AVALON_DMA_RADDRESS(DMA_BASE, raddr);
    asm("nop");
    asm("nop");
    //wrire write addr
    IOWR_ALTERA_AVALON_DMA_WADDRESS(DMA_BASE, waddr);
    asm("nop");
    asm("nop");
    //write length
    IOWR_ALTERA_AVALON_DMA_LENGTH(DMA_BASE,len);
    asm("nop");
    asm("nop");
    //start transfer
    control = IORD_ALTERA_AVALON_DMA_CONTROL (DMA_BASE);
    control |= ALTERA_AVALON_DMA_CONTROL_GO_MSK;
    IOWR_ALTERA_AVALON_DMA_CONTROL (DMA_BASE, control);
    //
    dmaf=0;
    asm("nop");
    //**
  while (1)
  {
    /***/
wlabel:
    asm("nop");
    //
    if (dmaf==0) goto wlabel;
    
    asm("nop");
    IOWR_ALTERA_AVALON_PIO_DATA(SEVEN_SEGMENT_PORT_BASE,segments[inbuffer[0]] );        
        asm("nop");
    while (1);
    /***/
  }
  
  return 0;
}


В обсчем, компилируется всё нормально, код вроде выглядить при дебуге нормально,
однако есть непонятные моменты...
Если поставить точек прерываний по коду в ключевых местах - регистрация прерывания, запись контрола ДМА, старт ДМА - то всё отрабатывается нормально, если только на старте ДМА - то интерупт генерится а действия никакого..
Если вообсче не ставить точек прерывания - то ничего не отрабатывается - интерупта нет.. ничего нет...
Дебаг юнит в НИОСЕ - 2-й, 3-й - без разницы.
Read и Write каналы соединены с уартом и сдрам, программа находтся в сдрам, переменные - тоже.
В принципе такое поведение наталкивает на мысль , что не хватает задержек (только не пойму зачем, вроде в описании к ДМА не было про них...) , потому и наставил нопов - однако с ними и без них - работает одинаково...
smile3046.gif
Кто работал с ДМА - подскажите что не так ..
help.gif
Спасибо.
Kuzmi4
Что ? Никто не работал с ДМА через регистры ?? sad.gif
help.gif
Неохота просто тратить килобайты кода на каналы, что в хале уже есть, если можно просче...
torik
Надо попробовать для начала без прерываний:
Код
    while ((IORD_ALTERA_AVALON_DMA_STATUS (DMA_0_BASE) & ALTERA_AVALON_DMA_STATUS_BUSY_MSK)); // ждем пока все не передаст
Kuzmi4
В обсчем попробовал я без прерываний..

Код:
Код
//
    unsigned char i=0;
    for (i=0;i<16;i++)
    {
        inbuffer[i]=0;
        outbuffer[i]=i+1;
    }
    //
    waddr = (alt_u32)&inbuffer[0];
    raddr = (alt_u32)&outbuffer[0];
    buff_length = 8;
    //
    IOWR_ALTERA_AVALON_DMA_STATUS(DMA_BASE, 0); //очистка статуса
    IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_BASE,0); //очистка регистра управления
    //
    IOWR_ALTERA_AVALON_DMA_RADDRESS(DMA_BASE, raddr); //адрес передатчика
    IOWR_ALTERA_AVALON_DMA_WADDRESS(DMA_BASE, waddr); //адрес приемника
    //
    IOWR_ALTERA_AVALON_DMA_LENGTH(DMA_BASE, buff_length); //длина в байтах
    dma_length=IORD_ALTERA_AVALON_DMA_LENGTH(DMA_BASE);
    //
    IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_BASE,
    ALTERA_AVALON_DMA_CONTROL_BYTE_MSK|
    ALTERA_AVALON_DMA_CONTROL_GO_MSK|
    ALTERA_AVALON_DMA_CONTROL_LEEN_MSK);
    
    while ( IORD_ALTERA_AVALON_DMA_STATUS(DMA_BASE) & (ALTERA_AVALON_DMA_STATUS_BUSY_MSK))
    { // ждем пока все не передаст
        asm volatile ("nop");
    }
    //отображение
    printf("!!!");
    printf("inbuffer= ");
    for (i=0; i<buff_length; i++)
    {
        printf("%i ", inbuffer[i]);
        asm volatile ("nop");
    }
    printf("!!!");
    printf("outbuffer= ");
    for (i=0; i<buff_length; i++)
    {
        printf("%i ", outbuffer[i]);
        asm volatile ("nop");
    }
    printf("!!!");
    while (1);


Вот что выдало:

!!!inbuffer= 0 0 0 0 0 0 0 0 !!!outbuffer= 1 2 3 4 5 6 7 8 !!!

То есть отработка есть а результата нет - как такое может быть ? wacko.gif
Специально проверил в дизайне процессора - коннекты есть с сдрамом для записи и чтения:
Нажмите для просмотра прикрепленного файла

Это вот меня и загоняет в тупик....... smile3046.gif
AlexanderL
попробуй вот так:

IOWR_ALTERA_AVALON_DMA_RADDRESS(DMA_BASE, outbuffer); //адрес передатчика
IOWR_ALTERA_AVALON_DMA_WADDRESS(DMA_BASE, inbuffer); //адрес приемника
Kuzmi4
2 AlexanderL -

Понимаете -
конструкция вида
waddr = (alt_u32)&inbuffer[0];
как раз и загружает в waddr адрес inbuffer[0].

А ваше предложение вызывает такие варнинги:
../count_binary.c: In function `main':
../count_binary.c:50: warning: passing arg 2 of `__builtin_stwio' makes integer from pointer without a cast
../count_binary.c:51: warning: passing arg 2 of `__builtin_stwio' makes integer from pointer without a cast

Так что это не то..
Кстати до и после транзакции смотрел - правильные адреса в регистрах...
Длинна - то же правильная в регистре..
( Смотрел в дебуге )
vetal
Цитата
waddr = (alt_u32)&inbuffer[0];
как раз и загружает в waddr адрес inbuffer[0].

Это если без кэша, с кэшем - они там и остаются. Чтобы обойти кэш надо установить 31 бит в адресе переменной или использовать макросы доступа к регистрам.
Kuzmi4
NIOSII у меня fast - тобто полной комплектации - есть кеш.

Однако по коду просмотрел значения waddr и raddr и те что записывались в регистры ДМА, а потом в мемори тыканулся по этим адресам - всё соответствовало реальности..
Биты DONE и LEN выставляются, регистры адреса меняются, регистр длинны нулевой в конце , а результата - НОЛЬ crying.gif
help.gif

Не можете вы объяснить что значит "обойти кеш" и к чему это?
smile3046.gif
torik
А вот эти массивы откуда беруться, как объявлены. Проверяли в дебагере - соответствуют ли они тем адресам на которые подключен DMA?
Код
        inbuffer[i]=0;
        outbuffer[i]=i+1;


Да вообще может я чего-то не понимаю, но как это вы задаете для DMA буфер откуда читать из памяти SDRAM (и то по этому поводу я выше писал), если в системе сопс он подключен к UART. Тогда и подкулючайте порт чтения DMA к той же памяти.
Ну и, пожалуй буферы выделяйте через malloc().
Kuzmi4
Цитата(torik @ May 8 2008, 16:58) *
А вот эти массивы откуда беруться, как объявлены

Обявлены до мэйна
Код
//---DATA Declaration    
    volatile alt_u8 inbuffer[16];
    volatile alt_u8 outbuffer[16];
    volatile alt_u32 waddr=0;
    volatile alt_u32 raddr=0;
    volatile alt_u32 buff_length=0;
    volatile alt_u32 dma_length=0;
//---END DATA Declaration
//

//---MAIN---
int main (void)
{
....

В дебуге проверял - выше писал..Перед записью GO_MASK для старта делал останов и проверял регистры - readaddress и writeaddress соответствовали действительным адресам в раме(тыкался по мемори,смотрел..), длинна тоже была правильной...

Вот рисунок с SoPC - там можете увидеть - синеньком подсвечены read и write подключения - ДМА подключён к уарту и сдрам
Нажмите для просмотра прикрепленного файла

И что вы имелли ввиду на счёт
Цитата(torik @ May 8 2008, 16:58) *
как это вы задаете для DMA буфер откуда читать из памяти SDRAM
Ну и, пожалуй буферы выделяйте через malloc().

Я выставляю в ДМА регистре readaddress откуда читать, в регистре writeaddress - куда писать...
И зачем именно malloc() ? Вроде бы уже есть массив volatile alt_u8 ...

--
Прицепил весь свой прожект вообсче.
Если будет время посмотрите - может что не так...
Вот картинки начальных конфигурирования ДМА:
Нажмите для просмотра прикрепленного файла
Нажмите для просмотра прикрепленного файла
vetal
Цитата
Не можете вы объяснить что значит "обойти кеш" и к чему это?

Это значит то, что вы можете писать в память,но данные на самом деле не выйдут за пределы процессора. Также при чтении получите коллизию данных, когда в кэше сидят старые данные, а в памяти новые. Кэш то не знает чего вы там за пределами процессора делаете.
При использовании макросов прямого доступа к периферии данные гарантированно выходят за пределы процессора. volatile спасает от оптимизации, но не от кэша!
Kuzmi4
2 vetal - Спасибо. Буду знать.

Сегодня пересоздал процессор - дма, цпу, сдрам - результат такой же - дма отрабатывает, а записи в массив нету...
Видимо как раз у меня проблема с этим кэшем..
Надо будет пересобрать процессор без кеша на крайний случай...

А на счёт макросов обращения к памяти - я ж вроде смотрел в мемори въювере - адреса меняются, всё вроде отрабатывается, только вот в том же въювере не видно изменений в выходном массиве.. То есть запись то в регистры ДМА получается проходит нормально....
wacko.gif
Тут есть идея - возможно что когда я повторно считываю данные с массива inbuffer - процюк берёт их с кеша - ведь он уже с ними работал до этого в начале мэйна... А как можно перегрузить данные массива из памяти в кеш ?? smile3046.gif
vetal
Работа с кешем:
http://altera.com/literature/hb/nios2/n2sw_nii52007.pdf
RHnd
Цитата(vetal @ May 11 2008, 21:12) *

Действительно, попробуйте для эксперимента отключить кеш у проца. Если траблы исчезнкт, то осваивайте работу с кешем.
Kuzmi4
Ага! 08.gif
Пока суть до дела, я отправил запрос в саппорт - типа хелп, не работает...
В обсчем получил ответ с саппорта - догадка оказалась правльной - действительно кеш бякой оказался:
Цитата
...
Since the CPU you used has data cache, I am afraid that the data displaying after the DMA operation is the dirty data.

Please call alt_dcache_flush_all (); after the DMA finishes. The alt_dcache_flush_all() function flushes, i.e., writes back dirty data and then invalidates, the entire contents of the data cache.
...

Сегодня как дойдут руки - обязательно попробую , а то уже столько времени уже убил блин на одном месте....
smile3046.gif
...
Кстати читая "n2sw_nii52007.pdf" наткнулся на место:
Цитата
The volatile keyword ONLY prevents the compiler from optimizing out accesses using the pointer.

Как раз то , о чём говорил vetal ..
Действительно тут немного другой подход...
Kuzmi4
-----
Пересобрал НИОС2 , и решил подобавлять alt_dcache_flush_all в код.
Что самое интересное - если вставить эту функцию после начальной инициализации массивов
Код
for (i=0;i<16;i++)
    {
        inbuffer[i]=0;
        outbuffer[i]=i+1;
    }
    //*******
    alt_dcache_flush_all();
    //*******
    waddr = (alt_u32)&inbuffer[0];
    raddr = (alt_u32)&outbuffer[0];
    buff_length = 8;
    //

Тогда всё ок - по printf -> выдаётся то, что и должно быть
Цитата
!!!inbuffer= 1 2 3 4 5 6 7 8 !!!outbuffer= 1 2 3 4 5 6 7 8 !!!


А если вставить alt_dcache_flush_all после цикла ожидания
Код
while ( IORD_ALTERA_AVALON_DMA_STATUS(DMA_BASE) & (ALTERA_AVALON_DMA_STATUS_BUSY_MSK))
    { // ждем пока все не передаст
        asm volatile ("nop");
    }
    //flush
    //alt_dcache_flush_all();
    //отображение
    printf("!!!");

То выдаётся такое:
Цитата
!!!inbuffer= 0 0 0 0 0 0 0 0 !!!outbuffer= 1 2 3 4 5 6 7 8 !!!

Как это можно объяснить ? smile3046.gif
Ведь в описании комманды flushd , которую собсно и вызывает alt_dcache_flush_all указано, что:
Цитата
Flushes the data cache line associated with address rA + σ (IMM16).

То есть очищает кеш данных асоциированных с адресом таким то..

Почему очистка после ожидания флага не даёт результата ??
wacko.gif
vetal
Цитата
Почему очистка после ожидания флага не даёт результата ??

alt_dcache_flush_all() скадывает данные из кэша в озу и производит сброс(инициализацию) кэша. Выполнение функции после отработки дма затирает новые данные старыми.
Вроде так smile.gif
Из словаря promt(информатика): flush- сбрасывать на диск. В нашем случае мочно читать как : перемещать в память.
Kuzmi4
Тогда получатся всё правильно - я инициализирую данные начальными значениями, сбрасываю с кеша в сдрам и сбрасываю кеш, потом запусукаю ДМА , а после процесор смотрит что у него нету этих данных в кеше и берёт с сдрама...
2 vetal - a14.gif

Вот оно как хитро получается...
smile.gif

Прицепил си-шный код, вдруг кому понадобится..
AlexanderL
Цитата(Kuzmi4 @ May 12 2008, 16:49) *
Вот оно как хитро получается...


молодец, a14.gif +1, я бы даже и не догадался что ДМА так будет работать с кэшируемыми данными
хорошо что раскопал, (у меня были другие проблемы (разрядность brust count и разряднорсть передаваемых данных)), спасибо буду знать.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.