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

[ATTiny26][ASM] Programowy UART

17 Gru 2010 18:02 1973 20
  • Poziom 9  
    Witam

    Pisałem już w innym dziale na podobny (łączący się problem) z działaniem wyjścia z TxD z układu, jednak udało mi sie go rozwiązać, więc stanąłem przed obliczem drugiego problemu (chyba).
    Jestem w trakcie poszukiwania błędu w transmisji szeregowej, na chwile obecną wysył.
    Nie używam przerwań, timerów itd, bo wszystko może działać po chamsku, z kodem opóźniającym wkodowanym.

    ilosc_bitow=bit_startu+bity_danych+[ewentualny]bit_parzystosci+bity_stopu[1 lub 2]
    Algorytm wygląda mniej więcej tak:
    1. Ustawiam 0 na TxD (bit startu) i czekam FREQUENCY/(BAUD*ilosc_bitow) cykli
    2. Sprawdzam czy bit na najmłodszej pozycji jest równy 0 lub 1 i adekwatnie ustawiam 1->1, 0->0 stan na TxD, czekając odpowiedni czas.
    3. Przesuwam daną w prawo o bit
    4. Zmniejszam licznik danych wysłanych, jeżeli wysłałem komplet (bity_danych) to ide dalej, jeśli nie wracam do 2.
    5. Wysyłam bit parzystości, który licze przy okazji w krokach 2-3 i znowu czekam [krok opcjonalny, jeżeli bitu nie ma to go nie wykonuje]
    6. Wysyłam odpowiednią ilość bitów stopu, stan 1
    7. Wychodze z procedury.

    Czy gdzieś robie błąd?

    W AVRStudio zmiany stanu na bicie wyjściowym wyglądają na odpowiednie, czasy np dla BAUD ustawionego na 2400 i zegarze 4MHz wynoszą 414,5 us, czyli mam 2,1 us błędu, czyli jakieś 0,5%.
    Jeśli ktoś, miałby ochotę sprawdzić kod, to wkleję go, ale nie chce tego robić od razu, żeby nikogo nie odstraszyć, bo troszkę tego jest.

    Pozdrawiam
  • PCBway
  • Pomocny post
    Poziom 32  
    Wstaw kod bo schemat blokowy wydaje sie poprawny.
  • Poziom 9  
    Inicjalizacja:
    Code:

    ; czestotliwosc kwarca
    .equ UARTSOFT_FREQ = 4000000
    ; ilosc bitow
    .equ UARTSOFT_DATABITS  = 8
    .equ UARTSOFT_STOPBITS  = 2
    .equ UARTSOFT_PARITY    = 0
    ; predkosc baudowa, poczatkowo zle zrozumialem baud, dlatego musze przyspieszyc transmisje o ilosc bitow
    .equ UARTSOFT_BAUD      = 9340*(UARTSOFT_DATABITS+UARTSOFT_STOPBITS+1+INT(UARTSOFT_PARITY>0))
    (...) ; dodatkowo kopiowanie pierwszego znaku z pamieci programu do SRAM
       LDI R29, BYTE2(buf)
       LDI R28, BYTE1(buf)
          
       LDI R31, BYTE2(OKTAB<<1)
       LDI R30, BYTE1(OKTAB<<1)

       LPM
       ST Y,R0      
       LDI R16,1

       LDI R31, BYTE2(buf)
       LDI R30, BYTE1(buf)
       RCALL UARTSOFT_WRITE
    (...)
    .cseg
    .org 0x0025F
       OKTAB:  .DB 'O','k','!',10,13
       NOTAB:   .DB 'N','o','?',10,13
    .dseg
    .org 96
       buf:   .DB 0

    Chciałem przesłać cały tekst, ale teraz na starcie męczyłem 1 znak.
    Code:

    .ifndef UARTSOFT_FREQ
       .ERROR "Please define UARTSOFT_FREQ"
    .endif
    .ifndef UARTSOFT_BAUD
       .ERROR "Please define UARTSOFT_BAUD"
    .endif
    .ifndef UARTSOFT_DATABITS
       .ERROR "Please define UARTSOFT_DATABITS [1-8]"
    .endif
    .ifndef UARTSOFT_STOPBITS
       .WARNING "Please define UARTSOFT_STOPBITS [1-2]"
       .WARNING "UARTSOFT_STOPBITS was sets to 1"
       .equ UARTSOFT_STOPBITS = 1
    .endif
    .ifndef UARTSOFT_PARITY
       .WARNING "Please define UARTSOFT_PARITY [0-2], 0-none, 1-odd, 2-even"
       .WARNING "UARTSOFT_PARITY was sets to 0"
       .equ UARTSOFT_PARITY = 0
    .endif
    ; potrzebne do obliczenia ilosci petli czekajacych
    .equ UARTSOFT_LONGEST_INSTR = 15 + 7
    ; ilosc petli czekajacych, to jest do wyrownania czasu
    .equ UARTSOFT_BIG_LOOPS =  ((UARTSOFT_FREQ - UARTSOFT_LONGEST_INSTR*UARTSOFT_BAUD)/(UARTSOFT_BAUD*256))
    .equ UARTSOFT_WAIT_CYCLES = INT(UARTSOFT_FREQ / UARTSOFT_BAUD) - UARTSOFT_BIG_LOOPS * 256 - UARTSOFT_LONGEST_INSTR
    .equ UARTSOFT_SMALL_LOOPS = INT(UARTSOFT_WAIT_CYCLES/3)
    .equ UARTSOFT_SMALL_LOOPS_REST = UARTSOFT_WAIT_CYCLES % 3


    .if UARTSOFT_SMALL_LOOPS<1
       .if UARTSOFT_BIG_LOOPS==0
          .ERROR "Speed of processor is too low."
       .endif
    .endif
    .if INT(UARTSOFT_BIG_LOOPS) > 255
       .if INT(UARTSOFT_BIG_LOOPS) == 256
          UARTSOFT_BIG_LOOPS = 0
       .else   
          .ERROR "Speed of processor is to high, increse UARTSOFT_BAUD"
       .endif
    .endif
    ; jezeli to sobie odkomentujemy to w symulatorze wylaczymy proces czekania
    ;.equ UARTSOFT_WAIT_DEBUG = 1
    ; uniwersalna funkcja czekajaca, wstawiam ja pomiedzy bitami usarta
    .ifndef UARTSOFT_WAIT_DEBUG
    UARTSOFT_WRITE_WAIT_15:
       .if UARTSOFT_BIG_LOOPS>0
          LDI R21,UARTSOFT_BIG_LOOPS
             LDI R22,84
                DEC R22
             BRNE PC-1         
             NOP
             DEC R21
          BRNE PC-5

          LDI   R21,UARTSOFT_SMALL_LOOPS
             DEC R21
          BRNE PC-1   
          .if UARTSOFT_SMALL_LOOPS_REST > 0
             NOP
          .endif
          .if UARTSOFT_SMALL_LOOPS_REST > 1
             NOP
          .endif
       .else
          LDI   R21,UARTSOFT_SMALL_LOOPS
             DEC R21
          BRNE PC-1
          .if UARTSOFT_SMALL_LOOPS_REST > 0
             NOP
          .endif
          .if UARTSOFT_SMALL_LOOPS_REST > 1
             NOP
          .endif   
       .endif
       RET
    .endif

    ; sending from Z, R16 signs
    UARTSOFT_WRITE:
       SBI DDRB,DDB1 ; pin TxD
       CBI DDRB,DDB0 ; pin RxD
    UARTSOFT_WRITE_LOOP:
       ; mozna zanegowac sygnal wyjsciowy dyrektywa, szukalem bledu dlatego to dodalem
       .ifndef UARTSOFT_NEGATIVE
          CBI PORTB,PORTB1
       .else
          SBI PORTB,PORTB1
       .endif
       NOP
       NOP   
       

       LD R17,Z   ; zrodlo
       MOV R18,R17   ; kopia zrodla
       LDI R19,UARTSOFT_DATABITS   ; licznik
       .if UARTSOFT_PARITY != 2
          LDI R20,0   ; parity, even
       .else
          LDI R20,1   ; odd
       .endif
       
       ; czekanie dla bitu startowego
       .ifndef UARTSOFT_WAIT_DEBUG
          RCALL UARTSOFT_WRITE_WAIT_15
       .endif
       ; koniec czekania dla bitu startowego

       LDI R19,UARTSOFT_DATABITS
       UARTSOFT_WRITE_DATA_LOOP:
          MOV R17,R18
          ANDI R17,1
          BRNE PC+4
             NOP
             .ifndef UARTSOFT_NEGATIVE
                CBI PORTB,PORTB1
             .else
                SBI PORTB,PORTB1
             .endif
             RJMP PC+4         
             .ifndef UARTSOFT_NEGATIVE
                SBI PORTB,PORTB1
             .else
                CBI PORTB,PORTB1
             .endif
             NOP
             NOP   
             NOP
             NOP

          ; czekanie dla bitu danych
          .ifndef UARTSOFT_WAIT_DEBUG
             RCALL UARTSOFT_WRITE_WAIT_15
          .endif
          ; koniec czekania dla bitu danych

          EOR R20,R17      
          ROR R18
          DEC R19
       BRNE UARTSOFT_WRITE_DATA_LOOP

       .if UARTSOFT_PARITY > 0
          ANDI R20,1
          BRNE PC+6
             NOP
             NOP
             NOP
             .ifndef UARTSOFT_NEGATIVE
                CBI PORTB,PORTB1
             .else
                SBI PORTB,PORTB1
             .endif
             RJMP PC+6
             NOP
             NOP
             .ifndef UARTSOFT_NEGATIVE
                SBI PORTB,PORTB1
             .else
                CBI PORTB,PORTB1
             .endif
             NOP   
             NOP      
          .ifndef UARTSOFT_WAIT_DEBUG
             RCALL UARTSOFT_WRITE_WAIT_15
          .endif
          LDI R17,2
             DEC R17
          BRNE PC-1
       .endif   
       
       LDI R17,UARTSOFT_STOPBITS
       UARTSOFT_WRITE_STOP_BITS_LOOP:
          LDI R21,1
             DEC R21
          BRNE PC-1
          NOP
          .ifndef UARTSOFT_NEGATIVE
             SBI PORTB,PORTB1
          .else
             CBI PORTB,PORTB1
          .endif
          .ifndef UARTSOFT_WAIT_DEBUG
             RCALL UARTSOFT_WRITE_WAIT_15
          .endif
          LDI R21,2
             DEC R21
          BRNE PC-1      
          DEC R17
       BRNE UARTSOFT_WRITE_STOP_BITS_LOOP

       LD R17,Z+
       DEC R16
       BRNE UARTSOFT_WRITE_LOOP
       RET

    .exit

    Kod chciałem zrobić plastyczny, stąd takie cuda z dyrektywami.
    Nigdy nie wiem co z elektrodą.. czy dodawać załączniki do takich rzeczy czy kleić taki długi kod, więc na przyszłość prosiłbym o sprostowanie.
  • Poziom 32  
    Napisz jakie problemy masz z tym programem?
  • Poziom 9  
    Na terminalu nie widać nic co powinno być przesłane. W desperacji sprawdzałem różne baudy, opcje z bitami itd ale nic z tego. Jak dam prędkość taką jaką ma program na uC to nie dostaje nic (kursor z terminala stoi w miejscu). Jak dam 2 razy większą to lecą przeważnie F4h i temu podobne śmieci. Sprawdzałem putty, hyperterminal, program własny i jeszcze jeden polecany przez forumowiczów, ale nazwy nie pamiętam.
    Po wysłaniu mam jeszcze pętle która stopuje program na kilka ms, żeby nie zalać całego terminala.

    Ogólnie czym prędkość większa tym F'ów więcej.
    Przy prędkości mniejszej nie ma nic.
  • PCBway
  • Poziom 32  
    A gdzie masz deklaracje STOSU.
  • Poziom 9  
    Nie przekopiowałem, przeoczyłem.
    Code:

       LDI R16,0x70
       OUT SP,R16

    Znajduje sie na początku programu.

    Procesor sie nie wysypuje, kręci do roboty to co ma, ponadto przepisuje jeszcze stany wejść 0-3 na wyjścia 4-7 z portu A pomiędzy odczytami, więc sprawdzam czy program nie poszedł w maliny.
  • Poziom 9  
    Przeniosłem stos na ostatni bajt pamięci (127), zmieniłem baud na bps i odziwo.. zacząłem odbierać pierwszy znak.
    Próbowałem później przesłać cały napis, ale odbierałem tylko 1 znak a reszta były 255. Nie bardzo rozumiem co sie stało że zaczęło działać, ani tego że nie odbieram reszty wysyłanego napisu. Możliwe, że pomieszałem kopiowanie z pamięci programu do SRAM (chociaż symulator twierdzi co innego). No nic, trzeba będzie węszyć dalej.
    Pozdrawiam
  • Pomocny post
    Poziom 34  
    Proponuję zobaczyć noty aplikacyjne AVR304 do AVR309 Tu ;)
  • Poziom 9  
    Witam

    OO Nie wiedziałem, że na stronie atmela, są takie fajne rzeczy.
    Wielkie dzięki :-)
    Program wydaje sie cały czas poprawny, w święta może spróbuje znaleźć czas i zaimplementować to co jest w tym pdf'ie.
    Do tego czasu chciałbym sie upewnić jeszcze kilka rzeczy.
    W układzie mam MAX232N, podłączone do niego elektrolity 1uF. Nie dałem elektrolita pomiędzy Vcc i GND, "dodawałem go" podczas transmisji po chamsku dotykając piny, ale transmisja sie nie poprawiła. Czy jest on bardzo konieczny? Czy 1 uF to jest dobra wartość, czy doświadczenie sugeruje inne? Czy odległość tych kondensatorów od pinów ma jakieś spore znaczenie? Jeden mam troche "daleko", jest jakieś 4 cm od pinu (ten od pinu 6 do GND). Czy długość ścieżki z mikroprocesora może być zakłócona?
    Zdaje sobie sprawę, że są to troche idiotyczne pytania, ale ręce mi opadają, a to pierwszy układ jaki praktycznie robię, a nie chce się poddać.

    Pozdrawiam
  • VIP Zasłużony dla elektroda
    W moim układzie, w którym pracuje MAX232CPE prawidłowo do 230400 bps, na pompkach ładunkowych mam 4µ7 tantalowe, a pozostałe 10µ. Jeśli masz pod ręką woltomierz, to po prostu sprawdź napięcie na 6 wyprowadzeniu, powinno wynosić co najmniej -8V (względem GND), a jeśli jest -10V to jest wręcz idealnie. Prościej byłoby sprawdzić transmisję z µC posiadającym USART sprzętowy, po czym dopiero badać programowy, mając pewność, że reszta działa.
  • Poziom 9  
    Dziękuje za odzew.

    Hmm, po podłączeniu obciążenia (czyli kabla do komputera), napięcie na pinie 6 mam -7,99V, na 2 jest 8,5. To może być przyczyną błędnej transmisji? Zastanawia mnie fakt że poprawnie wysyła się pierwszy znak po przerwach kilku ms (ładuje sie kondensator w tym czasie?). Czyli jakie będzie dobre rozwiązanie, zmienic kondensatory?
  • Poziom 9  
    Zmieniłem na elektrolity 10uF, napięcie troche wzrosło, jednak ciągle ten sam wynik na terminalu. Jutro kupie tantalowe, jak to nie pomoże to zostaje gruntowny remont softu albo przeprojektowanie płytki, bo kończą mi sie już alternatywy :-(
  • Poziom 34  
    Odepnij kwarca i zobacz czy dalej wysyła może zasuwa na RC zamiast na rezonatorze.
  • VIP Zasłużony dla elektroda
    Przecież pierwszy znak jest OK, więc to nie problem z zegarem systemowym...
  • Poziom 9  
    Liczba znaków też sie zgadza, wysyłam 5, dostaję pierwszą literę i 4 śmieciowate, odziwo odbierany też jest poprawnie bit parzystości. Ustawiałem fuse bity, musiałem nawet kondensatory zmienić z 22pF na 15, bo mi kwarc nie chciał chodzić (więc taktowanie raczej śmiga).
  • Poziom 34  
    Proponuje zrobić przerwę między kolejnymi bajtami może przerwa jest zbyt mała i to robi problem.
  • Poziom 9  
    Wydłużyłem przerwe, bez zmian, wysyła sie tylko jeden (pierwszy) bajt, zmieniłem kondensatory, również bez zmian. Najbardziej irytuje mnie fakt że niezależnie jak długie są przerwy, znak pierwszy wysyła sie prawidłowo. Druga sprawa, wysyłany pierwszy znak nie zależy od procedury, tj jeżeli wysyłam 3 razy po jednym znaku (używając 3 razy RCALL) to również wysyłany jest pierwszy bajt.
    Pętla:
    robie_jakieś_pierdoły
    wyślij 'a'
    wyślij 'b'
    wyślij 'c'
    skocz do pętla
    To odbieram 'a' i dwa krzaczki.
    Watchdog? raczej bez sensu, nie wysyłałby 3 znaków (a nawet to wysłałby 2 poprawnie, a trzeci źle, nawet go nie włączałem, więc tymbardziej).
    Bity parzystości są poprawnie, symulator pokazuje prawidłowy wysył (jechałem po zmianach portu) i dane które odbiera terminal są różne od tego które wskazuje symulator. Ech, mam już tego powoli dosyć, już kompletnie nie wiem gdzie szukać.

    Wysyłałem różne znaki (zmieniałem pierwszy również, żeby zobaczyć czy te "zakłócenia" nie są przypadkowe (wskazując na prawidłową transmisję)). Dodatkowo rozbraja mnie fakt prawidłowego przesyłania bitu parzystości.

    Zmieniłem też mikroprocesor, ale efekt identyczny.

    Pętla:
    robie_jakieś_pierdoły
    wyślij 'a'
    robie_identyczne_pierdoly
    wyślij 'b'
    robie_identyczne_pierdoly
    wyślij 'c'
    skocz do pętla

    Również nie działa, przesyłany jest jedynie poprawnie pierwszy znak (dając około 50 ms pomiędzy znakami).
  • Poziom 23  
    Witam,

    Piszesz że dostajesz 1 prawidłowy i krzaczki. Uruchom portmon i sprawdź w hex co odbierasz. Napisz co nadajesz i co widać na portmon. Powinno się rozjaśnić.

    Pozdrawiam

    Eagle
  • Poziom 9  
    Witam wszystkich po świętach.

    Korzystając z wolnego tygodnia, napisałem na szybko programik, który jest mniej uniwersalny od poprzedniego. Wysyłanie prezentuje się następująco:
    Code:
    put_char:
    
       LDI R16,10
       COM R18
       SEC
    put_char_loop:
       BRCC skacz_bo_c_0
          NOP
          CBI PORTB,PORTB1
          RJMP PC+4
       skacz_bo_c_0:
          SBI PORTB,PORTB1
          NOP
          NOP
       RCALL UART_delay
       RCALL UART_delay
       LSR R18
       DEC R16
       BRNE put_char_loop
       RET

    UART_delay:
       LDI TEMP,135
    UART_delay1:   
       DEC TEMP
       BRNE UART_delay1
       RET

    Transmisja na 4MHz 4800bps oparta na nocie z Atmela. Odziwo działająca.. więc nie wiem co namieszałem, że moja stara przekombinowana wersja nie chciała działać. W symulacji działają niemal identycznie. No cóż, dziękuje wszystkim zainteresowanym za pomoc i życze szczęśliwego Nowego Roku :-) Oby takich głupich nieznanych problemów było jak najmniej.

    Pozdrawiam