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

Biphase mask - PWM na ATMega32

kuch_arc 10 Wrz 2008 11:02 2036 22
  • #1 5521623
    kuch_arc
    Poziom 14  
    Witam,
    Potrzebuje zakodować bity uzywajac biphase maski. Działa to tak jak na obrazku ponizej.

    Chcialbym do tego celu uzyc PWM wbudowanego w Timer1 na atmedze. Musze wysylac 6400 b/s, czyli potrzebuje min. 12800 Hz + cos na parity/preamble bits. Czy jest jakis naprawde dobry tutorial do PWM? Moze ktos moglby pokazac przykladowy kod, najlepiej z opisem zebym sobie mogl z datahseetem pokminic?

    Jesli chodzi o timery, to cos juz tam wiem. Zrobilem w CTC wysylanie danych co 0.01 z jednego mikrokontrolera na ten wlasnie co ma kodowac biphase. I tutaj pojawia sie chyba najwiekszy problem. Ten mikrokontroler oprocz tego, ze ma wysylac na pin informacje w biphase, to jeszcze musi odbierac te dane co je wysyla i tego jeszcze nie rozwiazalem, a chcialbym uniknac dodawania jakiegos modolu czasowego i tagow czasowych jako takich.

    Najlepsze rozwiazanie dla mnie to przesylanie tych danych "on the fly". Jakkolwiek, te dane, wyslane w danym momencie, musza byc w tym momencie przeslane dalej :/ albo przynajmniej ze stalym, znanym opoznieniem. Any hints ?
    Biphase mask - PWM na ATMega32
  • #2 5522167
    szelus
    Poziom 34  
    kuch_arc napisał:

    Potrzebuje zakodować bity uzywajac biphase maski. [...]
    Chcialbym do tego celu uzyc PWM wbudowanego w Timer1 na atmedze.

    Moim zdaniem tryb PWM to się do tego nie nadaje. Tutaj zmienia Ci się nie tyle wypełnienie, co częstotliwość nośnej.
    Jeżeli jitter wynikający z programowego ustawiania/kasowania pinu wyjściowego jest nie do przyjęcia, to proponuję jako modulatora użyć timera w trybie CTC, przy ustawieniu trybu "toggle" dla wyjścia OC.
    Tylko współczynnik podziału zegara dla zera musiałby być parzysty.

    Cytat:

    Jesli chodzi o timery, to cos juz tam wiem. Zrobilem w CTC wysylanie danych co 0.01 z jednego mikrokontrolera na ten wlasnie co ma kodowac biphase. I tutaj pojawia sie chyba najwiekszy problem. Ten mikrokontroler oprocz tego, ze ma wysylac na pin informacje w biphase, to jeszcze musi odbierac te dane co je wysyla i tego jeszcze nie rozwiazalem, a chcialbym uniknac dodawania jakiegos modolu czasowego i tagow czasowych jako takich.

    Chodzi o kontrolę danych wysyłanych np. do współdzielonego medium transmisyjnego i detekcję kolizji?
    Odbiór zmodulowanego sygnału będzie chyba najprościej zrealizować za pomoca sygnału ICP.

    Cytat:

    Najlepsze rozwiazanie dla mnie to przesylanie tych danych "on the fly". Jakkolwiek, te dane, wyslane w danym momencie, musza byc w tym momencie przeslane dalej :/ albo przynajmniej ze stalym, znanym opoznieniem.

    Tego to już kompletnie nie zrozumiałem. Mógłyś spróbować rozjaśnić, co masz na myśli?
  • #3 5522322
    kuch_arc
    Poziom 14  
    Primo - dzieki za odpowiedź :).

    Secundo...
    Troche mi sie pomylilo , bo wlasnie na CTC zaczynam to robic. Nie jestem wymiataczem w uC, taka wpadka troche ;). Myslalem, ze PWM mi da kontrole nad zmianami amplitudy poza dlugoscia wypelnienia.

    A co do rozjasnienia - jeden uC droga radiowa w trybie JEDNOKIERUNKOWYM wysyla co 0.01 s dane - paczke 8 x 8bit , czyli 6400 b/s. Dane te odbiera drugi mikrokontroler o ktorym teraz mowimy i ma je zaraz wysylac na analogowe wejscie mikrofonowe finalnego urzadzenia. Opoznienie pomiedzy odebraniem paczki danych a jej transmisją szeregowa na to wejscie mikrofonowe, musi byc mozliwe najmniejsze. I tutaj wlasnie mam problem. Chcialbym to zrobic wykrzystujac przerwania i CTC maksymalnie, aby wszystko dzialo się w takich samych odstepach czasu - tj. nawet jesli bedzie jakies opoznienie, to musi byc ono stale i mozliwe do wyliczenia.

    Reasumujac - musze jakos pogodzic odebranie paczki i jej wyslanie, tak zeby zawsze zajmowalo to tyle samo czasu. Ciezko wszystko ustawić na sztywno, bo tak naprawde nie wiem ile czasu zajmuje nadawanie i kiedy ta paczka dotrze, a dane od momentu wyslania do zapisania na kanale audio musza miec jak najmniejszy poslizg czasowy.

    EDIT:
    Jak moge blokowac toggle na wyjsciu przy CTC? Zakladajac ze MUSZE miec zmiane na wyjsciu na parzystym przerwaniu a MOGE na nieparzystym, jak zrobic? To by bylo idealne. Moglbym czytac bity z bajta przesuwajac je w prawo i ustawiac jakas flage, dobrze mysle?
  • #4 5522548
    szelus
    Poziom 34  
    Potencjalny problem, jaki widzę to taki, że jeżeli zegary pomiedzy nadajnikiem i odbiornikiem nie będą chodziły z dokładnie tą samą częstotliwością, to to wysyłanie równocześnie z odbiorem będzie się rozjeżdżać przy dłuższych komunikatach. Chociaż przy kwarcowej stabilizacji i krótkich komunikatach nie powinno byc tego problemu.
    Opóżnienie większe niż czas 1 bitu jest nieuniknione (w końcu trzeba bit odebrać i rozpoznać).

    kuch_arc napisał:

    Jak moge blokowac toggle na wyjsciu przy CTC? Zakladajac ze MUSZE miec zmiane na wyjsciu na parzystym przerwaniu a MOGE na nieparzystym, jak zrobic? To by bylo idealne. Moglbym czytac bity z bajta przesuwajac je w prawo i ustawiac jakas flage, dobrze mysle?


    1. Możesz odczytać stan wyjścia OC i następnie przełączyć na tryb "set/clear on compare match", w zależności od stanu.

    2. Ja myślałem raczej o podmienianiu wartości OCR i zaliczaniu dwóch przerwań na bit 1 i jednego na bit 0.
  • #5 5522656
    kuch_arc
    Poziom 14  
    AD2.
    Hmm, ale myslalem ze tylko OCR1A moze robić jako TOP value w w TCNT1. Jeśli chce mieć te 12800 albo 14400, to musze ograniczać licznik a OCR1B chyba nie może tego robić. No chyba, że nie zauwazyłem jakiejś kombinacji prescaler/count number, która pozwolić działać na pełnym obrocie licznika.

    Jeszcze tego nie widze do konca, ale moze juz wkrotce :)
  • #6 5522685
    szelus
    Poziom 34  
    ad 2. To miałoby działać tak: w przerwaniu od OCR zmieniasz wartość OCR1A, w zleżności, czy masz bit 1 (wartość X), czy 0 (wartość (X+1)*2-1). Dodatkowo, dla bitu 1 ustawiasz flagę, aby przy następnym przerwaniu nic nie robić (poza zgaszeniem tej flagi).

    ad.1 Może to nawet prostsze rozwiązanie, w tym sensie, że masz zawsze dwa przerwania na bit.
  • #7 5522905
    ZbeeGin
    Poziom 39  
    szelus napisał:
    kuch_arc napisał:

    Potrzebuje zakodować bity uzywajac biphase maski. [...]
    Chcialbym do tego celu uzyc PWM wbudowanego w Timer1 na atmedze.

    Moim zdaniem tryb PWM to się do tego nie nadaje. Tutaj zmienia Ci się nie tyle wypełnienie, co częstotliwość nośnej.

    Oczywiście lepiej wykonać to z wykorzystaniem "normalnych" trybów pracy Timera (np. Compare Mode), choć w sumie dałoby się to zrobić także z wykorzystaniem PWM. Wiadomo nie w trybie Phase and Frequency Correct PWM (dual slope) tylko w trybie Fast PWM (single slope). Powód? Tryb dual slope środkuje przebieg. Rysunki w nocie katalogowej wyjaśnią o co chodzi.

    Zauważ, że występują tu jakby trzy stany PWM. 0% wypełnienia (stan niski), 50% wypełnienia (przebieg o dwukrotnej częstotliwości) i 100% wypełnienia (stan wysoki). Jest tylko kwestia zapisu do rejestru OCR, który to należy wyprzedzać aby system synchronicznego zapisu tego rejestru nie powodował błędów transmisji. Zatem w połowie poprzedniego stanu należy zapisać do OCR nową wartość.
    Drobną niedogodnością byłoby występowanie szpilek wyjściowych przy wypełnieniu 0%. Jeśli układ odbiorczy jest na nie uodporniony (nie reaguje na krótkie zmiany) to OK - da się.
  • #8 5523009
    Freddie Chopin
    Specjalista - Mikrokontrolery
    wg mnie natomiast cala ta zabawa z PWMami i jakimis dziwnymi trybami timera jest baz sensu...

    prosciej jest zgrac sie z sygnalem w fazie (przerwanie od zmiany stanu np) i nastepnie dokonywac probkowania pinu o czestotliwosci 2x wiekszej niz czestotliwosc sygnalu. probkowac nalezy miedzy tymi strzaleczkami ktore sa narysowane na gorze. algorytm dekodowania jest bardziej niz banalny:
    - z kazdego okresu mamy 2 probki
    - zrobic z nich XORa
    - wynik XORa jest bezposrednim wynikiem dekodowania.

    sygnal jest woooooooolny... 6400 bitow na sekunde, to wystarczy uruchomic timer'a, zeby sprobkowac to z 2x taka czestotliwoscia (oczywiscie odpowiednio trafiajac z pierwsza probka na 0.25 pierwszego okresu).

    algorytm kodowania rowniez bez sensu wg mnie bawic sie w PWMy, bo to same problemy imho sa. ustawic sobie przerwanie na 2x taka czestotliwosc, dorobic licznik liczacy od 0 do 1.
    jesli 0 - odczytac jeden bit sygnalu - jesli 1 - XOR wyjscia
    jesli 1 - XOR wyjscia
    zwiekszyc licznik i wyANDowac wszystko poza najmlodszym bitem - dzieki czemu liczy tylko od 0 do 1.

    cala idea otwarta jest oczywiscie na dalsze optymalizacje poprzez operacje bitowe, w koncu to nie ja mam to zrobic [;

    EDIT: pierwsza optymalizacja juz mi sie nasunela:
    jesli bit sygnalu == 1 albo jesli licznik == 1 - XOR wyjscia

    4\/3!!
  • #9 5525903
    kuch_arc
    Poziom 14  
    Przy odpowiednik zakodowaniu stanów, polowy i konca okresu danych, to jest zwykla funkcja OR. CTC zrobie na 2x bitrate i wtedy co przerwanie musze sprawdzac bit:
    
    if (bit&&position) { toggle_output; }
    
    .

    Teraz jak wyciagac te bity po kolei?
    Czy jesli bede mial tablice unsigned char na 8 bajtów, to moge przesuwac bity w calej tablicy? Moze jest do tego jakas funkcja? Chce cala paczke wysylac szeregowo.
  • #10 5526078
    Freddie Chopin
    Specjalista - Mikrokontrolery
    a pytanko jest tego typu

    czy jak masz np liczbe 00001111 jako pierwsza, to co pojdzie najpierw w kanal? LSB czy MSB?

    jesli LSB to sprawa jest extremalnie banalna:

    robisz sobie licznik, ktory wskazuje ci na to, ktory aktualnie BIT jest wysylany, z calego wielkiego lancucha bitow...

    wiedzac, ze dane masz w paczkach po 8 bitow mozesz sobie stworzyc prosta funkcje, ktora bedzie to pieknie robila. oto przyklad czegos dokladnie takiego.

    (pseudo C kod of kors)

    
    
    void przerwanie_od_timera(void)
    {
    	static char aktualne_slowo=0;
    	
    	if(globalny_index_bitowy>=globalna_dlugosc_calego_ciagu)
    		globalny_index_bitowy=0;		
    	
    	if(!(globalny_index_bitowy&0x7)) // 3 najnizsze bity adresuja bit w danym slowie, starsze bity adresuja slowo w tablicy
    		aktualne_slowo=globalny_wskaznik_na_poczatek_tablicy_danych[globalny_index_bitowy>>3];
    	
    	if(aktualne_slowo&(1<<(globalny_index_bitowy&0x7)))
    		// zrobic cos, co jest dla jedynki
    	else
    		// zrobic cos dla zera
    	
    	globalny_index_bitowy++;
    }
    


    jesli zas kod jest MSB first, to trzeba przy tym odwracaniu po prostu odjac ta wartosc od 7 (nie od 8!)

    4\/3!!
  • #11 5526540
    kuch_arc
    Poziom 14  
    Dzieki za odpowiedź, ale tak się zastanawiam, ile to sie bedzie wykonywać. Wiem, że C dla uP-ów powstało po to, żeby było łatwiej, ale chciałbym jakoś możliwie najmniej czasożernie to zrobić i żeby co odpalenie przerwania to się wykonywało tyle samo czasu.
    Jakieś przesuwanie bitowe, coś w tym stylu. Może by wczytywać z tej tablicy dane do jakieś temp zmienne po 1 bajcie i potem przesuwać i sprawdzać flage czy zmienić bajt czy też nie ?


    Pytanie jeszcze z innej beczki - bawił się ktoś wejściem mikrofonowym? Czy ono ma jakiś standard? Jakie napięcie, jaki prąd, takie tam ;).
  • #12 5526539
    kuch_arc
    Poziom 14  
    Dzieki za odpowiedź, ale tak się zastanawiam, ile to sie bedzie wykonywać. Wiem, że C dla uP-ów powstało po to, żeby było łatwiej, ale chciałbym jakoś możliwie najmniej czasożernie to zrobić i żeby co odpalenie przerwania to się wykonywało tyle samo czasu.
    Jakieś przesuwanie bitowe, coś w tym stylu. Może by wczytywać z tej tablicy dane do jakieś temp zmienne po 1 bajcie i potem przesuwać i sprawdzać flage czy zmienić bajt czy też nie ?


    Pytanie jeszcze z innej beczki - bawił się ktoś wejściem mikrofonowym? Czy ono ma jakiś standard? Jakie napięcie, jaki prąd, takie tam ;).
  • #13 5527249
    Freddie Chopin
    Specjalista - Mikrokontrolery
    jaknajbardziej mozesz to zrobic, ale uzyskanie idealnie rownego czasu wykonywania sie przerwan jest... niemozliwe w C. jesli tak chcesz, to ASM. mam jednak dla ciebie inna propozycje.

    caly kod - ten powyzej lub wlasny - przesunac do maina i liczy on kolejna probke, wystawia ja do jakiejs zmiennej globalnej, ustawia flage i czeka az flaga zgasnie. przerwanie odbiera bajcik, wystawia go na port i gasi flage. tym sposobem, bez zbednych kombinacji masz idealnie rowno wysylane probki...

    niemniej jednak wciaz uwazam, ze to sztuka dla sztuki. jesli sygnal ma miec 6400bps, a twoj procek bedzie chodzil na - dajmy na to - 10MHz, to jaka to roznica, czy sie czasem przesunie sygnal o te 10 taktow w prawo czy w lewo... 10 taktow stanowi ok 0,5% czasu trwania pojedynczego bitu, wiec...

    twoje rozwiazanie - z rotacja do jakiejs flagi - jest bardzo sensowne, ale jak zwykle tutaj klania sie ASM. w C nie zrobisz wyrotowywania jednego bitu do Carry, bo C nie wie co to Carry <:

    4\/3!!
  • #14 5527405
    kuch_arc
    Poziom 14  
    Dokladnie tak mysle to zrobic :). I chyba faktycznie nie omine tych przesuniec. Pseudo kod co go wymyslilem wyglada tak:
    
    ISR_INTERRUPT()
    {
    
    if FLAG
     read bajt(i);
     if (bit && pos) toggle_output;
     i++;
     if (i==8) 
        i=0; clear FLAG; 
    }
    
    int main()
    {
    init_wszystko();
    
    while(1)
       {
           recieve_packets();
           if PACKETS_OK set FLAG;
               else 
                set FLAG 
                for j=0;j++;j<=7
                   data[j]=0;   // zeby zawsze wysylal cos, chocby zera to bede
                                   //wiedzial ktora z 3 probek wziac, bo mam        
                                   //nadzieje bede mial 3 wiecej
                                   //probek  niz potrzebuje.         
        }
    }
    


    Kolejne pytanie - jaki jest latwy i szybki w ilosci taktow sposob na sprawdzenie spojnosci ramki? Jakby ktos sie podzielil przykladem bylbym wdzieczny.
  • #16 5541592
    kuch_arc
    Poziom 14  
    Kurde.. mozdze i mozdze ale nie wiem jak odczytywac bity z bajta po kolei? Nie pisalem duzo w C, wiem ze to nie jest trudne, ale nie mam pojecia jak to zrobic.. jakis wskaznik i potem go przesuwac?

    Jesli ktos bylby tak uprzejmy i wyjasnil n00bkowi taka base operacje na bajcie jak przesuwanie i wypluwanie bitow.

    Myslalem o masce, iloczynie logicznym i wtedy mialbym dany bit, ale to moze troche za dlugo trwac.

    Mam cos takiego, wszelkie uwagi mile widziane.
    
    ISR(TIMER1_COMPA_vect){
    
     position = !position;   // change the period 0- halfway , 1 - end this allows the truth table for output to be just OR func.
     if (flag){
    	bit = tab & 0x01;	 // ustawienie maski, wtedy bedzie albo 1 albo 0 na LSB
    	if (bit && position){
    	    PA0 = !PA0;	    
    	 } 	
    	tab << 1;
     } 
       
    }
    
  • #17 5542543
    Freddie Chopin
    Specjalista - Mikrokontrolery
    eee....

    
    for(i=0;i<7;i++)
    {
    if(dana&(1<<i))
    ... cos dla jedynki
    else
    ... cos dla zera
    }
    


    mozna tez kombinowac prosciej, np:

    
    for(jak wyzej)
    {
    bit=dana&1;
    dana>>=1;
    ...
    }
    


    4\/3!!
  • #18 5542564
    kuch_arc
    Poziom 14  
    
    
    volatile unsigned int position = 1, incr = 0, bit, tFLAG=0, tab;	
    volatile unsigned char *dBytes;   
    volatile unsigned int ik= 0, byte_no = 0;
    
    ISR(TIMER1_COMPA_vect){
     
     position = !position;   // jak zmotac zmienna bool w AVR C??
    						
     if (tFLAG){
    	bit = tab & 0x01;	 // ustawienie maski, wtedy bedzie albo 1 albo 0 na LSB
    	if (bit && position){
    	    PA0 = ~PA0;	     // jak zrobic dobry output toggle ???
    	 	} 	
    	tab >> 1;
    	incr--;
    	if (incr==0){
    		incr=7;
    		byte_no++;	
    		tab= dBytes[byte_no];
    		if (byte_no>7){
    			tFLAG=0;
    			byte_no=0;
    		4 x }
    
    a potem w main
    if RF_TRANS_COMPLETE
      {
          tFLAG=1;
    	  tab = dBytes[0];
       }
    


    Ten wczesniejszy to podczas pracy wkleiłem. Koniec koncow wyszlo to co sie obawialem - w ciul if'ow i ogolnie duzo taktow :/. W komentach sa tez zapytania co do poniektorych watpliwosci...

    W Twoim poscie nie rozumiem zapisu
    
    bit=dana&1; 
    dana>>=1;
    ??
  • #20 5543071
    kuch_arc
    Poziom 14  
    Czyli wtedy to co by mi wychodzilo na carry wysylalbym na pin wyjscia ??
    Nie skojarzylem zapisu skroconego >>= ;)
  • #21 5543090
    Freddie Chopin
    Specjalista - Mikrokontrolery
    z grubsza tak, pozatym ze Carry raczej nie da sie przepisac sensownie, za to mozna je sprawdzic i wykonac skok, badz nie... niestety jeszcze w zadnym kompilatorze nie zauwazylem mozliwosci wykorzystania C do czegokolwiek, wiec tylko ASM <:

    anyway - to by byly w zasadzie 6 instrukcje w asm, wiec na wstawke jak znalazl
    1. wyrotowac bit z danej
    2. sprawdzic carry - jesli 1 skoczyc do 5.
    3. zrobic cos co powinno byc wykonane dla bitu==0
    4. skoczyc do 6.
    5. zrobic cos co powinno byc wykonane dla bitu==1
    6. cokolwiek [; wlacznie z niczym (etykieta bez opcodu).

    tutaj dodam, ze punkt 3 i 5 moze byc napisany w C, choc zasadniczo moze to byc problematyczne... kompilatorowi sie to na pewno nie spodoba i nie wiadomo co tam nawymysla, wiec lepiej tylko w ASM to zrobic. mozna tez punkt 3 i 5 zapisac jako osobne funkcje, ale to jest pomylka, bo po co optymalizowac, skoro wywolywane sa osobne funkcje, ktorych wywolanie i powrot trwa 4x tyle cykli ile zaoszczedzono optymalizacja...

    anyway - walcz, rozwiazan jest wiele.

    4\/3!!
  • #22 5544040
    kuch_arc
    Poziom 14  
    Cytat:

    1. wyrotowac bit z danej // mozesz napisac jak to zrobic w ASM?
    2. sprawdzic carry - jesli 1 skoczyc do 5.
    3. zrobic cos co powinno byc wykonane dla bitu==0
    4. skoczyc do 6.
    5. zrobic cos co powinno byc wykonane dla bitu==1
    6. cokolwiek [; wlacznie z niczym (etykieta bez opcodu).
  • #23 5544065
    Freddie Chopin
    Specjalista - Mikrokontrolery
    ej no juz nie przesadzaj...

    po 1 nie znam w ogole assemblera AVR, bo uzywam innych prockow
    po 2 to chyba jestes w stanie znalezc w datasheecie instrukcje ktora nazywa sie shift albo rotate (obojetne)

    4\/3!!
REKLAMA