logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

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

Aro_ 06 Sie 2011 13:49 2208 10
REKLAMA
  • #1 9796880
    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:
    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:
    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;
  • REKLAMA
  • Pomocny post
    #2 9796968
    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.
  • REKLAMA
  • #3 9797300
    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.
  • #4 9798569
    drzasiek
    Specjalista CNC
    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..
  • REKLAMA
  • #5 9798598
    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
  • #6 9798622
    drzasiek
    Specjalista CNC
    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:
    
    TCC0.CTRLA = 0x01;      // Prescaler: clk/1
    TCC0.PER   = 32; //1MHz
    

    To jest nie prawda :)
  • REKLAMA
  • #7 9798673
    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.
  • #8 9798712
    drzasiek
    Specjalista CNC
    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.
  • #9 9799312
    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?
  • Pomocny post
    #10 9800878
    drzasiek
    Specjalista CNC
    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 :)
  • #11 9801163
    Aro_
    Poziom 15  
    No faktycznie:) Nie zwróciłem uwagi na to :D Dzięki!
REKLAMA