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

ATMEGA8, asembler drobny problem

23 Lut 2007 23:25 3603 21
  • Poziom 29  
    Witam, mam drobny problem z programem na ATMEGA8. RXD i TXD podłączone są pod kostke SN75176 która wysyła na szyne RS485, pinem PD4 przełączam tryb pracy kostki (1- nadawanie, 0 - odbieranie).
    Kwarc 4MHz

    Program ma wysyłać wartość 97 na szynę przez USART. Kod programu poniżej:

    Kod programu poniżej:

    Code:

    .include "m8def.inc"
    .cseg
    .org 0x00

    ;### WEKTORY PRZERWAŃ ###
    rjmp reset

    .org 0x1B
    rjmp odbierz

    reset:

    ldi r16, LOW(RAMEND)
    out SPL, r16

    ldi r16, HIGH(RAMEND)
    out SPH, r16

    ldi r16, 255

    out ddrd, r16
    ldi r16, 0
    out portd, r16

    ldi r16, 255
    out ddrb, r16
    ldi r16, 0
    out portb, r16

    cli


    ;# konfiguracja usart
    ldi r17, high(51)
    ldi r16, low (51)
    out ubrrh, r17
    out ubrrl, r16


    ldi r16, (1<<ursel)|(1<<ucsz1)|(1<<ucsz0)

    out ucsrc, r16

    ldi r16, (1<<rxcie)|(1<<rxen)|(1<<txen)
    out ucsrb, r16

    ;# konfiguracja adc
    ldi r16, (1<<refs1)|(1<<refs0)|(1<<adlar)
    out admux, r16

    ldi r16, (1<<aden)|(1<<adsc)|(1<<adfr)|(1<<adps2)|(1<<adps1)|(1<<adps0)
    out adcsra, r16

    sei

    ldi r20, 97

    petla:

    rcall wyslij

    rjmp petla

    wyslij:
    sbi portd, 4
    ldi r16, (0<<rxcie)|(1<<rxen)|(1<<txen)
    out ucsrb, r16

    sbis ucsra, udre
    rjmp wyslij

    nop
    nop
    nop
    nop
    nop
    nop
    nop

    out udr, r20
    aaa:
    sbis ucsra, udre
    rjmp aaa

    cbi portd, 4
    ldi r16, (1<<rxcie)|(1<<rxen)|(1<<txen)
    out ucsrb, r16

    ret

    odbierz:
    wroc: reti


    Dziwna rzecz dzieje sie w tym miejscu:
    Code:
    ldi r20, 97
    
    petla:

    Mikrokontroler w obecnej postaci programu nie wysyła 97 tylko inne wartosci np 82, 133.
    Natomiast gdy wrzuce ldi r20, 97 do petli "petla" program działa dobrze.

    Code:
    petla:
    
    ldi r20, 97


    Strasznie mnie to dziwi, bo wynika z tego, że po wywołaniu procedury wyslij modyfikowane jest r20, ale gdzie i dlaczego? Gdy wrzuce ta procedure do petli a ldi r20, 97 zostawie za petla wtedy równiez działa dobrze. W czym moze tkwić problem?

    Z góry dziekuje za pomoc

    Pozdrawiam
    Paweł
  • Poziom 33  
    Nie wnikając na razie w treść pętli po resecie powinienes ustawić stos tak:

    RESET:
    LDI R16, HIGH(RAMEND) ; Init SP
    OUT SPH, R16
    LDI R16, LOW(RAMEND)
    OUT SPL, R16

    Pzdr. N.
  • Poziom 42  
    Witam,

    używasz zdaje się prędkości 4800 przy tym kwarcu tak? - sprawdź więc dobrze czy w odbiorniku masz taką samą.

    Poza tym zajrzyj sobie do noty katalogowej ATmega8 tam są pokazane ładnie procedurki w asemblerze jak inicjalizować oraz jak odbierać lub nadawać - wydaje mi się, że powinno ci się wtedy wyjaśnić bo tu masz coś pogmatwane. W nocie sekcja UART.

    ... dodasz tylko swoje sterowanie dla RS485 i na pewno będzie działać - ja też to tak robiłem na RS485 i na początku skorzystałem z kodu pokazanego w nocie - ruszyło od razu

    Cytat:
    ldi r16, (1<<rxcie)|(1<<rxen)|(1<<txen)
    out ucsrb, r16

    ten fragment kodu powyżej napisz tylko raz w inicjalizacji a nie ciągle w pętli (zresztą jak mówię w nocie jest też ładnie pokazana w asm inicjalizacja - i wszystko stanie się jasne podejrzewam)

    pozdrawiam
  • Poziom 29  
    mirekk36 napisał:
    Witam,

    używasz zdaje się prędkości 4800 przy tym kwarcu tak? - sprawdź więc dobrze czy w odbiorniku masz taką samą.


    Taka sama, sprawdzam w terminalu co uC wysyła.

    mirekk36 napisał:

    Poza tym zajrzyj sobie do noty katalogowej ATmega8 tam są pokazane ładnie procedurki w asemblerze jak inicjalizować oraz jak odbierać lub nadawać - wydaje mi się, że powinno ci się wtedy wyjaśnić bo tu masz coś pogmatwane. W nocie sekcja UART.


    wiem jak odpalic usart i w jednej petli wszystko działa;) nie wiem tylko skad sie bierze ta zmiana rejestru r20 po wywołaniu procedury bo nic takiego w kodzie nie ma

    ... dodasz tylko swoje sterowanie dla RS485 i na pewno będzie działać - ja też to tak robiłem na RS485 i na początku skorzystałem z kodu pokazanego w nocie - ruszyło od razu

    mirekk36 napisał:

    Cytat:
    ldi r16, (1<<rxcie)|(1<<rxen)|(1<<txen)
    out ucsrb, r16

    ten fragment kodu powyżej napisz tylko raz w inicjalizacji a nie ciągle w pętli (zresztą jak mówię w nocie jest też ładnie pokazana w asm inicjalizacja - i wszystko stanie się jasne podejrzewam)

    pozdrawiam


    To nie ma znaczenia, spadek po innej wersji programu w ktorej blokowałem przerwanie od uarta po odebraniu przychodzacego znaku ;) dlatego w innym miejscu w petli jest (0<<rxcie)

    Dzieki za pomoc i nadal czekam na wskazówki
    Paweł

    Dodano po 2 [godziny] 46 [minuty]:

    Moge sie odwdzieczyć dużą ilością punktów za pomoc :)
  • Poziom 42  
    ok to napisz krótko i zwięźle jeszcze raz cały fragment swojego kodu bez tych rzeczy co pozostały w spadku (wiesz? żeby łatwiej to czytać) ;) i na spokojnie rzucę jeszcze raz okiem ok?

    Dodano po 1 [godziny] 3 [minuty]:

    hmmm a możesz tak narazie na próbę bo i tak tylko wysyłasz nie robić cbi portd, 4 - może za szybko to następuje?
  • Poziom 29  
    Raczej nie nastepuje to za szybko bo mam w kodzie
    out udr, r20
    aaa:
    sbis ucsra, udre
    rjmp aaa

    cbi portd, 4

    i cbi pord, 4 wykonywane jest dopiero po wysłaniu bajtu, który znajduje się w r20, dopóki bajt jest wysyłany program skacze od aaa: do rjmp aaa poniewaz bit udre w rejestrze ucsra jest ustawiany dopiero gdy bufor nadawczy jest opróżniony i nadawanie jest skończone

    Dodano po 2 [minuty]:

    mirekk36 napisał:
    ok to napisz krótko i zwięźle jeszcze raz cały fragment swojego kodu bez tych rzeczy co pozostały w spadku (wiesz? żeby łatwiej to czytać) ;) i na spokojnie rzucę jeszcze raz okiem ok?


    Zaraz okroje kod i przetestuje i wrzuce na forum. Sprawdze tez co sie dzieje w symulatorze w AVR studio.
  • Poziom 39  
    Elektrooonik napisał:
    ...Mikrokontroler w obecnej postaci programu nie wysyła 97 tylko inne wartosci np 82, 133.
    Natomiast gdy wrzuce ldi r20, 97 do petli "petla" program działa dobrze.
    ...

    Nie napisałeś dokładnie , co oznacza "tylko inne wartosci np 82,133".
    Czy procek po zresetowaniu generuje nonstop 82 , a po następnym resecie 133 , czy procek pracuje cały czas , a Ty wciskasz Connect/Disconnct w terminalu.Zapuściłem Twój programik na swojej M8 i jedynie jeśli się Źle "wstrzelę" z połączeniem terminala , to widzę (lub nie) w oknie terminala co raz to inną literkę/znak.Natomiast jak wyłączę proca , uruchomię terminal , wcisnę connect i uruchomię proca , to bez względu na to czy jednokrotnie załaduję R20 , czy też dam to w pętli , to na terminalu jest zawsze to , co ma być.Jedyne co zmieniłem , to baudrate na 19200 , bo mam zegar systemowy 12MHz.Jeśli dołożę pętlę ze zwłoką w pętli głównej , to nie udaje mi się w żaden sposób rozsynchronizować transmisji ;)
    Code:

    ;...
       ldi r20, 0x41
    petla:
       rcall wyslij
       rcall wait
       rjmp petla

    wait:
       clr r0
       clr r1
       ldi r22,64 ; ~ 1s dla 12MHZ
    _r0:
       dec r0
       brne _r0
       dec r1
       brne _r0
       dec r22
       brne _r0
    ret

    wyslij:
    ;...

    Jestem przekonany , że ma tu miejsce błąd w transmisji , a nie "nieautoryzowana" :D zmiana zawartości rejestru r20.

    Piotrek
  • Poziom 42  
    po wyrzuceniu zbędnych rzeczy z tej procedury wyslij i przeanalizowaniu tego ;) wynika, że absolutnie obojętnie gdzie nie wstawisz ldi R20, 97 - czy przed pętlą czy w pętli to nie powinno mieć najmniejszego znaczenia

    dziwi mnie, że napisałeś:
    Cytat:
    Gdy wrzuce ta procedure do petli a ldi r20, 97 zostawie za petla wtedy równiez działa dobrze


    co to ma oznaczać? tzn chyba to że dajesz to zanim wejdziesz do pętli tak?

    - tak czy inaczej - albo czegoś jeszcze nie opisałeś, albo może jeszcze jakieś inne przerwanie ci działa, które może używa rejestru R20, albo na końcu się okaże, że to nic związanego z tym kodem a problem leży gdzie indziej.

    co do tego cbi portd, 4 to dobrze się orientuję, że zerujesz linię gdy bufor nadawczy jest juz pusty ale być może nie wiesz jeszcze, że w przypadku SN75176 istnieją czasem ważne zależności czasowe jeśli chodzi o zmianę stanu tego sygnału i ja tu troszkę być może upatruję błędu, który polega na tym, że może nie jest tak iż zmienia ci się gdzieś zawartość R20 tylko poprostu w wyniku tej bardzo szybkiej zmiany stanu tej linii dzieją się dziwolągi podczas transmisji - ale to tylko przypuszczenia i gdybys to sprawdził usuwając narazie to cbi to byłoby mozna myśleć dalej co się tam u ciebie dzieje ;) - problem mnie o tyle interesuje, ze porocedura prosta jak drut i nie powinna nie działać ;)
  • Poziom 29  
    Dzieki chłopaki za zaangażowanie, sprawdzam własnie wszystkie możliwości jak odkryje coś nowego odezwę się w tym temacie niebawem.
  • Poziom 39  
    Powiedz jeszcze z łaski swojej , co to za wektor :?: ;) :D
    Code:

    .org 0x1B
    rjmp odbierz

    Bo jeśli terminal odsyła echo , .... ;)

    Piotrek
  • Poziom 29  
    Wielkie dzieki Zumek za zwrócenie uwagi, miało być 0B a nie 1B, nie wiem skąd to się wzięło :)

    Chociaż w tym programie i tak to nic nie zmieni.
  • Poziom 42  
    a tak przy okazji nie lepiej zamiast opisywać wektory wartościami w hexie to otworzyć sobie na sekundkę plik definicji procka którego się używa w tym przypadku m8def.inc i stamtąd zassać sobie zdefiniowane nazwy wektorów - dzięki temu naprawdę trudno później sobie coś popsuć a na dodatek bardzo przejrzyście to wygląda np:

    ;**************************************
    .CSEG ;
    .ORG 0 ;
    rjmp RESET ; skok do miejsca w programie bezpośrednio po RESECIE

    ;
    ;********** definicje wektorów przerwań dla procesora ATmega8
    ;
    .org INT0addr ;
    reti ;
    .org INT1addr ;
    reti ;
    .org OC2addr ;
    reti ;
    .org OVF2addr ;
    reti ;
    .org ICP1addr ;
    reti ;
    .org OC1Aaddr ;
    reti
    .org OC1Baddr ;
    reti ;
    .org OVF1addr ;
    reti ;
    .org OVF0addr ;
    reti ;
    .org SPIaddr ;
    reti ;
    .org URXCaddr ;
    reti ;
    .org UDREaddr ;
    reti ;
    .org UTXCaddr ;
    reti ;
    .org ADCCaddr ;
    reti ;
    .org ERDYaddr ;
    reti ;
    .org ACIaddr ;
    reti ;
    .org TWIaddr ;
    reti ;
    .org SPMRaddr ;
    reti ;
  • Poziom 29  
    Witam ponownie, wpadłem już w całkowitą konsternację. Testuje ten program na rózne sposoby, wywalam poszczególne fragmenty i jestem coraz bardziej zdziwiony.

    Obecnie kod mam taki:

    Code:

    .include "m8def.inc"
    .cseg
    .org 0x00

    ;### WEKTORY PRZERWAŃ ###
    rjmp reset

    .org 0x0B
    reti

    reset:

    ldi r16, LOW(RAMEND)
    out SPL, r16

    ldi r16, HIGH(RAMEND)
    out SPH, r16

    ldi r16, 255

    out ddrd, r16
    ldi r16, 0
    out portd, r16

    ldi r16, 255
    out ddrb, r16
    ldi r16, 0
    out portb, r16

    cli


    ;# konfiguracja usart
    ldi r17, high(51)
    ldi r16, low (51)
    out ubrrh, r17
    out ubrrl, r16


    ldi r16, (1<<ursel)|(1<<ucsz1)|(1<<ucsz0)

    out ucsrc, r16

    ldi r16, (0<<rxcie)|(0<<rxen)|(1<<txen)
    out ucsrb, r16



    sbi portd, 4
    ldi r20, 97

    petla:

    rcall wyslij

    rjmp petla

    wyslij:

    sbis ucsra, udre
    rjmp wyslij
    out udr, r20
    ret



    W terminalu odbieram albo 133, albo 88 albo czasami własnie 97. Ale cały czas ta sama wartosc. TZn: robie connect i odbieram cały czas 133, rozłaczam sie, łacze ponownie (procka nie resetuje) i dostaje 88.

    Dlaczego nie wysyła 97?
  • Poziom 39  
    To teraz napisz , jak masz ustawione fusiki ;)
    Sprawdziłem Twój kod w procu i VMLab-ie (właśnie VMLab "zauważył" błąd wektora) i wszystko działa jak należy.Spróbuj jak mówię , terminal na connect i dopiero po tym zasil procka.Następnie wyłącz zasilanie i ponownie włącz.Cudów nie ma - a może są :?: ;)

    Piotrek
  • Poziom 29  
    Gdy robie tak jak mówisz w jednym terminalu jest ok, dostaje 97 a drugi na zmiane, raz 97 raz cos innego. Jak to zinterpretowac?

    Pytasz o fusy, załaczam screen:
    ATMEGA8, asembler drobny problem
  • Poziom 39  
    Czy w terminalach masz takie same ustawienia transmisji :?:
    Liczba bajtów na sekundę:4800
    Bity danych :8
    Parzystość :brak
    Bity stopu :1
    Sterowanie przepływem :brak

    Piotrek

    PS
    Fusiki ok :D
  • Poziom 42  
    hmmm fusy masz ustawione dla High Freq Resonator (1111) - czyli tak jak pisze kolega powyżej powinno działać na rezonatorze ale na początku pisałeś że masz rezonator 4MHz to powinieneś mieć teoretycznie ustawione dla Low Freq Resonator (1011) albo Medium Freq Resonator (1101)

    hmmm ciekawe czy dlatego ? może jednak są jakieś zakłócenia transmisji i czasem jest ok a czasem jest dobrze - ale to trza by było sprawdzić - czyli ustawić je inaczej
  • Poziom 30  
    masz tak:
    Code:
    ldi r17, high(51)
    
    ldi r16, low (51)
    out ubrrh, r17
    out ubrrl, r16

    a dokumentacja mówi tak:
    Code:
    • Bit 7 – URSEL: Register Select
    
    This bit selects between accessing the UCSRC or the UBRRH Register. It is read as
    one when reading UCSRC. The URSEL must be one when writing the UCSRC.
    Więc to twoje zapisywanie do ubrrh nie działa wcale.
    Ale to jeszcze nie to - analizuje dalej.
    ------------------------------------
    I jeszcze jedno - wstaw cała kompletną tablicę wektorów w której wszystkie nie używane wpisz reti - to żeby wyglądało ładniej.
  • Poziom 42  
    kolego szymtro tak tylko zapytam - dlaczego twierdzisz, że ta inicjalizacja którą robi kolega autor ma nie działać? skoro nawet gdy zajrzysz sobie do noty pdf to można tam zobaczyć:

    Cytat:
    Assembly Code Example(1)
    USART_Init:
    ; Set baud rate
    out UBRRH, r17
    out UBRRL, r16
    ; Enable Receiver and Transmitter
    ldi r16, (1<<RXEN)|(1<<TXEN)
    out UCSRB,r16
    ; Set frame format: 8data, 2stop bit
    ldi r16, (1<<URSEL)|(1<<USBS)|(3<<UCSZ0)
    out UCSRC,r16
    ret


    i ja też zawsze tak robię i wszystko działa jak najlepiej
  • Poziom 30  
    Wklejasz nie pełny kod, zapuść tłumaczenie tego bitu ursel z pdf'a.
    ...
    To znaczy tyle że ten bit wybiera czy zapisując pod adres rejestru ucsrc zapisujemy tam czy (=0) zapisujemy do ubrrh. Domyślnie ten bit jest 1 i jeżeli tego nie zmienisz to zapis do rejestru ubrrh tak naprawdę zapisze do ucscr. Takich numerów w M8 jest chyba 4.
    Cytat:
    The UBRRH Register shares the same I/O location as the UCSRC Register. See the
    “Accessing UBRRH/UCSRC Registers” on page 148 section which describes how to
    access this register.

    A to że ci działa ...
    -----------------------------------------
    Zgodze się z następnym postem - faktycznie zadziała - chyba ze ktoś spróbuje tam wpisać >127 wtedy nie zadziała i zapisze do ucsrc.
    W takim razie uwaga dla asm'owców na pozostałe 3 numery.
  • Poziom 42  
    nie nie ... poczekaj - to że mi działa czy innym działa nie wynika z przypadku bo jeśli napiszę

    ldi R16, High(51)
    out UBRRH, R16

    to zauważ, że w bit0 w UBRRH będzie = 0 tak?

    a jeśli robię zapis:

    ldi r16, (1<<URSEL)|(1<<USBS)|(3<<UCSZ0)
    out UCSRC, r16

    to w trakcie zapisu wartość bitu 0 = 1 zgadza się?

    poza tym przejrzyj sobie jaką maksymalną wartość może osiągnąć cały rejestr UBRR nawet dla wartości rezonatora 20MHz - 1041

    tak więc nawet w takim przypadku:

    ldi R16, High(1041)
    out UBRRH, R16

    wartość bitu 0 UBRRH przy zapisie będzie = 0 co wcale nie przypadkowo spowoduje, że zapis będzie do właściwego rejestru

    zgodzisz się z tym?

    Dodano po 10 [minuty]:

    Cytat:
    chyba ze ktoś spróbuje tam wpisać >127 wtedy nie zadziała i zapisze do ucsrc

    no tak ale żaden asm-owiec jak napisałeś nie wpisze tam czyli do UBRRH wartości w której bit0 = 1 - bo to jest bez sensu a co ważniejsze - jest w nocie tabela z której można pobierać wartości do UBRR - można te wartości nawet w prosty sposób wyliczać na etapie kompilatora i też nigdy nie ma przypadku aby zadając odpowiednie wartości prędkości dla portu RS232 pojawił tam się bit0=1

    w tym konkretnym przypadku wartość R16 będzie zawsze równa ZERO jeśli napiszemy ldi R16, High(51)

    jak się już pisze w asemblerze to pisze się już z pełną świadomością tego co się robi - nie myśli za nas kompilator

    Dodano po 24 [minuty]:

    oczywiście wszędzie gdzie powyżej pisałem o bicie0 robiłem małą pomyłkę bo chodzi o bit7 ;) ale to absolutnie nie zmienia tego co opisałem - wręcz potwierdza tylko bardziej - ponieważ gdyby ktoś chciał tak całkiem przypadkiem nawet jak pisze kolega szymtro wpisać tam taką wartość aby bit7 był równy JEDEN to musiałby chcieć wpisywać do 16bitowego rejestru UBRR wartość większą niż 32768 - a to jak też już wcześniej pisałem jest absolutnym nonsensem ;) - gdzie podałem przykład z noty dla kwarca 20MHz i tak ta wartość może osiągnąć 1041

    myślę, że ATMEL dobrze to przemyślał i nie jest to jakąś ich pomyłką czy pułapką dla programistów


    .... no tak ale czy autorowi coś w końcu się wyjaśniło z jego problemem???
  • Poziom 33  
    Nie wnikając na razie w treść pętli po resecie powinienes ustawić stos tak:

    RESET:
    LDI R16, HIGH(RAMEND) ; Init SP
    OUT SPH, R16
    LDI R16, LOW(RAMEND)
    OUT SPL, R16

    Pzdr. N.