Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[XMEGA][c] DMA wyzwalane timerem i odczyt portu.

Aro_ 06 Sie 2011 13:49 1947 10
  • #1 06 Sie 2011 13:49
    Aro_
    Poziom 15  

    Witam,
    Od dłuższego czasu zastanawiam się jak rozwiązać pewien problem.
    Otóż, gdy próbuję ustawić DMA wyzwalane przepełnieniem timera, to nie działa jak powinno. DMA startuje przy pierwszym przepełnieniu TC, a później odczytuje dane z portu w swoim tempie, nie zważając na przerwania timera. Kod wydląda tak:

    Code:
    TCC0.CTRLA = 0x01;      // Prescaler: clk/1 
    
       TCC0.PER   = 32; //1MHz
       //DMA.CTRL =1<<7; //enable DMA upper
       DMA.CH3.CTRLA = (0<<5) | (1<<2) | (0<<0); //single, 1-byte
       DMA.CH3.CTRLB = 0<<4 | 0<<5 | 0<<2 | 2<<0; //error and complete interrupt flags, high level interrupt
       DMA.CH3.ADDRCTRL = (0<<6) | (0<<4) | (3<<2) | (1<<0); //addr reload src after 1-byte, no inc src addr, inc dst addr
       DMA.CH3.TRIGSRC = 0x40; //TCC0 - 0x40, TCD1 - 0x66 overflow trig.
       DMA.CH3.TRFCNT = 2048; //set 2048Byte block
       DMA.CH3.SRCADDR0  =(((uint16_t)(&PORTD.IN))>>0*8) & 0xFF;
       DMA.CH3.SRCADDR1  =(((uint16_t)(&PORTD.IN))>>1*8) & 0xFF;
       DMA.CH3.SRCADDR2  = 0;
       DMA.CH3.DESTADDR0 =(((uint16_t)(buf))>>0*8)&0xFF;
       DMA.CH3.DESTADDR1 =(((uint16_t)(buf))>>1*8)&0xFF;
       DMA.CH3.DESTADDR2 = 0;

    Natomiast podobny przykład, tylko wyzwalanie przez ADC nie sprawia żadnych problemów:
    Code:
    DMA.CTRL =1<<7; //enable DMA 
    
       DMA.CH1.CTRLA = (0<<5) | (1<<2) | (1<<0); //single, 2-byte
       DMA.CH1.CTRLB = 0<<4 | 0<<5 | 0<<2 | 2<<0; //error and complete interrupt flags, high level interrupt
       DMA.CH1.ADDRCTRL = (2<<6) | (1<<4) | (1<<2) | (1<<0); //addr reload src after 2-byte, inc src addr, inc dst addr
       DMA.CH1.TRIGSRC = 0x10; //ADCA, CH0
       DMA.CH1.TRFCNT = 2048; //set 2048Byte block
       DMA.CH1.SRCADDR0  =(((uint16_t)(&ADCA.CH0RESL))>>0*8) & 0xFF;
       DMA.CH1.SRCADDR1  =(((uint16_t)(&ADCA.CH0RESL))>>1*8) & 0xFF;
       DMA.CH1.SRCADDR2  = 0;//(((uint32_t)(&ADCA.CH0))>>2*8) & 0xFF;
       DMA.CH1.DESTADDR0 =(((uint16_t)(buf))>>0*8)&0xFF;
       DMA.CH1.DESTADDR1 =(((uint16_t)(buf))>>1*8)&0xFF;
       DMA.CH1.DESTADDR2 = 0;//(((uint32_t)(buf))>>2*8)&0xFF;

    0 10
  • Pomocny post
    #2 06 Sie 2011 14:17
    BoskiDialer
    Poziom 34  

    Zwykle z kanałami DMA jest tak, że jeśli urządzenie zgłosiło żądanie DMA, to będzie ono utrzymane tak długo, aż kanał DMA odczyta wartość z tego urządzenia. Przykładowo jeśli ADC uzyska próbkę, zgłosi żądanie do DMA, ale jak tylko DMA odczyta tą próbkę, żądanie zostanie zwolnione. Podobnie może być w przypadku timera: zdarzenie-żądanie-odczyt-potwierdzenie. Używanie żądania od timera do wyzwalania odczytu z portu może być utrudnione lub niemożliwe: aby timer zwolnił żądanie, musi pojawić się potwierdzenie, a te w przypadku timera są oparte o dostęp do rejestrów CNT,PER,PERBUF lub CCx,CCxBUF.

    0
  • #3 06 Sie 2011 16:17
    Aro_
    Poziom 15  

    Niestety, święta racja:(
    Wygląda na to, że będę musiał programowo odczytywać stan portu, bo raczej nie da się tego obejść.
    Dzięki wielkie za pomoc, teraz już wiem o co w tym biega.

    0
  • #4 06 Sie 2011 22:38
    drzasiek
    Specjalista - Mikrokontrolery

    A może by tak trochę to obejść?
    Jeśli możesz, to poświęć na to jeden z wirtualnych kanałów ADC.
    ADC bez problemu możesz taktować przepełnieniem Timera.
    DMA będzie wyzwalane przez ADC ale robiło będzie swoje, czyli odczytywało stan portu.
    Tylko teraz czy to się kupy trzyma?
    Działać powinno ale czy warto, to ja już nie wiem niestety :)
    A może można prościej..

    0
  • #5 06 Sie 2011 22:47
    BoskiDialer
    Poziom 34  

    Niestety, problem pozostanie ten sam: jeśli DMA będzie odczytywać z portu, nie nastąpi odczyt z ADC, a więc ADC będzie utrzymywać żądanie DMA. Cały problem jest w tym, że odczyt z urządzenia stanowi jednocześnie potwierdzenie powodujące zwolnienie żądania DMA. Żądania DMA nie mogą zawsze trwać jeden cykl - gdyby tak było, DMA przy przegraniu arbitrażu mogło by mieć dylemat: czy nadal należy odczytywać rejestr, czy już nie ma czego odczytywać? - żądania muszą być aż do potwierdzenia, którym niestety jest odczyt (lub zapis) z urządzenia

    0
  • #6 06 Sie 2011 22:56
    drzasiek
    Specjalista - Mikrokontrolery

    Noto poświęcić 2 kanały DMA, jeden odczyta wartość z ADC a drugi stan portów.
    Obydwa kanały DMA będą wyzwalane tym samym ADC :)
    No ale swoją drogą dziwne.. Skoro DS przewiduje wyzwalanie Timerem, czemu nie działa..
    [XMEGA][c] DMA wyzwalane timerem i odczyt portu.
    Może ma działać, ale czegoś brakuje w programie.
    Do autora:

    Code:

    TCC0.CTRLA = 0x01;      // Prescaler: clk/1
    TCC0.PER   = 32; //1MHz

    To jest nie prawda :)

    0
  • #7 06 Sie 2011 23:07
    BoskiDialer
    Poziom 34  

    A może wyzwalanie DMA timerem jest po to, aby zapisywać właśnie do timera? jak ktoś będzie generować przebieg o zmiennym okresie, to może mieć w buforze kolejkę kolejnych wartości TOP (nie wiem dokładnie jak działają timery w xmega, nie programowałem ich nigdy) uaktualnianych po każdym przebiegu. Może ktoś będzie generować przebieg o zmiennym wypełnieniu, wtedy DMA może aktualizować długość impulsu przy każdym przepełnieniu? Może ktoś będzie chciał zbierać dużą liczbę danych z input-capture, aby nie gubić próbek są przesyłane po DMA? Niestety, ale DMA wyzwalane timerem będzie użyteczne tylko w obrębie tego timera.

    Nawet gdyby się dało użyć 2 kanały DMA, była by to praca poza dokumentacją, a przy okazji nie było by gwarancji, że odczyt wystąpi (jeśli kanał właściwy będzie szybszy) lub że nie wystąpi wielokrotnie (kanał właściwy wolniejszy, albo o niższym priorytecie) - zapewnienie dokładnie jednego transferu jest osiągnięte przez zwolnienie żądania natychmiast po dostępie do urządzenia.

    0
  • #8 06 Sie 2011 23:21
    drzasiek
    Specjalista - Mikrokontrolery

    Tzn dyskusja schodzi trochę w bok ale czemu nie :)
    Wszystko zależy z jaką szybkością chce odczytywać stan tych portów.
    Nie sądzę, żeby miało to aż takie znaczenie, że któryś kanał będzie szybszy. Obydwa kanały "dostaną sygnał" do nowego transferu w tym samym czasie. No chyba, że odczyt portu będzie trwał dłużej niż czas pomiędzy kolejnymi nowymi próbkami z ADC.
    2 kanały DMA wyzwalane jednym ADC-rzecz spotykana w profesjonalnych projektach (open source) z tym, że nie analizowałem tego, czy działają jednocześnie, ale raczej tak. Więc myślę, że to by działało choć to marnotrastwo straszne, wykorzystywać timer, ADC i 2 kanały DMA do jednej tak prostej rzeczy.
    Wydaje mi się, że można prościej, ale jak?
    Niestety nie wiem, Ja DMA używałem jak narazie do ADC i DAC.

    0
  • #9 07 Sie 2011 10:24
    Aro_
    Poziom 15  

    Chyba nawet próbowałem z dwoma kanałami, ale na wszelki wypadek sprawdzę jeszcze raz, tylko podłączę się pod TC. Zresztą i tak będzie to już sporo kombinowania, bo przy dużych częstotliwościach próbkowania, będę musiał przełączyć się na jeden kanał.

    drzasiek napisał:
    2 kanały DMA wyzwalane jednym ADC-rzecz spotykana w profesjonalnych projektach (open source) z tym, że nie analizowałem tego, czy działają jednocześnie, ale raczej tak.

    Może to po prostu Double buffering?

    drzasiek napisał:
    Kod:

    TCC0.CTRLA = 0x01; // Prescaler: clk/1
    TCC0.PER = 32; //1MHz

    To jest nie prawda

    Co z tym nie tak?

    0
  • Pomocny post
    #10 07 Sie 2011 18:22
    drzasiek
    Specjalista - Mikrokontrolery

    TCC0.PER powinno być chyba raczej 31 dla 1 MHz nie?
    Bo jeśli masz 32 to razem z zerem jest to 33 kombinacje a 32 M / 33 to nie jest 1 M.
    Przynajmniej ja do tej pory żyłem w takim właśnie przekonaniu :)

    0
  • #11 07 Sie 2011 19:47
    Aro_
    Poziom 15  

    No faktycznie:) Nie zwróciłem uwagi na to :D Dzięki!

    0