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

Avr asembler porównywanie danych w szybszy sposób ?

KJ 15 Lip 2010 02:59 2064 13
REKLAMA
  • #1 8293662
    KJ
    Poziom 31  
    Witam. Pisze właśnie 48 kanałowy moduł PWM. Procesor to atmega 169. problem Polega na tym że odświeżanie jest trochę za wolne jak na moje oko - nie wiem czy nie przegiąłem z liczbą kanałów obsługiwanych przez jeden procesor. Pierwotnie napisałem program w bascomie - działa ale zdecydowanie za bardzo miga. Metoda chyba najszybsza z możliwych czyli programowy licznik który liczy od 0 do 128 i w każdym przebiegu licznika porównuję ten licznik z danymi z tabeli jeżeli któraś jest równa to wyłączam kanał odpowiadający tej zmiennej - przed licznikiem włączam wszystkie kanały. Postanowiłem program przepisać na asembler już w zasadzie działa i jest szybciej ale nadal nie tak szybko jak bym chciał... Metoda postępowania ta sama - włączam wszystko i wpadam w pętlę w której sprawdzam czy któraś dana z tablicy odpowiada licznikowi i wyłączam dany kanał. Problem jest w tym sprawdzaniu. Obecnie robię to tak:

    cpse r30,r17
    jmp tam
    cbi	PORTe,6	
    tam:
    
    cpse r30,r18
    jmp tam1
    cbi	PORTe,7
    tam1:
    .
    .
    .
    
    

    R30 to mój licznik z którym porównuje inne rejestry. Mam jednak tylko 32 rejestry a kanałów 48 trzeba więc porównywać z zawartością ramu a nie rejestru i tu pytanie - czy istnieje polecenie działające jak cpse tylko zamiast dwóch rejestrów porównujące rejestr z komórką pamięci ram albo dwie komórki pamięci? czy jedyna metoda to przerzucenie danej z komórki ramu do rejestru i dopiero porównanie przez cpse ?
  • REKLAMA
  • #2 8293736
    Konto nie istnieje
    Poziom 1  
  • REKLAMA
  • #3 8294149
    skynet_2
    Poziom 26  
    Hmm a nie dało by się to zrobić równolegle po 8 wyjść na raz?

    Masz zakres 0-127, więc można by zrobić tablicę o długości 768 B [128poziomów*48wyjść/8bitów].
    W każdych kolejnych 6 komórkach masz wszystkie stany dla 48 wyjść odpowiadające jednemu cyklowi licznika.

    PORTA to 0 komórka pamięci więc każdy bit w tej komórce odpowiada za 1 wyjście, PORTB to 1 komórka pamięci, itd. aż wszystkie wyjścia zostaną ustawione, następne 6 komórka to znowu PORTA itd.

    Innymi słowy w tablicy masz zapisane bezpośrednio stany wyjściowe portów dla wszystkich wartości licznika.

    Przykładowy program:
    uint8_t tab[128*48/8] = {};
    uint8_t *p;
    while(1)
    {
    	p = tab; //ustawienie wskaźnika
    	for (uint8_t i = 0; i <= 127; ++i)
    	{
    		PORTA = *p;
    		++p;
    		PORTB = *p;
    		++p;
    		PORTC = *p;
    		++p;
    		PORTD = *p;
    		++p;
    		PORTE = *p;
    		++p;
    		PORTF = *p;
    		++p;
    	}
    }

    Można to jeszcze przyspieszyć poprzez rozwinięcie pętli for.
  • #5 8294295
    Konto nie istnieje
    Poziom 1  
  • #6 8294606
    skynet_2
    Poziom 26  
    androot napisał:
    Kolega nie odróżnia asm od C??
    Chodzi o optymalizację kodu w celu przyspieszenia.
    Odróżnia odróżnia ale chciałem przedstawić jak by to miało działać, a ponieważ piszę w C to pokazałem w C.

    atom1477 napisał:
    skynet_2: żeby o działało to musiał byś mieć tablicę zawierającą wszystkie kombinacje wartości PWMów.
    Czyli 128wartości ^ 48 PWMów = raczej dużo.


    Przy 128 poziomach i 48 PWM'ach będzie to 768 Bajtów.

    Widzę że nie wyjaśniłem wystarczająco dokładnie, normalnie musisz porównać wartość licznika z wartością zmiennej, czyli można by to tak zapisać.
    uint8_t pwmA1 = 67;
    uint8_t pwmA2 = 100;
    for (uint8_t i = 0; i <= 127; ++i)
    {
    	if (pwmA1 > i)
    		CLEAR(PORTA, PIN0);
    	if (pwmA2 > i)
    		CLEAR(PORTA, PIN1);
    }


    Natomiast ja bym nic nie porównywał tylko przepisywał wartość portu z wcześniej wygenerowanej tablicy.

    uint8_t pwmA1 = 67;
    uint8_t pwmA2 = 100;
    
    uint8_t buforpwmA[128];
    for (uint8_t i = 0; i <= 127; ++i)
    {
    	if (pwmA1 > i)
    		buforpwmA[i] |= 1<<PIN0;
    	else
    		buforpwmA[i] &= ~(1<<PIN0);
    	if (pwmA2 > i)
    		buforpwmA[i] |= 1<<PIN1;
    	else
    		buforpwmA[i] &= ~(1<<PIN1);
    }
    //główna bętla
    for (uint8_t i = 0; i <= 127; ++i)
    {
    	PORTA = buforpwmA[i];
    }


    //Dla uproszczenie nie dałem wskaźników.

    Dzięki temu za pomocą jednego przepisania możemy ustawić aż 8 wyjść[w tym przykładzie 2], tyle że jeśli trzeba zmienić wartość jednego z PWM'ów, to trzeba zaktualizować tablicę buforpwmA, a to może trochę potrwać.
    Chociaż można by aktualizować tylko kawałek tablicy z zależności od tego jak zmieniła się wartość danego PWM'a.
  • REKLAMA
  • #7 8294628
    Konto nie istnieje
    Poziom 1  
  • #8 8294876
    skynet_2
    Poziom 26  
    atom1477 napisał:
    Mowa o wszystkich kombinacjach PWMów.

    Inna sprawa że Ty chyba mówisz o czymś innym.

    Tak zupełnie o czymś innym, wymyśliłem że można by zbuforować operacje porównywanie licznika z wartością danego PWM'a i wrzucić to wszystko to tablicy.

    Tyle że nie wrzucałbym wszystkich możliwych kombinacji a jedynie te które odpowiadają aktualnej wartości danych pwm'ów i odświeżałbym tablicę jeżeli wartość zadana dla któregoś PWM'u się zmieni.
  • #9 8294898
    KJ
    Poziom 31  
    Nie bardzo rozumiem jak to zrealizować - C nie znam w ogóle podane przykłady niewiele mi mówią.
  • #10 8295089
    skynet_2
    Poziom 26  
    KJ napisał:
    Nie bardzo rozumiem jak to zrealizować - C nie znam w ogóle podane przykłady niewiele mi mówią.


    Musisz przeznaczyć pewną ilość pamięci na bufor.

    Załóżmy że PWM ma tylko 16 poziomów więc licznik liczy do 16, i jest 8 PWM'ów czyli 1 port.
    Pierwszy pwm niech ma wartość np. 12.
    Czyli bufor wyglądał by jakoś tak[1 linijka to 1 bajt]:
    0 0 0 0 0 0 0 1 
    0 0 0 0 0 0 0 1 
    0 0 0 0 0 0 0 1 
    0 0 0 0 0 0 0 1 
    0 0 0 0 0 0 0 1 
    0 0 0 0 0 0 0 1 
    0 0 0 0 0 0 0 1 
    0 0 0 0 0 0 0 1 
    0 0 0 0 0 0 0 1 
    0 0 0 0 0 0 0 1 
    0 0 0 0 0 0 0 1 
    0 0 0 0 0 0 0 1 
    0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0


    Zamiast porównywać za każdym razem czy dany PWM jest równy wartości licznika a jeżeli jest to gasić dane wyjście, ja bym te procesy rozdzielił.

    Najpierw bym sprawdził czy dany PWM jest większy od wartości licznika[jeśli nie to bit w pamięci = 1, jeśli tak to = 0] wrzuciłbym ten wynik to pamięci, oczywiście trzeba to powtórzyć dla wszystkich aktualnych wartościach PWM'ów i wszystkich stanów licznika dlatego przy 128 poziomach i 48 PWM'ach jest to 768 B, jedno wyjście to 1 bit.

    Później bym tylko przepisywał sprawdzone wcześniej wyniki bezpośrednio na wyjście.

    Będzie działać to szybciej bo kiedy licznik leci od początku i PWM'y mają taką samą wartość to nie musisz ich sprawdzać.

    Tyle że jeżeli zmienisz wartość któregoś z PWM'ów to będziesz musiał zaktualizować tablicę przechowującą wyliczone stany wyjściowe.
  • REKLAMA
  • #11 8295943
    Konto nie istnieje
    Poziom 1  
  • #12 8296045
    KJ
    Poziom 31  
    No to pozostaje mi jeszcze problem UARTu opisany tutaj:Link
  • #13 8296361
    rpal
    Poziom 27  
    Może napisz to samo w C a potem porównaj generowany kod z tym co sam napisałeś i znajdziesz błąd ? To w sumie jest dosłownie kilka linijek do analizy.
  • #14 8296720
    KJ
    Poziom 31  
    W zasadzie to już rozwiązałem problem z uartem - jest byk w symulatorze. W prawdziwym procku program działa. bazuję głównie na symulacji przy debugowaniu asemblera bo nie mam programatora współpracującego z AVRstudio i przeprogramowywanie procesora x razy jest dość kłopotliwe.
REKLAMA