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

[ATTiny26][ASM] Programowy UART

Wesoły Pierożek 17 Gru 2010 18:02 2204 20
  • #1 8880558
    Wesoły Pierożek
    Poziom 10  
    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
  • Pomocny post
    #2 8880990
    asembler
    Poziom 32  
    Wstaw kod bo schemat blokowy wydaje sie poprawny.
  • #3 8881419
    Wesoły Pierożek
    Poziom 10  
    Inicjalizacja:
    
    ; 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.
    
    .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.
  • #4 8881453
    asembler
    Poziom 32  
    Napisz jakie problemy masz z tym programem?
  • #5 8881500
    Wesoły Pierożek
    Poziom 10  
    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.
  • #6 8881580
    asembler
    Poziom 32  
    A gdzie masz deklaracje STOSU.
  • #7 8881665
    Wesoły Pierożek
    Poziom 10  
    Nie przekopiowałem, przeoczyłem.
    
    	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.
  • #8 8891496
    Wesoły Pierożek
    Poziom 10  
    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
    #9 8891685
    kamyczek
    Poziom 38  
    Proponuję zobaczyć noty aplikacyjne AVR304 do AVR309 Tu ;)
  • #10 8893249
    Wesoły Pierożek
    Poziom 10  
    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
  • #11 8895543
    LordBlick
    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.
  • #12 8895581
    Wesoły Pierożek
    Poziom 10  
    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?
  • #13 8895775
    LordBlick
    VIP Zasłużony dla elektroda
    Jeśli te -8V chwilowo się zapada, to trzeba zmienić kondensatory. Na pompce albo LOW ESR/ tantal, albo nie elektrolityczne, na zasilaniu i wyp. 6 mogą być większe nawet elektrolityczne.
    Tutaj przykładowy kondensator do pomp ładunkowych :
    http://www.maritex.com.pl/pl/shop/productInfo/ggid/42/pid/14803/page/1/backurl
  • #14 8897075
    Wesoły Pierożek
    Poziom 10  
    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 :-(
  • #15 8897142
    kamyczek
    Poziom 38  
    Odepnij kwarca i zobacz czy dalej wysyła może zasuwa na RC zamiast na rezonatorze.
  • #17 8897222
    Wesoły Pierożek
    Poziom 10  
    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).
  • #18 8897417
    kamyczek
    Poziom 38  
    Proponuje zrobić przerwę między kolejnymi bajtami może przerwa jest zbyt mała i to robi problem.
  • #19 8899870
    Wesoły Pierożek
    Poziom 10  
    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).
  • #20 8901717
    Eagle
    Poziom 24  
    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
  • #21 8919578
    Wesoły Pierożek
    Poziom 10  
    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:
    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
REKLAMA