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

Niezwykłe "nie_działanie" przerwania RXC

innocent 20 Sie 2007 22:00 1652 14
REKLAMA
  • #1 4197935
    innocent
    Poziom 11  
    Posty: 10
    Witam
    Napotkałem dziś problem natury nierozwiązalnych (podczas normalnego 8mio godzinnego dnia pracy), przynajmniej przeze mnie. Chodzi mianowicie o to, iż w budowanym przeze mnie układzie nie działa przerwanie RXC, ale... ale nie działa ono dość niezwykle:)
    Najpierw przedstawie krótki opis układu, a nastepnie objawy "niedziałania".

    Mikrokontroler ATmega32, kwarc 16MHz, asembler, programator JTAG ICE (używany także jako debugger). ATmega ma być sterownikiem 5ciu końcówek mocy zasilających silniki krokowe. Ma za zadanie wysyłać sygnały CLK, EN, CW/CCW. Z kontrolerem komunikuje się PC wysyłając 4 bajtowe słowa sterujące.

    PC wysyła słowo jako 4 bajty jeden po drugim, a nie 4 na raz:
    
    for (unsigned int i = 0; i < dNumberOfBytesToWrtie; i++)
    {
        WriteFile(hCommDev, &chBufferOut[i], 1, &dNumberOfBytesWritten, NULL);
    }
    


    ATmega odbiera to jako pojedyncze znaki i zapisuje ich ilość w pamięci:
    
    odbior2:
      cli
      rcall zapisz_rejestry
      clr R29	
      ldi R28, 0x007A
      ld a, Y
      inc a
      st Y, a
      add R28, a
      in b, UDR
      st Y, b
      cpi a, 4
      breq s0
      rcall wczytaj_rejestry
      sei	
      reti
    

    Jak ilość == 4, wywołuje się funkcja interpretująca słowo:
    
    s0:
      clr a
      clr R29	
      ldi R28, 0x007A
      st Y+, a
      ld pom1, Y+
      ld pom2, Y+
      ld pom3, Y+
      ld pom4, Y+
      ...
      itd.
    

    Tak powinien działać program. Ale jakby działał, to bym nie zawracał głowy.
    Jak już powiedziałem używam JTAGa jako online debuggera. Mam ustawiony breakpoint w momencie wywołania funkcji odbior2. Gdy PC wysyła słowo, funkcja odbior2 nie jest wywoływana, a program na PC zawiesza się (PortMon pokazuje, że PC wysyła tylko 1 bajt). Gdy zapauzuję wykonywanie programu na atmedze, program PC odwiesza się i wysyła pozostałe 3 bajty (PortMon). Na podglądzie rejestrów atmegi widać iż flaga RXC jest ustawiona (!), a po wykonaniu jeszcze jednego kroku (AVRStudio F11) program wykonuje przerwanie RXC.

    O co chodzi?

    Co jest ciekawe, zacząłem dochodzić co jest przyczyną takiego zachowania się programu atmegi przez wyłączanie poszczególnych funkcji wywoływanych w trakcie jego wykonywania. Okazało się, iż przerwanie zaczyna działać normalnie, gdy nie wywołuję funkcji sprawdzającej stan krańcówek:
    
    s_k:
      clr R29
      ldi R28, 0x0000
        s_k_0:	
      cpi c, 9
      brlo s_k_1
      subi c, 8
      inc R28
      rjmp s_k_0
        s_k_1:
      ldi b, 0b00000001
        s_k_2:
      dec c
      cpi c, 0
      breq s_k_3
      lsl b
      rjmp s_k_2
        s_k_3:
      ld c, Y+
      mov c, r1
      and c, b
      cpi c, 0
      breq s_k_end
      cpi pom1, 0x4C
      brne s_k_P
        s_k_L:
      sbr a, 0b00000010
      rjmp s_k_end
        s_k_P:
      sbr a, 0b00000001
      rjmp s_k_end
        s_k_end:
      ret
    

    A co jest JESZCZE ciekawsze, przerwanie działa normalnie, gdy wyrzucę z powyższej funkcji linijkę:
    
      ld c, Y+
    

    Nie mam pojęcia o co może chodzić. Jeżeli ktoś ma jakiś pomysł, proszę o radę. Jeżeli potrzeba więcej informacji, proszę napisać.

    Krzysztof
  • REKLAMA
  • #2 4198677
    Paweł Es.
    VIP Zasłużony dla elektroda
    Posty: 6981
    Pomógł: 1236
    Ocena: 691
    NIezwykłe to jest, to, że domagasz się pomocy podając niepełny program, bez komentarzy, co robi dany fragment, opisu zmiennych (np. a,b, c) opisu czego dotyczą adresy hex ładowane do rejestru Y (R28/R29.

    Do tego nie robisz wcięć, przez co program jest nieczytelny.

    Czy naprawdę myślisz, że tu są samarytanie jasnowidze o zdolnościach śledczych porucznika Borewicza i upierdliwości porucznika Jaszczuka co dojdą po tych kawałkach, jak działa ten twój program i jeszcze znajdą w nim błąd ?

    No miejże litość, uczytelnij ten program (wcięcia po etykietach), podaj adresy i definicje zmiennych, wpisz komentarze i dopiero czekaj pomocy :)
  • REKLAMA
  • #3 4198740
    Ch.M.
    Poziom 27  
    Posty: 1009
    Pomógł: 62
    Ocena: 15
    Hmm piszesz w kompilatorze gcc ASMem... nie prościej odinstalować plugin i sprawdzić, czy po drodze nic nie dodał?
    Cytat:
    Piszesz, jakoby od razu nie wykonywał sie program Na podglądzie rejestrów atmegi widać iż flaga RXC jest ustawiona (!), a po wykonaniu jeszcze jednego kroku (AVRStudio F11) program wykonuje przerwanie RXC.

    O co chodzi?

    Przerwanie nie jest wykonywane od razu bez namysłu, tylko trzeba poczekac kilka cykli, ale to chyba wiesz.

    Pokazując fragment programu, w dodatku bez komentarzy nic nie wskórasz, tak jak napisał moj poprzednik. Zamiesc cały kod z opisem. Na chybił trafił, moge powiedziec, ze np. źle przydzieliłeś rozmiar pamięci dla stosu. Takich pomysłów mogę mieć więcej, ale podaj coś więcej, mało jasnowidzy jest wśród nas
    Pozdrawiam
  • #4 4199009
    innocent
    Poziom 11  
    Posty: 10
    No nie to żebym od razu się domagał:) po prostu myślałem, że się ktoś zainteresuje i jak nie będzie widział tutaj potrzebnych informacji to powie mi jakich (a nie od razu zmiesza z błotem:) bo ja nie wiem co jest potrzebne żeby zdiagnozować ten błąd.
    Po kolei.
    Cytat:

    Do tego nie robisz wcięć, przez co program jest nieczytelny.

    Szukałem jak wygląda na tym forum formatowanie kodu w postach, ale znalazłem tylko kod wrzucany w słupku, jedna komenda pod drugą, więc nie wiem jak mam sformatować to co zaraz wyślę. Pokaż przykład, to tak przeformatuję.

    Nie chciałem od razu wrzucać całego kodu programu, bo jest on dosyć długi, no ale jak widać, nie obejdzie się bez tego.

    Będzie z opisami:)

    Używane zmienne:
    
    .INCLUDE "m32def.inc"
    .def a = r16	// zmienne pomocnicze, używane w różnych celach
    .def b = r17	//
    .def c = r22	//
    				//
    .def pom1 = r18	//
    .def pom2 = r19	//
    .def pom3 = r20	//
    .def pom4 = r21	// 
    
    .def rejestr1 = r0	// bajty wysyłane na porty. sterownie końcówkami mocy
    .def rejestr2 = r1	//
    .def rejestr3 = r2	//
    .def rejestr4 = r3	//
    
    .def del1 = r24		// liczniki zarazerwowany dla delaya 
    .def del2 = r25		// liczniki zarazerwowany dla delaya
    .def del00 = r30	// Lb czasu opoznienia
    .def del01 = r31	// Hb czasu opoznienia
    

    Struktura pamięci, opis słowa z PC itd.
    
    //////////////////////////////////////////
    //
    //	struktura SRAM:
    //		0x0060	Hb krokow silnika S1
    //		0x0061	Lb krokow silnika S1
    //		0x0062	kirunek obrotu S1
    //		0x0063	~EN silnika S1
    //		0x0064	rezerwa S1
    //
    //		0x0065	Hb krokow silnika S2
    //		0x0066	Lb krokow silnika S2
    //		0x0067	kirunek obrotu S2
    //		0x0068	~EN silnika S2
    //		0x0069	rezerwa S2
    //
    //		0x006A	Hb krokow silnika S3
    //		0x006B	Lb krokow silnika S3
    //		0x006C	kirunek obrotu S3
    //		0x006D	~EN silnika S3
    //		0x006E	rezerwa S3
    //
    //		0x006F	Hb krokow silnika S4
    //		0x0070	Lb krokow silnika S4
    //		0x0071	kirunek obrotu S4
    //		0x0072	~EN silnika S4
    //		0x0073	rezerwa S4
    //
    //		0x0074	Hb krokow silnika S4
    //		0x0075	Lb krokow silnika S4
    //		0x0076	kirunek obrotu S4
    //		0x0077	~EN silnika S4
    //		0x0078	rezerwa S4
    //		
    //		0x0079  czas trwania 1 kroku [ms]
    //
    //		0x007A	wskaznik odebranych liczby odebranych danych z UART
    //		0x007B	UART bajt 1
    //		0x007C	UART bajt 2
    //		0x007D	UART bajt 3
    //		0x007E	UART bajt 4
    //
    //		0x007F	1 parametr do funkcji
    //		0x0080	2 parametr do funkcji
    //
    //		0x0090	poczatek miejsca na kopiowane rejestry
    //		......
    //		0x00aF	koniec miejsca na kopiowane rejestry
    //
    //////////////////////////////////////////
    //
    //	Struktura slowa z PC:
    //		00	11	22	33
    //		nr_silnika
    //			kierunek
    //				Hb_ilosci_krokow	
    //					Lb_ilosci_krokow
    //
    //		1,2,3,4
    //			"L"0x4C,"P"0x50		kierunek obrotu "L"=stan 0 na porcie
    //			"T"0x54				"T"-zmiana opoznienia pomiedzy kolejnymi krokami [ms], bajt 3-dowolny, bajt 4-opozninie 
    //			"E"0x45				enabled (slowo ma postac 1 E 0 1 aby wlaczyc S1) 0xFF w SRAM jezeli enabled, 0x00 jezeli not enabled (na porcie odwrotnie- stan wysoki to not enabled)
    //				0x00-0xFF
    //					0x00-0xFF	
    //
    //
    //////////////////////////////////////////
    //
    //	Porty:	
    //		PortD.0	[1]	 --------------			rejestr1
    //		PortD.1	[2]	 --------------
    //		PortD.2	[3]	 --------------
    //		PortD.3	[4]	 --------------
    //		PortD.4	[5]	 --------------
    //		PortD.5	[6]	 --------------
    //		PortD.6	[7]	 --------------
    //		PortD.7	[8]	 1	CLK			S1
    //	
    //		PortC.0	[9]	 1	CW/CCW		S1		rejestr2
    //		PortC.1	[10] 1	~EN			S1
    //		PortC.2	[11] 0	krancowka1	S1
    //		PortC.3	[12] 0	krancowka2	S1
    //		PortC.4	[13] 1	CLK			  S2
    //		PortC.5	[14] 1	CW/CCW		  S2
    //		PortC.6	[15] 1	~EN			  S2
    //		PortC.7	[16] 0	krancowka1	  S2
    //
    //		PortB.0	[17] 0	krancowka2	  S2	rejestr2
    //		PortB.1	[18] 1	CLK			S3
    //		PortB.2	[19] 1	CW/CCW		S3
    //		PortB.3	[20] 1	~EN			S3
    //		PortB.4	[21] 0	krancowka1	S3
    //		PortB.5	[22] 0	krancowka2	S3
    //		PortB.6	[23] 1	CLK			S3
    //		PortB.7	[24] 1	CW/CCW		  S4
    //
    //		PortA.0	[25] 1	~EN			  S4	rejestr4
    //		PortA.1	[26] 0	krancowka1	  S4
    //		PortA.2	[27] 0	krancowka2	  S4
    //		PortA.3	[28] 1	CLK			S5
    //		PortA.4	[29] 1	CW/CCW		S5
    //		PortA.5	[30] 1	~EN			S5
    //		PortA.6	[31] 0	krancowka1	S5
    //		PortA.7	[32] 0	krancowka2	S5
    //
    //////////////////////////////////////////
    

    Ustawienia początkowe:
    
    .cseg
    
    .org 0x0000 jmp main
    .org 0x0002 reti
    .org 0x0004 reti
    .org 0x0006 reti
    .org 0x0008 reti
    .org 0x000a reti
    .org 0x000c reti
    .org 0x000e reti
    .org 0x0010 reti
    .org 0x0012 reti
    .org 0x0014 reti
    .org 0x0016 reti
    .org 0x0018 reti
    .org 0x001a jmp odbior2
    .org 0x001c reti
    .org 0x001e reti
    .org 0x0020 reti
    .org 0x0022 reti
    .org 0x0024 reti
    .org 0x0026 reti
    .org 0x0028 reti
    
    main:
    	ldi a, LOW(RAMEND)			// inicjalizacja stosu
    	out SPL, a					//
    	ldi a, HIGH(RAMEND)			//
    	out SPH, a					//
    
    
    	ldi a, 0b10000000	// ustaienia początkowe rejestrów
    	mov rejestr1, a		//
    	ldi a, 0b01110011	//
    	mov rejestr2, a		//
    	ldi a, 0b11001110	//
    	mov rejestr3, a		//
    	ldi a, 0b00111001	//
    	mov rejestr4, a		//
    		
    	out DDRD, rejestr1		// ustawienia portow
    	out PortD, rejestr1		//
    							//
    	out DDRC, rejestr2		//
    	out PortC, rejestr2		//
    							//
    	out DDRB, rejestr3		//
    	out PortB, rejestr3		//
    							//
    	out DDRA, rejestr4		//
    	out PortA, rejestr4		//
    
    
    	ldi a, 0									// ustawienia usart
    	out UBRRH, a								//
    	ldi a, 103									//
    	out UBRRL, a								//	
    												//
    	ldi a, (1<<RXCIE) | (1<<RXEN) | (1<<TXEN)	//
    	out UCSRB, a								//
    	
    	ldi a, 0x45				// wyslanie "E" na USART
    	out UDR, a				//
    
    	ldi a, (1<<JTD)		// disable JTAG interface (2 sec external reset lo, enables JTAG interface)	
    //	out MCUCSR, a		//
    //	out MCUCSR, a		// musi byc 2x!!!
    						
    	rcall czyscmemo
    
    	rcall ustawienia_poczatkowe
    	
    	sei        //włączenie przerwań
    

    Pętla główna, w niej jest sprawdzana ilość kroków (stanów niskich pinu CLK dla danego silnika), stanu pinów ENABLED, pinu kierunku CW/CCW i stanu pinów krańcówek (stan wysoki na pinie krańcówki, oznacza zadziałanie krańcówki):
    
    loop:
    	in rejestr1, PinD	// wczytanie do rejestrów stanu pinów (aby zdiagnozować stan krańcówek)
    	in rejestr2, PinC	//
    	in rejestr3, PinB	//
    	in rejestr4, PinA	//
    
    	ldi c, 8		// nie ruszac, poczatkowe ustawienie dla ustawiania bitow w rejestrach (funkcja ustaw_bit_rejestru)
    
      loop_s1:			
    	push c
    	 subi c, 8
      	 clr R29			// wczytanie wartosci parametrow do wyslania do silnika (CK, CW/CCW, EN)
    	 ldi R28, 0x0060	//
    	 add R28, c			//
    	pop c				//
    	ld R27, Y+			// wczytanie Hb ilości kroków dla danego silnika
    	ld R26, Y+			// wczytanie Lb ilości kroków 
    	ld pom1, Y+			// wczytanie kierunku działania
    	ld pom2, Y+			// wczytanie stanu pinu enabled
    	subi R28, 4
    
    	push c						// --- ENABLED --- ustawienie pinu 
    	 inc c						//
    	 inc c						// c - który bit rejestrów ustawić (bity numerowane od 1, czyli bit 0 rejestr1, ma nr 1, bit 0 rejestr2 ma nr 9 itd.)
    	 ldi a, 0					// a - jaki ma być stan bitu
    	 sbrs pom2, 0				//
    	 ldi a, 1					//
    	 rcall ustaw_bit_rejestru	//
    	pop c						// --- /ENABLED ---	
    
       loop_s1_0:					// --- KIERUNKU DZIAŁANIA --- zdefiniowanie (0x4C = "L" = 0 na porcie)	
       								//			
    	push c						//
    	 inc c
    	 ldi a, 0					//
    	 cpi pom1, 0x4C				//
    	 breq loop_s1_skipR			//
    	 ldi a, 1					//
    	 loop_s1_skipR:				//
    	 rcall ustaw_bit_rejestru	//
    	pop c						// --- /KIERUNKU DZIAŁANIA ---
    
    
    	push c				// --- KRAŃCÓWKI ---
    	 clr a
    	 inc c
    	 inc c
    	 inc c
    	 rcall s_k			// funkcja sprawdzająca stan krańcówek
    	 pop c				// zwraca w zmiennej a liczbę 1 jeżeli zadziałała krańcówka prawa, liczbę 2 jeżeli lewa, 3 jeżeli obie (ktoś wcisnął:)
    	 push c
    	 inc c
    	 inc c
    	 inc c
    	 inc c
    	 rcall s_k
    	pop c		
    
    	cpi pom1, 0x4C
    	brne loop_s1_kP
      loop_s1_kL:
    	sbrs a, 1
    	rjmp loop_s1_3
    	rjmp loop_s1_krancowka
      loop_s1_kP:
    	sbrs a, 0
    	rjmp loop_s1_3
    	rjmp loop_s1_krancowka
      loop_s1_krancowka:
    	ldi a, 1				// wyslanie sygnalu ze zadzialala krancowka
    	out UDR, a				//
    	ldi a, 0x4B				//
    	out UDR, a				//
    	ldi a, 0x00				//
    	out UDR, a				//
    	mov a, pom1				//
    	out UDR, a				//
    
    	ldi a, 1			// wyslanie wartosci pozostalej ilosci krokow do zrealizowania
    	out UDR, a			//
    	ldi a, 0x4B			//
    	out UDR, a			//
    	ld R27, Y+			// wczytanie obecnej liczby krokow do wykonania
    	ld R26, Y+			//
    	subi R28, 2			//
    	mov a, R27			//
    	out UDR, a			//
    	mov a, R26			//
    	out UDR, a 			//
    	rjmp loop_s1_2		//
    
       loop_s1_2:
    	clr R27				// jezeli zadzialala krancowka, kasujemy kroki
    	clr R26				//
    	st Y+, XH			// i zapisujemy to w SRAM
    	st Y+, XL			//	
    	subi YL, 2			// --- /KRAŃCÓWKI ---
    
       loop_s1_3:					// --- CLK --- ustawienie pinu
    								//
    	push c						// wstepne ustawienie na 1 pinu clk	
    	 ldi a, 1					//		
    	 rcall ustaw_bit_rejestru	//	
    	pop c						//
       	
    	cpi R27, 0			// sprawdzenie ilosci krokow do wykonania
    	brne loop_s1_4		//
    	cpi R26, 0			//
    	breq loop_s1_5		//
       loop_s1_4:			//
    	sbiw XH:XL, 1		// jezeli ilosc > 0 odjecie jednego kroku, zapisanie nowej ilosci
    	st Y+, XH			//
    	st Y+, XL			//
    	subi YL, 2			//
    
    	push c						// i wpisanie 0 na pin clk
    	 ldi a, 0					//
    	 rcall ustaw_bit_rejestru	//
    	pop c						// --- /CLK ---
    
       loop_s1_5:
    	cpi c, 28
    	breq loop_wypisanie_rejestrow
    	inc c
    	inc c
    	inc c
    	inc c
    	inc c
    	rjmp loop_s1
    
      loop_wypisanie_rejestrow:
    
    //	mov a, rejestr1				// wyczyszczenie pinow input od krancowek w rejestrach
    //	cbr a, 0b00000000			//
    //	mov rejestr1, a				//
    								//
    	mov a, rejestr2				//
      	cbr a, 0b10001100			//
    	mov rejestr2, a				//
    								//
    	mov a, rejestr3				//
    	cbr a, 0b00110001			//
    	mov rejestr3, a				//
    								//
    	mov a, rejestr4				//	
    	cbr a, 0b11000110			//
    	mov rejestr4, a				//
    
     	out PortD, rejestr1		// wypisanie rejestrow na porty
    	out PortC, rejestr2		//
    	out PortB, rejestr3		//
    	out PortA, rejestr4		//
    
    	ldi del00, 100		// delay 100 us
    	call delay_us		//
    
    	mov a, rejestr1			// wyczyszczenie bitow CLK w rejestrach
    	sbr a, 0b10000000		//
    	mov rejestr1, a			//
    	mov a, rejestr2			//		
    	sbr a, 0b00010000		//
    	mov rejestr2, a			//
    	mov a, rejestr3			//
    	sbr a, 0b01000010		//
    	mov rejestr3, a			//
    	mov a, rejestr4			//
    	sbr a, 0b00001000		//
    	mov rejestr4, a			//
    
     	out PortD, rejestr1		// wypisanie rejestrow na porty
    	out PortC, rejestr2		//
    	out PortB, rejestr3		//
    	out PortA, rejestr4		//
    
    	clr R29				// wywolanie opoznienia pomiedzy krokami
    	ldi R28, 0x0079		//
    	clr del01			//
    	ld del00, Y			//
    	call delay			//
    
      loop_end:
    rjmp loop
    

    Używane w programie funkcje.
    Ustaw_bit_rejestru - ustaw bit o numerze c rejestru złożonego z 4 bajtów (rejestr1, rejestr2, rejestr3, rejestr4). 0x0000 to rejestr1 itd. Ustawia stan w zależności od liczby wpisanej do a. a=1 ustaw 1, a=0 ustaw 0.
    
    ustaw_bit_rejestru:
    	clr R29
    	ldi R28, 0x0000
      ustaw_bit_rejestru_0:	
    	cpi c, 9
    	brlo ustaw_bit_rejestru_1
    	subi c, 8
    	inc R28
    	rjmp ustaw_bit_rejestru_0
      ustaw_bit_rejestru_1:
    	ldi b, 0b00000001
    	cpi a, 0
    	brne ustaw_bit_rejestru_3
    	ldi b, 0b11111110
      ustaw_bit_rejestru_2:			// ustaw 0
      	dec c
    	cpi c, 0
    	breq ustaw_bit_rejestru_4
    	sec
    	rol b
    	rjmp ustaw_bit_rejestru_2
      ustaw_bit_rejestru_3:			// ustaw 1
      	dec c
    	cpi c, 0
    	breq ustaw_bit_rejestru_5
    	clc
    	rol b
    	rjmp ustaw_bit_rejestru_3
      ustaw_bit_rejestru_4:			// and
    	ld c, Y	
    	and c, b
    	rjmp ustaw_bit_rejestru_end
      ustaw_bit_rejestru_5:			// or
    	ld c, Y
    	or c, b
      ustaw_bit_rejestru_end:
      	st Y, c
    	ret
    

    S_k - sprawdza stan bitu o numerze c w rejestrze 4 bajtowym. Zwraca stan w zmiennej a.
    
    s_k:
    	clr R29
    	ldi R28, 0x0000
      s_k_0:	
    	cpi c, 9
    	brlo s_k_1
    	subi c, 8
    	inc R28
    	rjmp s_k_0
      s_k_1:
      	ldi b, 0b00000001
      s_k_2:
      	dec c
    	cpi c, 0
    	breq s_k_3
    	lsl b
    	rjmp s_k_2
      s_k_3:
    	ld c, Y+
    	mov c, r1
    	and c, b
    	cpi c, 0
    	breq s_k_end
    	cpi pom1, 0x4C
    	brne s_k_P
      s_k_L:
    	sbr a, 0b00000010
    	rjmp s_k_end
      s_k_P:
    	sbr a, 0b00000001
    	rjmp s_k_end
      s_k_end:
        ret
    

    Odbiór z uart - jeżeli jest przerwanie RXC, pobiera daną, zapisuje ją do SRAM, zwiększa licznik pobranych danych (licznik też do sram). Jeżeli licznik==4, wykonuje s0.
    
    odbior2:
    	cli
    	rcall zapisz_rejestry	// zapisanie rejestrów r0 - r31 do sram
    
    	clr R29	
    	ldi R28, 0x007A
    	ld a, Y
    	inc a
    	st Y, a
    
    	add R28, a
    
    	in b, UDR
    	st Y, b
    
    	cpi a, 4
    	breq s0
    
    	rcall wczytaj_rejestry	// wczytanie rejestrów
    	sei	
    
    	reti
    

    s0 - interpretacja 4 bajtowego słowa które przyszło z PC:
    
    s0:
    	clr a
    	clr R29	
    	ldi R28, 0x007A
    	st Y+, a
    	ld pom1, Y+
    	ld pom2, Y+
    	ld pom3, Y+
    	ld pom4, Y+
    
      s_0_T:
      	cpi pom2, 0x54			// "T" - ustgaw czas opóźnienia pomiędzy cyklami CLK
    	brne s_0_1				//
     	ldi R28, 0x0079			//
    	st Y+, pom4				//
    	rjmp s_end				//
    
      s_0_1:
    	cpi pom1, 1		// jezeli pierwszybajt jest numerem silnika, zwieksz adresy rejestrow
    	brne s_0_2		//		
    	ldi a, 0		//
    	rjmp s_0_E		//
      s_0_2:			//
    	cpi pom1, 2		//
    	brne s_0_3		//
    	ldi a, 5		//
    	rjmp s_0_E		//
      s_0_3:			//
      	cpi pom1, 3		//
    	brne s_0_4		//
    	ldi a, 10		//
    	rjmp s_0_E		//
      s_0_4:			//
      	cpi pom1, 4		//
    	brne s_0_5		//
    	ldi a, 15		//
    	rjmp s_0_E		//
      s_0_5:			//
      	cpi pom1, 5		//
    	brne s_error	//
    	ldi a, 20		//
    	rjmp s_0_E		//
    
      s_0_E:
    	cpi pom2, 0x45	// "E" - ustawienie enable/not enable dladanego silnika
    	brne s_1_1		//
     	inc a			//
     	inc a			//
    	inc a			//
    	ldi	R28, 0x0060	//
    	add R28, a		//
    	clr a			//
    	sbrc pom4, 0	//
    	ldi a, 0xFF		//
    	st Y, a			//
    	rjmp s_end		//
    
      s_1_1:
    	clr R29				// przyszla nowa wartosc krokow, wpisanie do rejestrow wartosci krokow 	
      	ldi	R28, 0x0060		//
    	add R28, a			//
    	st Y+, pom3			//
    	st Y+, pom4			//
    	st Y+, pom2			//
    	rjmp s_end			//
    
      s_error:					// recieve error
    	ldi a, 0x45				// wyslanie "E" na USART
    	out UDR, a				//
    	rcall wczytaj_rejestry	//
    	sei						//
      	reti					//
    
      s_end:
      	ldi a, 1				// wyslanie 1 na USART
    	out UDR, a				//
    	rcall wczytaj_rejestry
    	sei
      	reti
    

    Inne mniej znaczące funkcje:
    
    ustawienia_poczatkowe:
    	ldi a, 0x50				// ustawienie "P" jako kierunku dla kazdego silnika
    	ldi R28, 0x0062			//
    	st Y, a					//
    	std Y+5, a				//
    	std Y+10, a				//
    	std Y+15, a				//
    	std Y+20, a				//	
    	
    	ldi a, 0xFF			//	ustawienia ~EN na disabled (0xFF)
    	ldi R28, 0x0063		//
    	st Y, a				//
    	std Y+5, a			//
    	std Y+10, a			//
    	std Y+15, a			//
    	std Y+20, a			//
    
    	ldi a, 0x99				// ustawienie bajtu rezerwowego (0x99)
    	ldi R28, 0x0064			//
    	st Y, a					//
    	std Y+5, a				//
    	std Y+10, a				//
    	std Y+15, a				//
    	std Y+20, a				//	
    
    	ldi R28, 0x0079		// ustawienie opoznienia kroku na 3 ms
    	ldi a, 2			//
    	st Y+, a			//
    
    	clr R29					// wyczyszczenie uzywanych zmiennych
    	clr a					//
    
    	ret
    //////////////////////////////////////////
    zapisz_rejestry:
    	sts 0x0090, R0
    	sts 0x0091, R1
    	sts 0x0092, R2
    	sts 0x0093, R3
    	sts 0x0094, R4
    	sts 0x0095, R5
    	sts 0x0096, R6
    	sts 0x0097, R7
    	sts 0x0098, R8
    	sts 0x0099, R9
    	sts 0x009A, R10
    	sts 0x009B, R11
    	sts 0x009C, R12
    	sts 0x009D, R13
    	sts 0x009E, R14
    	sts 0x009F, R15
    	sts 0x00A0, R16
    	sts 0x00A1, R17
    	sts 0x00A2, R18
    	sts 0x00A3, R19
    	sts 0x00A4, R20
    	sts 0x00A5, R21
    	sts 0x00A6, R22
    	sts 0x00A7, R23
    	sts 0x00A8, R24
    	sts 0x00A9, R25
    	sts 0x00AA, R26
    	sts 0x00AB, R27
    	sts 0x00AC, R28
    	sts 0x00AD, R29
    	sts 0x00AE, R30
    	sts 0x00AF, R31
    	ret
    //////////////////////////////////////////
    wczytaj_rejestry:
    	lds R0, 0x0090
    	lds R1, 0x0091
    	lds R2, 0x0092
    	lds R3, 0x0093
    	lds R4, 0x0094
    	lds R5, 0x0095
    	lds R6, 0x0096
    	lds R7, 0x0097
    	lds R8, 0x0098
    	lds R9, 0x0099
    	lds R10, 0x009A
    	lds R11, 0x009B
    	lds R12, 0x009C
    	lds R13, 0x009D
    	lds R14, 0x009E
    	lds R15, 0x009F
    	lds R16, 0x00A0
    	lds R17, 0x00A1
    	lds R18, 0x00A2
    	lds R19, 0x00A3
    	lds R20, 0x00A4
    	lds R21, 0x00A5
    	lds R22, 0x00A6
    	lds R23, 0x00A7
    	lds R24, 0x00A8
    	lds R25, 0x00A9
    	lds R26, 0x00AA
    	lds R27, 0x00AB
    	lds R28, 0x00AC
    	lds R29, 0x00AD
    	lds R30, 0x00AE
    	lds R31, 0x00AF
    	ret
    //////////////////////////////////////////
    delay:
      delay_0: 
    	ldi del1, 10						; --- !!! 10 !!!
      		delay_1:
    		ldi del2, 100					; --- !!! 100 !!!
      			delay_2:
    			nop
    			nop
    			nop
    			nop
    			nop
    			nop	
    			nop
    			nop
    			nop				
    			nop							; ---
    			nop							; --- 1ms ma teoretycznie ok 1003us
    			nop							; ---
    			dec del2
    			cpi del2, 0
    			brne delay_2
    		dec del1 
    		cpi del1, 0
    		brne delay_1
    	clz									; --- zeroj flage zera
    	sbiw del01:del00, 1					; --- odejmij 1 od liczby 2bajtowej
    	brbs 1, delay_end 				; --- przeskocz jezeli ustawiona flaga 0
    	brne delay_0
      delay_end:
    	clz								; --- zeroj flage zera
    ret
    //////////////////////////////////////////
    delay_us:
      delay_us_1:
    	clz	
    	nop
    	nop
    	nop
    	nop
    	nop
    	nop
    	nop
    	nop								
    	clz				
    	sbiw del01:del00, 1
    	brbs 1, delay_us_end 			
    	brne delay_us_1
      delay_us_end:
    	clz									; --- zeroj flage zera
    ret
    

    Tak to wygląda, jak mam coś dowyjaśnić, piszcie. Wiem że sprawdzanie cudzego asm to mordęga:) dzieki za zainteresowanie i proszę o wyrozumiałość. Nie krzyczeć, podporządkuję się:)

    Cytat:

    Hmm piszesz w kompilatorze gcc ASMem... nie prościej odinstalować plugin i sprawdzić, czy po drodze nic nie dodał?

    Wydaje mi się że nie da rady, ale nie sprawdzałem przeniesienia dll'a gcc gdzie indziej. A poza tym, jeżeli piszę w asm, to i tak to idzie przez gcc?

    Cytat:

    Przerwanie nie jest wykonywane od razu bez namysłu, tylko trzeba poczekac kilka cykli, ale to chyba wiesz.

    No tak, ale ja mogłem po wysłaniu przez minutę nie pauzować tego programu i dopiero po spauzowaniu i ruszeniu krokowo startowało przerwanie.

    Uf. Dużo. Tak jak mówiłem, jak będzie trzeba przeformatuję, ale może tak da rade.
    Dzięki.
  • #5 4199620
    Paweł Es.
    VIP Zasłużony dla elektroda
    Posty: 6981
    Pomógł: 1236
    Ocena: 691
     
    s_k_3: 
                  ld c, Y+          <---
                  mov c, r1       <---
                  and c, b 
                  cpi c, 0 
    
    


    Dlaczego w tym fragmencie podprogramu s_k ładujesz zmienną c z dwóch różnych miejsc?


    Problem zdaje się leży w tym, że końcówki sygnałów w interfejsie JTAG pokrywają się z niektórymi twoimi sygnałami w porcie C (np. krańcówki).
    Program może się gryźć z JTAG-iem gdzieś wewnątrz procesora.
  • REKLAMA
  • #6 4199716
    innocent
    Poziom 11  
    Posty: 10
    W programie ładuję z jednego, drugi mam zahaszowany. Jak wklejałem na forum, odhaszowałem i nie zobaczyłem że jest tam mov poniżej.
    Oba ładowania sprowadzają się do tego samego bo gdy YL zostanie zwiększony o 1, to będzie wskazywał na r1.

    Próbowałem po prostu innego sposobu na załadowanie zmiennej, ale jak zostawie mov, i zahaszuje ld jest tak samo jak bym zostawił ld i zahaszował mov - nie działa przerwanie.

    Na początku było ld, bo takie jest założenie działania tej funkcji.

    Dodano po 2 [minuty]:

    Przepraszam za podzielenie odpowiedzi na 2, ale nie zauważyłem ciągu dalszego.
    Cytat:

    Problem zdaje się leży w tym, że końcówki sygnałów w interfejsie JTAG pokrywają się z niektórymi twoimi sygnałami w porcie C (np. krańcówki).
    Program może się gryźć z JTAG-iem gdzieś wewnątrz procesora.

    Po odłączeniu jtaga też nie działa komunikacja.

    Próbowałem także w ten sposób- haszowałem wszystkie linijki, które czytały z i zapisywały do portu C. To też nie dało rezultatu.

    Dodano po 2 [minuty]:

    Testuję na razie bez podłączania końcówek mocy ani krańcówek- żadne sygnały na porty nie przychodzą.
  • REKLAMA
  • #7 4199813
    GaPaTech
    Poziom 12  
    Posty: 18
    Pomógł: 2
    Ocena: 3
    Czy jest ktoś w stanie wskazać w listingu ochronę SREG w obsłudze przerwania? Ja widzę "tylko" 32 rejestry robocze. :)
  • #8 4199825
    innocent
    Poziom 11  
    Posty: 10
    Ja w stanie wykazać nie jestem:)
    Zaraz dorzucę.
  • Pomocny post
    #9 4199947
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    GaPaTech napisał:
    Czy jest ktoś w stanie wskazać w listingu ochronę SREG w obsłudze przerwania? Ja widzę "tylko" 32 rejestry robocze. :)

    "Czy jest ktoś w stanie wytłumaczyć" ;) ... taką serię zapisów do UDR :?:
    
      loop_s1_krancowka:
       ldi a, 1            // wyslanie sygnalu ze zadzialala krancowka
       out UDR, a            //
       ldi a, 0x4B            //
       out UDR, a            //
       ldi a, 0x00            //
       out UDR, a            //
       mov a, pom1            //
       out UDR, a            //
    
       ldi a, 1         // wyslanie wartosci pozostalej ilosci krokow do zrealizowania
       out UDR, a         //
       ldi a, 0x4B         //
       out UDR, a         //
       ld R27, Y+         // wczytanie obecnej liczby krokow do wykonania
       ld R26, Y+         //
       subi R28, 2         //
       mov a, R27         //
       out UDR, a         //
       mov a, R26         //
       out UDR, a          //
       rjmp loop_s1_2      //
    

    innocent ! ! ! , zastanów się co czynisz :D
    Poza tym , takie bezpośrednie odwoływanie się do konkretnych adresów , czyni kod baaaardzo nieczytelnym.Nie po to producent kompilatora ułatwia nam życie - dodając takie udogodnienia jak etykiety,makra , itp. , byśmy z nich nie korzystali.Przecież w tej numerkologi , można sie szybko pogubić :( A gdy Twój kod "urośnie" już do kilku(nastu) tysięcy linii :?: ... makabra :D Jedźmy dalej ;) Umieszczenie w przerwaniu rozkazów cli i sei , świadczy tylko o Twojej nikłej znajomości architektury AVR-ów :(

    Piotrek
  • #10 4199991
    GaPaTech
    Poziom 12  
    Posty: 18
    Pomógł: 2
    Ocena: 3
    No tak...
    ten UART żeby zdążyć wysłać to co dostaje to chyba już na UKF nadaje zegarem takrującym :)
  • #11 4200101
    innocent
    Poziom 11  
    Posty: 10
    Ok, jestem z powrotem, a więc. W trakcie kiedy ja dodawałem zapis SREG, kumpel skompilował i odpalił program u siebie na kompie i co mnie bardzo zmartwiło- działa. No nie to że mnie zmartwiło bo jest ok że działa, ale myślałem że to wina kodu.
    A teraz postaram się odeprzeć zarzuty:) albo przyjąć je z otwartą przyłbicą:)
    Cytat:

    "Czy jest ktoś w stanie wytłumaczyć" ... taką serię zapisów do UDR

    Tak, ja jestem:) wysyłam w ten sposób informacje która krańcówka zadziałała i ile kroków silnikowi pozostało do wykonania. W sumie wystarczy tylko jedno słowo 4 bajtowe, drugiego być nie musi.
    Cytat:

    dodając takie udogodnienia jak etykiety,makra , itp. , byśmy z nich nie korzystali.

    Przyznaję że z makr nigdy nie korzystałem. Chyba muszę zacząć, posłucham się:) o jakie etykiety Ci chodzi? Czy o takie w stylu "loop_s1_krancowka:", czy o coś innego?
    Cytat:

    Umieszczenie w przerwaniu rozkazów cli i sei , świadczy tylko o Twojej nikłej znajomości architektury AVR-ów

    Tak, świadczy:( to mój duży błąd. A o makrach poczytam:)
    Cytat:

    No tak...
    ten UART żeby zdążyć wysłać to co dostaje to chyba już na UKF nadaje zegarem takrującym

    Ale on to wysyła tylko jak zadziała krańcówka, co mam nadzieję nigdy nie nastąpi, przynajmniej bedę się starał żeby do tego nie dopuścić:)

    Czemu na innym komputerze działa ok??
  • Pomocny post
    #12 4200162
    GaPaTech
    Poziom 12  
    Posty: 18
    Pomógł: 2
    Ocena: 3
    Jak zadziała krańcówka to i tak to nie zadziała bo o ile pamiętam to UART FIFO nie posiada (a może się mylę?)
    Jeżeli wysyłasz kolejne bajty w sekwencji
    ldi a,CośTam
    out UDR,a
    ldi a,CośTam
    out UDR,a.... i tak kilka razy to...
    wykonujesz 8M zapisów do UDR na 1s (clk=16Mhz, i po 1 takcie na rozkaz w tym wypadku)
    UART musi wysłać StartBit 8bitów danych i StopBit(1szt a może 2) to 10(11)bitów.
    8M zapisów * 10bitów to daje jakieś 80Mbod'ów - no nieżle!
    80MHz to jak pisałem UKF ale jak weżmiemy pod uwagę, że UART zwykle kilka razy próbkuje bit(choćby dlatego, że synchronizuje się ze zboczem StartBitu) to jego wewnętrzny zegar będzie musiał mieć już naprawdę imponującą wartość!

    Dodano po 6 [minuty]:

    No dobrze puściłem wodzę fantazji a nie zapytałem jaką linią to przesyłasz i czym odbierasz (jaką antenkę przypiąłeś do PCeta) ;)
    Sorki - teraz poważniej:
    przez bufor w RAM waść wysyłaj, a czyń to przez przerwania - UART ma ich chyba coś ze 3.
  • #13 4200308
    innocent
    Poziom 11  
    Posty: 10
    Ok:)
    Jak już wykazał zumek, moja wiedza na temat poprawnego programowania avr jest dosyć mała. Na razie robiłem tak, żeby działało:) a widać że jak troche skomplikowałem, działać przestało.

    Przepiszę wysyłanie na przerwania:)

    A masz może pomysł czemu to u mnie nie działało i były takie dziwne objawy (z tą jedną linijką) a u kumpla działało i to bez żadnych poprawek?
  • #14 4201573
    kamyczek
    Poziom 38  
    Posty: 3994
    Pomógł: 394
    Ocena: 570
    bufor uarta to nie stos wysyłając mu tyle w czasie kilku cykli na bnank zgubi sporą część a samo przerwanie z tego co mi sie przypomina należy wyzerować ręcznie podczas jego obsługi flagę inaczej wystąpi ono tylko raz ,...
  • #15 4204393
    innocent
    Poziom 11  
    Posty: 10
    Bałwan jestem i tyle:)
    Nie znałem etykiet adresów, makr... eh. Już znam:)
    Dziękuję za pomoc i za wytknięcie mi mojej niewiedzy. Przepiszę część programu z dodaniem lepszej obsługi UARTa i zobaczymy czy się uda odpalić. Jak coś dalej będzie nie tak, napiszę.

Podsumowanie tematu

✨ Dyskusja dotyczy problemu z nieprawidłowym działaniem przerwania RXC w mikrokontrolerze ATmega32 (16 MHz) programowanym w asemblerze, używanym do sterowania silnikami krokowymi poprzez interfejs UART. Autor opisuje, że przerwanie RXC nie działa poprawnie, mimo że kod działa u innego użytkownika na innym komputerze. Wątpliwości budzi fragment kodu asemblerowego, w którym zmienna jest ładowana z dwóch różnych miejsc, co może wskazywać na błędy w obsłudze rejestrów i stosu. Zwrócono uwagę na brak ochrony rejestru statusu SREG w obsłudze przerwania oraz na potencjalne konflikty sygnałów portu C z interfejsem JTAG, które mogą powodować problemy sprzętowe. Dyskutowano także o sposobie wysyłania danych przez UART – bez bufora i przerwań, co może prowadzić do utraty danych z powodu zbyt szybkiego zapisu do rejestru UDR. Sugerowano implementację obsługi UART z wykorzystaniem przerwań i bufora w RAM, a także poprawę czytelności kodu przez stosowanie makr, etykiet i komentarzy. Autor przyznaje się do braku doświadczenia z makrami i etykietami, planuje poprawić kod i ponownie przetestować działanie przerwania RXC. Wskazano, że różnice w działaniu programu na różnych komputerach mogą wynikać z konfiguracji sprzętowej lub środowiska programistycznego.
Wygenerowane przez model językowy.
REKLAMA