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

[Atmega16][asm]Graficzny wyświetlacz LCD.

maciej_333 06 Lis 2010 22:30 4256 27
REKLAMA
  • #1 8711475
    maciej_333
    Poziom 38  
    Usiłuję nawiązać jakąś komunikację z wyświetlaczem graficznym LGM2412. Ma on rozdzielczość 240x128 pikseli. Jednak ze strony wyświetlacza nie ma odzewu. Poniżej kod:
    .nolist
    .include "m16def.inc"
    .list
    .cseg
    
    ;sterowanie LCD
    .EQU WR   = 7
    .EQU RD   = 6
    .EQU CE   = 5
    .EQU C_D  = 4
    .EQU RST  = 3
    .EQU FS   = 2
    .EQU STER_LCD     = PORTA
    .EQU STER_LCD_DDR = DDRA
    
    ;dane LCD
    .EQU DANE_LCD     = PORTB
    .EQU DANE_LCD_DDR = DDRB
    .EQU DANE_LCD_PIN = PINB
    
    .org 0 rjmp RESET
    	reset_LCD:
    		cbi STER_LCD,RST
    		ldi R17,254
    		delay:
    			inc R17
    		brne delay
    		sbi STER_LCD,RST
    	ret
    
    
    	zajety_tryb_zwykly:
    		;szyna danych LCD - jako wejście
    		clr R17
    		out DANE_LCD_DDR, R17 ;DDRB
    		ser R17
    		out DANE_LCD, R17 ;PORTB
    
    		sbi STER_LCD,WR
    		sbi STER_LCD,C_D
    		cbi STER_LCD,RD
    		nop
    		nop
    		cbi STER_LCD,CE
    
    		ldi R16,0x03
    		oczekiwanie:
    			in R17,DANE_LCD_PIN
    			andi R17,0x03
    			cpse R17,R16
    		rjmp oczekiwanie
    		sbi STER_LCD,CE
    	ret
    
    	zajety_tryb_auto:
    		;szyna danych LCD - jako wejście
    		clr R17
    		out DANE_LCD_DDR, R17 ;DDRB
    		ser R17
    		out DANE_LCD, R17 ;PORTB
    
    		sbi STER_LCD,WR
    		sbi STER_LCD,C_D
    		cbi STER_LCD,RD
    		nop
    		nop
    		cbi STER_LCD,CE
    
    		ldi R16,0x0C
    		oczekiwanie_:
    			in R17,DANE_LCD_PIN
    			andi R17,0x0C
    			cpse R17,R16
    		rjmp oczekiwanie_
    		sbi STER_LCD,CE
    	ret
    
    	wyslij_polecenie:
    			;w R17 wysyłane polecenie
    			sbi STER_LCD,RD
    			cbi STER_LCD,WR
    			sbi STER_LCD,C_D
    
    			;szyna danych LCD - jako wyjście
    			ser R16
    			out DANE_LCD_DDR,R16
    			out DANE_LCD,R17
    
    			nop
    			nop
    			cbi STER_LCD,CE
    			nop
    			nop
    			sbi STER_LCD,CE
    	ret
    
    	wyslij_dane:
    			;w R17 wysyłane dane
    			sbi STER_LCD,RD
    			cbi STER_LCD,WR
    			cbi STER_LCD,C_D
    
    			;szyna danych LCD - jako wyjście
    			ser R16
    			out DANE_LCD_DDR,R16
    			out DANE_LCD,R17
    
    			nop
    			nop
    			cbi STER_LCD,CE
    			nop
    			nop
    			sbi STER_LCD,CE
    	ret
    
    RESET:
    
    ldi R17, high(RAMEND) ;inicjalizacja wskaźnika stosu
    ldi R16, low(RAMEND)
    out SPH, R17
    out SPL, R16
    
    ;ldi R20,0xFF
    ;out DDRA,R20
    ;out PORTA,R20 ;dioda zgaszona i port ustawiony jako wyjście
    
    ldi R17, 0x00
    out DANE_LCD_DDR, R17 ;DDRB
    
    ldi R17, 0xFF
    out DANE_LCD, R17 ;PORTB
    
    ;konfiguracja linii sterujących LCD
    clr R17
    ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)|(1<<RST)|(1<<FS)
    out STER_LCD_DDR,R17
    out STER_LCD,R17
    
    
    rcall reset_LCD
    
    rcall zajety_tryb_zwykly
    ldi R17,0x93 ;cursor on, blink on
    rcall wyslij_polecenie
    
    rcall zajety_tryb_zwykly
    ldi R17,0x83 ;AND mode
    rcall wyslij_polecenie
    
    rcall zajety_tryb_zwykly
    ldi R17,0xA2 ;3-line cursor
    rcall wyslij_polecenie
    
    
    petla_glowna:
    rjmp petla_glowna
    

    Pracuję na wewnętrznym taktowaniu 4MHz. Datasheet od tego wyświetlacza jest tu. Sterownik na module LCD to T6963C. Teoretycznie przedstawiony program powinien zresetować LCD i wyświetlić migający kursor o wybranym rozmiarze.

    Osoba, która udzieli pomocnej odpowiedzi otrzyma 100 punktów.
  • REKLAMA
  • Pomocny post
    #2 8714397
    Andrzej__S
    Poziom 28  
    Proponuję lekturę Writing Software for T6963C based Graphic LCDs.

    Zgodnie z tym dokumentem napisałbym np. procedurę odczytu statusu mniej więcej tak:
    
    status_check: 
          ;szyna danych LCD - jako wejście 
          clr R17 
          out DANE_LCD_DDR, R17 ;DDRB 
    
          sbi STER_LCD, C_D   ; C/D = 1
          sbi STER_LCD, WR    ; WR = 1
          cbi STER_LCD, RD    ; RD = 0
          ldi r16, 0x03       ; STA0 = 1 , STA1 = 1
    
    status_loop1:
          cbi STER_LCD, CE
          nop                  ; opóźnienie na ustawienie danych przez LCD
          in R17,DANE_LCD_PIN
          andi R17, 0x03
          sbi STER_LCD, CE
          cpse R17, R16       ; sprawdzenie czy STA0 = 1 i STA1 = 1
          rjmp status_loop1   ; jeżeli nie, ponów pętlę
          sbi STER_LCD, RD    ; jeżeli tak, zakończ działanie procedury
          ret
    
    


    Poza tym poczytaj dokładnie rozdział 5 - "Initialising the display", bo wygląda na to, że masz nieprawidłową/niepełną inicjalizację wyświetlacza. Brakuje np. ustawienia takich parametrów jak TEXT HOME ADDRESS, TEXT AREA SET czy ADDRESS POINTER.

    Tutaj np. używasz DISPLAY MODE:
    
    ldi R17,0x93 ;cursor on, blink on
    

    ale bit 2, który jest odpowiedzialny za włączenie wyświetlacza tekstowego, masz ustawiony na 0.

    Aby kursor był widoczny, musisz też ustawić jego pozycję za pomocą CURSOR POINTER SET.

    Zwróć uwagę, że niektóre komendy wymagają wysłania dwóch lub trzech bajtów danych. Np. CURSOR POINTER SET wymaga wysłania po kolei:
    #1 bajt: współrzędna X
    #2 bajt: współrzędna Y
    #3 bajt: komenda 0x21
    Oczywiście przed wysłaniem każdego bajtu należy sprawdzać status.

    Życzę powodzenia.
  • #3 8716269
    maciej_333
    Poziom 38  
    Aktualnie mam taki kod:
    ;PORTB szyna danych LCD
    
    .nolist
    .include "m16def.inc"
    .list
    .cseg
    
    ;sterowanie LCD
    .EQU WR   = 7
    .EQU RD   = 6
    .EQU CE   = 5
    .EQU C_D  = 4
    .EQU RST  = 3
    .EQU FS   = 2
    .EQU STER_LCD     = PORTA
    .EQU STER_LCD_DDR = DDRA
    
    ;dane LCD
    .EQU DANE_LCD     = PORTB
    .EQU DANE_LCD_DDR = DDRB
    .EQU DANE_LCD_PIN = PINB
    
    ;instrukcje LCD
    .EQU TEXT_ATTRIBUTE_MODE = 0x8C
    .EQU SET_GRAPHIC_HOME_ADRESS = 0x42
    .EQU SET_GRAPHIC_AREA = 0x43
    .EQU SET_TEXT_HOME_ADRESS = 0x40
    .EQU SET_TEXT_AREA = 0x41
    ;.EQU MODE_SET = 0x82 ;internal CGROM, AND mode
    .EQU MODE_SET = 0x80 ;internal CGROM, OR mode
    .EQU DISPLAY_MODE = 0x9F
    .EQU SET_CURSOR_POINTER = 0x21
    .EQU SET_ADRESS_POINTER = 0x24
    .EQU DATA_WRITE_INC_ADP = 0xC0
    
    .org 0 rjmp RESET
    	reset_LCD:
    		cbi STER_LCD,RST
    		ldi R17,200
    		delay:
    			inc R17
    		brne delay
    		sbi STER_LCD,RST
    	ret
    
    
    	zajety_tryb_zwykly:
    	      ;szyna danych LCD - jako wejście 
    	      clr R17 
    	      out DANE_LCD_DDR, R17 ;DDRB 
    
    	      sbi STER_LCD, C_D   ; C/D = 1 
    	      sbi STER_LCD, WR    ; WR = 1 
    	      cbi STER_LCD, RD    ; RD = 0 
    	      ldi r16, 0x03       ; STA0 = 1 , STA1 = 1 
    
    		  status_loop1:
    		      cbi STER_LCD, CE 
    	    	  nop                  ; opóźnienie na ustawienie danych przez LCD 
    		      in R17,DANE_LCD_PIN 
    	    	  andi R17, 0x03 
    			  sbi STER_LCD, CE 
    	    	  cpse R17, R16       ; sprawdzenie czy STA0 = 1 i STA1 = 1 
    		  rjmp status_loop1   ; jeżeli nie, ponów pętlę 
    	      sbi STER_LCD, RD    ; jeżeli tak, zakończ działanie procedury 
        ret 
    
    
    
    	zajety_tryb_auto:
    		;szyna danych LCD - jako wejście
    		clr R17
    		out DANE_LCD_DDR, R17 ;DDRB
    		ser R17
    		out DANE_LCD, R17 ;PORTB
    
    		sbi STER_LCD,WR
    		sbi STER_LCD,C_D
    		cbi STER_LCD,RD
    		nop
    		nop
    		cbi STER_LCD,CE
    
    		ldi R16,0x0C
    		oczekiwanie_:
    			in R17,DANE_LCD_PIN
    			andi R17,0x0C
    			cpse R17,R16
    		rjmp oczekiwanie_
    		sbi STER_LCD,CE
    	ret
    
    	wyslij_instrukcje:
    			;w R17 wysyłane polecenie
    			sbi STER_LCD,RD
    			cbi STER_LCD,WR
    			sbi STER_LCD,C_D
    
    			;szyna danych LCD - jako wyjście
    			ser R16
    			out DANE_LCD_DDR,R16
    			out DANE_LCD,R17
    
    			nop
    			nop
    			cbi STER_LCD,CE
    			nop
    			nop
    			sbi STER_LCD,CE
    	ret
    
    	wyslij_dane:
    			;w R17 wysyłane dane
    			sbi STER_LCD,RD
    			cbi STER_LCD,WR
    			cbi STER_LCD,C_D
    
    			;szyna danych LCD - jako wyjście
    			ser R16
    			out DANE_LCD_DDR,R16
    			out DANE_LCD,R17
    
    			nop
    			nop
    			cbi STER_LCD,CE
    			nop
    			nop
    			sbi STER_LCD,CE
    	ret
    
    RESET:
    
    ldi R17, high(RAMEND) ;inicjalizacja wskaźnika stosu
    ldi R16, low(RAMEND)
    out SPH, R17
    out SPL, R16
    
    ldi R17, 0x00
    out DANE_LCD_DDR, R17 ;DDRB
    
    ldi R17, 0xFF
    out DANE_LCD, R17 ;PORTB
    
    ;konfiguracja linii sterujących LCD
    clr R17
    ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)|(1<<RST)|(1<<FS)
    out STER_LCD_DDR,R17
    out STER_LCD,R17
    
    
    rcall reset_LCD
    
    ;rcall zajety_tryb_zwykly
    ;ldi R17,TEXT_ATTRIBUTE_MODE
    ;rcall wyslij_instrukcje
    
    rcall zajety_tryb_zwykly
    ldi R17,0xFF ;młodszy bajt adresu
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,0x3F ;starszy bajt adresu
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,SET_GRAPHIC_HOME_ADRESS
    rcall wyslij_instrukcje
    
    rcall zajety_tryb_zwykly
    ldi R17,0x20 ;32 bajtów na pole grafiki
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,0x00
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,SET_GRAPHIC_AREA
    rcall wyslij_instrukcje
    
    rcall zajety_tryb_zwykly
    ldi R17,0x00
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,0x00
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,SET_TEXT_HOME_ADRESS
    rcall wyslij_instrukcje
    
    rcall zajety_tryb_zwykly
    ldi R17,0x20 ;32 bajtów na pole tekstu
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,0x00
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,SET_TEXT_AREA
    rcall wyslij_instrukcje
    
    rcall zajety_tryb_zwykly
    ldi R17,MODE_SET
    rcall wyslij_instrukcje
    
    rcall zajety_tryb_zwykly
    ldi R17,DISPLAY_MODE
    rcall wyslij_instrukcje
    
    rcall zajety_tryb_zwykly
    ldi R17,0x01 ;X
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,0x00 ;Y
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,SET_CURSOR_POINTER
    rcall wyslij_instrukcje
    
    rcall zajety_tryb_zwykly
    ldi R17,0x00 ;młodszy
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,0x00 ;starszy
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,SET_ADRESS_POINTER
    rcall wyslij_instrukcje
    
    rcall zajety_tryb_zwykly
    ldi R17,0x21 ;znak 'A'
    rcall wyslij_dane
    rcall zajety_tryb_zwykly
    ldi R17,DATA_WRITE_INC_ADP
    rcall wyslij_instrukcje
    
    
    petla_glowna:
    rjmp petla_glowna
    

    Na wyświetlaczu wyświetlają się same śmieci. Kursor miga na prawidłowej pozycji (ustawionej pozycji). Jednak litera 'A' nie pojawia się w wyznaczonym miejscu. Zamiast niej jest "krzak". Ponadto jak wyczyścić pamięć ? Wysłanie zerowego bajtu nie powoduje wyczyszczenia wybranego miejsca. Wskazany przez kolegę PDF okazał się być bardzo pomocny.
  • #4 8717260
    Andrzej__S
    Poziom 28  
    Nie mam teraz czasu, żeby analizować dokładnie kod. Na pierwszy rzut oka nie widzę błędów.
    Spróbuj ustawić GRAPHIC HOME ADRESS na 0x0200, bo Ty masz dużo większy i być może to powoduje problemy.

    Nie wiem, czy znasz tę stronę. Napisane w C, nie w assemblerze, ale wiele może wyjaśnić, np. w pliku T6963C.h jest przedstawione, jak obliczać takie parametry jak właśnie GRAPHIC HOME ADDRESS czy też TEXT AREA lub GRAPHIC AREA.
  • #5 8717681
    maciej_333
    Poziom 38  
    Przeanalizowałem kod kolegi radzio z podanej strony. Szczególnie plik nagłówkowy T6963C.h. Jednak nie do końca to rozumiem. Poniżej zaznaczyłem moją interpretację poszczególnych stałych.

    
    //-------------------------------------------------------------------------------------------------
    // Graphic LCD with Toshiba T6963 controller
    // Copyright (c) Radosław Kwiecień, 2007r
    // http://en.radzio.dxp.pl/t6963/
    // Compiler : avr-gcc
    //-------------------------------------------------------------------------------------------------
    
    // display properties
    #define GLCD_NUMBER_OF_LINES				128 //prawdopodobnie ilość linii w pikselach/ilość pikseli w pionie
    #define GLCD_PIXELS_PER_LINE				240
    #define GLCD_FONT_WIDTH						8 //zależne od linii FS -> dla FS=1 FONT_WIDTH=8
    //
    #define GLCD_GRAPHIC_AREA					(GLCD_PIXELS_PER_LINE / GLCD_FONT_WIDTH) //ilość znaków na linię 240/8=30
    #define GLCD_TEXT_AREA						(GLCD_PIXELS_PER_LINE / GLCD_FONT_WIDTH) //ilość znaków na linię 240/8=30
    #define GLCD_GRAPHIC_SIZE					(GLCD_GRAPHIC_AREA * GLCD_NUMBER_OF_LINES) //??? 30*128=3840 znaki*piksele ???
    #define GLCD_TEXT_SIZE						(GLCD_TEXT_AREA * (GLCD_NUMBER_OF_LINES/8))//jeżeli font jest 8x8, to jest to 
                                                                                           //ilość znaków w całym LCD 30*128/8=30*16=480
    
    
    #define GLCD_TEXT_HOME						0 //pewnie tekst ma się zaczynać od adresu 0x0000 w pamięci ???
    #define GLCD_GRAPHIC_HOME					(GLCD_TEXT_HOME + GLCD_TEXT_SIZE) //czyli grafika ma się znajdować zaraz za tekstem ???
    #define GLCD_OFFSET_REGISTER				2 //???
    #define GLCD_EXTERNAL_CG_HOME				(GLCD_OFFSET_REGISTER << 11) //jak rozumieć "offset register" 2 << 11=4096
    

    Dziękuję za zaangażowanie. Ustawienie GRAPHIC_HOME_ADRESS=0x2000 nic nie zmienia.
    [edit]
    Ustawiłem wszystkie parametry wg kodu kolegi radzio. Jednak w zasadzie dalej to samo.
  • Pomocny post
    #6 8718486
    Andrzej__S
    Poziom 28  
    Nie wiem, czy tylko tu się pomyliłeś, czy w kodzie też. Napisałeś, że ustawiłeś GRAPHIC_HOME_ADRESS=0x2000, a ja miałem na myśli raczej 0x0200. Jeśli LCD ma przykładowo 8K RAM, to wartość 0x2000 jest już poza zakresem. Trudno przewidzieć, co w takim przypadku będzie wyświetlane.

    
    #define GLCD_GRAPHIC_SIZE               (GLCD_GRAPHIC_AREA * GLCD_NUMBER_OF_LINES) //??? 30*128=3840 znaki*piksele ???
    

    No tak 30 bajtów 8bitowych (dla ustawienia FS=1) * 128 wierszy (linii) daje:
    30*8*128=240*128=30720 bitów (30*128=3840 bajtów)
    czyli tyle bitów ile pikseli. Inaczej mówiąc GLCD_GRAPHIC_SIZE to rozmiar (w bajtach) pamięci graficznej.

    
    #define GLCD_OFFSET_REGISTER            2 //??? 
    #define GLCD_EXTERNAL_CG_HOME            (GLCD_OFFSET_REGISTER << 11) //jak rozumieć "offset register" 2 << 11=4096
    

    Masz to opisane na ostatniej stronie dokumentu, do którego link umieściłem w pierwszym swoim poście. GLCD_OFFSET_REGISTER to po prostu najstarsze 5 bitów adresu bazowego do przechowywania znaków "user defined". Stąd też to przesunięcie o 11 bitów w lewo (16-5). Można zdefiniować maks. 256 znaków. W trybie "Internal CG" dostępnych dla użytkownika jest "górne" 128, czyli znaki o kodach 0x80 do 0xFF. Znaki od 0x00 do 0x7F wyświetlane są wtedy z wewnętrznej pamięci ROM. W trybie "External CG" dostępnych jest wszystkie 256 znaków. Każdy znak to 8 bajtów, dlatego obszar pamięci potrzebny na zapamiętanie tych znaków zawiera się w granicach:
    od (GLCD_OFFSET_REGISTER << 11)
    do (GLCD_OFFSET_REGISTER << 11) + (256*8 - 1) = (GLCD_OFFSET_REGISTER << 11) + 0x07FF

    Jeśli nie będziesz definiował|używał własnych znaków, możesz nie ustawiać offsetu. Ewentualnie dla pewności możesz ustawić go tak, by obszar danych znaków definiowalnych nie pokrywał się z innymi danymi.

    Co do kodu, na razie nie dopatrzyłem się błędów (poza tym GRAPHIC_HOME_ADRESS). Proponuję spróbować nie włączać wyświetlania grafiki (DISPLAY_MODE=0x97). Jak nie pomoże, to jeszcze raz sprawdzić, czy na pewno wszystkie parametry są dobrze ustawione.
  • REKLAMA
  • #7 8718979
    maciej_333
    Poziom 38  
    Pomyliłem się z tym GRAPHIC_HOME_ADRESS (również w kodzie). Na module LCD znajduje się układ 62256, czyli mam pamięć RAM 32KB. Czy cała szyna adresowa pamięci jest dołączona do sterownika, tego nie wiem. Pokombinuję jeszcze z tym LCD jak wrócę w środę do domu. Spróbuję też pewnie odpalić kod w C, choć i tak muszę mieć swoje procedury obsługi.
  • REKLAMA
  • #8 8721594
    Konto nie istnieje
    Konto nie istnieje  
  • #9 8726846
    maciej_333
    Poziom 38  
    Ustawiłem GRAPHIC_HOME_ADRESS na 0x0200 i jest pewna różnica. Otóż w wybranych pozycjach na wyświetlaczu pojawia się to co powinno. Jednak w polu każdego znaku znajdują się piksele, które nie powinny się palić.

    Wyłączyłem też prowizorycznie tryb graficzny. Wówczas wszystko wyświetla się tak jak powinno. Wysłanie bajtu 0x00 powoduje "wyczyszczenie" danego pola znaku. W związku z tym coś nie tak jest z ustawieniami grafiki...
  • #10 8727368
    Andrzej__S
    Poziom 28  
    Spróbuj może jeszcze wyczyścić pamięć grafiki, czyli jeżeli GRAPHIC_HOME_ADRESS masz równy 0x0200, a GRAPHIC_AREA=3840, to wprowadź 0x00 do komórek pamięci od 0x0200 do 0x10FF.
    Zresztą pewnie nie zaszkodziłoby wyczyszczenie całej pamięci, albo przynajmniej używanego obszaru.
  • #11 8729284
    Andrzej__S
    Poziom 28  
    Ten dokument też może okazać się przydatny.

    Proponowałbym też:

    #1 nie ustawiać pinu /RESET wstępnie w stan wysoki, czyli zamiast:
    
    RESET:
    .....
    
    ;konfiguracja linii sterujących LCD 
    clr R17 
    ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)|(1<<RST)|(1<<FS) 
    out STER_LCD_DDR,R17 
    out STER_LCD,R17 
    
    
    rcall reset_LCD
    

    zrobiłbym np. tak:
    
    RESET:
    .....
    
    ;konfiguracja linii sterujących LCD 
    clr R17 
    ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)|(1<<RST)|(1<<FS) 
    out STER_LCD_DDR,R17 
    ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)|(1<<FS) 
    out STER_LCD,R17 
    
    
    rcall reset_LCD
    


    #2 wydłużyć czas resetu, bo zgodnie z dokumentacją powinien mieć min. 1ms (patrz tabelka na stronie 25 podanego wyżej dokumentu, rozdział "Recommended Initialization"), a u Ciebie jest 0,04ms:
    
       reset_LCD: 
          cbi STER_LCD,RST 
          ldi R17,200 
          delay: 
          inc R17    ; pętla wykona się 55 razy !!!
          brne delay ; a trwa 3 takty
                     ; więc całkowite opóźnienie wyniesie 55*3=165 taktów
                     ; +2 takty na wykonanie 'inc R17' i 'brne delay' w ostatniej (56-tej) pętli, czyli 167 taktów
                     ; +1 takt na wykonanie 'ldi R17,200', czyli 168 taktów
                     ; tak więc dla zegara 4MHz będzie to ok. 0,04ms 
          sbi STER_LCD,RST 
       ret
    
  • #12 8736344
    maciej_333
    Poziom 38  
    Zwiększyłem czas resetu do ok. 2ms. Jednak w oryginalnym pdf Toshiby podano, że reset ma trwać przynajmniej 15 okresów zegara dla T6963C. Na moim module LCD występuje rezonator 6MHz. Wyczyściłem też całą pamięć RAM. Jest o wiele lepiej, chociaż nie ma niepotrzebnych pikseli w polach wyświetlanych znaków. Jednak teraz jeżeli mam załączony tryb tekstowy i graficzny, to wysłanie bajtu 0xFF pod GRAPHIC_HOME_ADRESS=0x0200 powinno spowodować zapalenie wszystkich pikseli tego bajtu pamięci. Tak, się dzieje, ale zapalają się piksele na samym początku ekranu, gdzie teoretycznie jest pole tekstu. Poniżej aktualny kod:
    .nolist 
    .include "m16def.inc" 
    .list 
    .cseg 
    
    ;parametry LCD
    .EQU MAX_RAM_LCD = 0x7FFF ;256Kb=32KB
    .EQU MAX_X = 240
    .EQU MAX_Y = 128
    .EQU FONT_WIDTH = 8 ;8x8 font
    
    .EQU TEXT_HOME_ADRESS    = 0x0000
    .EQU TEXT_AREA           = MAX_X / FONT_WIDTH
    .EQU GRAPHIC_HOME_ADRESS = 0x0200
    .EQU GRAPHIC_AREA        = MAX_X / FONT_WIDTH
    
    ;sterowanie LCD 
    .EQU WR   = 7 
    .EQU RD   = 6 
    .EQU CE   = 5 
    .EQU C_D  = 4 
    .EQU RST  = 3 
    .EQU STER_LCD     = PORTA 
    .EQU STER_LCD_DDR = DDRA 
    
    ;dane LCD 
    .EQU DANE_LCD     = PORTB 
    .EQU DANE_LCD_DDR = DDRB 
    .EQU DANE_LCD_PIN = PINB 
    
    ;instrukcje LCD 
    .EQU TEXT_ATTRIBUTE_MODE     = 0x8C 
    .EQU SET_GRAPHIC_HOME_ADRESS = 0x42 
    .EQU SET_GRAPHIC_AREA        = 0x43 
    .EQU SET_TEXT_HOME_ADRESS    = 0x40 
    .EQU SET_TEXT_AREA           = 0x41 
    
    ;Mode Set
    .EQU MD = 0
    ;MD=0 -> OR  MODE
    ;MD=1 -> XOR MODE
    ;MD=2 -> AND MODE
    ;MD=4 -> TEXT ATTRIBUTE MODE
    ;CG=0 -> Internal CG ROM; 1 -> RAM CG
    .EQU CG = 0
    .EQU MODE_SET = MD + 8*CG + 0x80
    
    ;Display Mode
    .EQU GRAPH  = 1
    .EQU TEXT   = 1
    .EQU CURSOR = 1
    .EQU BLINK  = 1
    .EQU DISPLAY_MODE = BLINK + 2*CURSOR + 4*TEXT + 8*GRAPH + 0x90
    
    .EQU SET_CURSOR_POINTER  = 0x21 
    .EQU SET_ADRESS_POINTER  = 0x24 
    .EQU DATA_WRITE_INC_ADP  = 0xC0 
    .EQU DATA_WRITE_NONV_ADP = 0xC4
    
    ;Cursor Pattern Select
    .EQU LINE = 7
    ;LINE = 0 -> 1-line cursor
    ;LINE = 1 -> 2-line cursor
    ;LINE = 2 -> 3-line cursor
    ;LINE = 3 -> 4-line cursor
    ;LINE = 4 -> 5-line cursor
    ;LINE = 5 -> 6-line cursor
    ;LINE = 6 -> 7-line cursor
    ;LINE = 7 -> 8-line cursor
    .EQU CURSOR_PATTERN_SELECT = LINE + 0xA0
    
    .org 0 rjmp RESET 
       reset_LCD: 
          cbi STER_LCD,RST
    
    ;      ldi R17,200 ;1
          ldi R17,155 ;1
          delay:
    	  	ldi R16,230 ;1
    		delay2:
    			inc R16 ;1
    		brne delay2 ;2/1, 1+25*3+1+1=78
    
            inc R17 ;1 cykl
          brne delay ;2 cykle / 1 gdy nie ma skoku
    	  			;pętla wykona się 155 razy, czyli 1+100*81 cykli
    				;w 256 skoku mamy 1+100*81+1+1=8103*(4MHz)^-1=2,02575ms
          sbi STER_LCD,RST
       ret 
    
       wyczysc_RAM_LCD:
    		ldi R18,0x00 ;młodszy 
    		rcall wyslij_dane 
    		ldi R18,0x00 ;starszy 
    		rcall wyslij_dane 
    		ldi R18,SET_ADRESS_POINTER 
    		rcall wyslij_instrukcje 
    
    		clr R25
    		clr R24
    
    		wysylaj:
    			ldi R18, 0x00
    			rcall wyslij_dane
    			ldi R18, DATA_WRITE_INC_ADP
    			rcall wyslij_instrukcje
    
    			cpi R24, MAX_RAM_LCD & 0xFF
    			brne przeskocz
    				cpi R25, (MAX_RAM_LCD & 0xFF00) >> 8
    				brne przeskocz
    					ret
    			przeskocz:
    			adiw R24, 1
    		rjmp wysylaj
       ret
    
       zajety: 
             ;szyna danych LCD - jako wejście 
             clr R17 
             out DANE_LCD_DDR, R17 ;DDRB 
    
             sbi STER_LCD, C_D   ; C/D = 1 
             sbi STER_LCD, WR    ; WR = 1 
             cbi STER_LCD, RD    ; RD = 0 
             ldi r16, 0x03       ; STA0 = 1 , STA1 = 1 
    
            status_loop1: 
                cbi STER_LCD, CE 
                nop                  ; opóźnienie na ustawienie danych przez LCD 
                in R17,DANE_LCD_PIN 
                andi R17, 0x03 
                sbi STER_LCD, CE 
                cpse R17, R16       ; sprawdzenie czy STA0 = 1 i STA1 = 1 
            rjmp status_loop1   ; jeżeli nie, ponów pętlę 
             sbi STER_LCD, RD    ; jeżeli tak, zakończ działanie procedury 
        ret 
    
       wyslij_instrukcje: 
             ;w R18 wysyłane polecenie 
    		 rcall zajety
             sbi STER_LCD,RD 
             cbi STER_LCD,WR 
             sbi STER_LCD,C_D 
    
             ;szyna danych LCD - jako wyjście 
             ser R16 
             out DANE_LCD_DDR,R16 
             out DANE_LCD,R18
    
             nop 
             nop 
             cbi STER_LCD,CE 
             nop 
             nop 
             sbi STER_LCD,CE 
       ret 
    
       wyslij_dane: 
             ;w R18 wysyłane dane 
    		 rcall zajety
             sbi STER_LCD,RD 
             cbi STER_LCD,WR 
             cbi STER_LCD,C_D 
    
             ;szyna danych LCD - jako wyjście 
             ser R16 
             out DANE_LCD_DDR,R16 
             out DANE_LCD,R18
    
             nop 
             nop 
             cbi STER_LCD,CE 
             nop 
             nop 
             sbi STER_LCD,CE 
       ret 
    
       dzielenie:
       		;R17 dzielna
       		;R16 dzielnik
    		;w R17 wynik ; w R16 reszta
    		tst R17
    		brne zero
    			clr R16
    			ret
    		zero:
    
    		clr R18
    		petla:
    			inc R18
    			mul R18,R16 ;sprawdzenie czy R18 jest wynikiem
    			push R17
    			sub R17,R0 ;obliczenie reszty
    			cp R17,R16 ;jeżeli R17=<R16 to R18 jest wynikiem
    			brsh koniec
    				mov R16,R17
    				mov R17,R18
    				pop R18 ;kasowanie wierzchołka stosu, by dało się wrócić
    				ret
    			koniec:
    			pop R17
    		rjmp petla
       ret
    
       zapal_piksel:
       		;X=R18 ; Y=R19
    		ldi R25,(GRAPHIC_HOME_ADRESS & 0xFF00) >> 8
    		ldi R24,GRAPHIC_HOME_ADRESS & 0xFF
    
    		mov R17,R18
    		ldi R16,FONT_WIDTH
    		rcall dzielenie
    		push R16
    		add R24,R17
    		clr R18
    		adc R25,R18
    
    		ldi R18,GRAPHIC_AREA
    		mul R18,R19
    
    		add R24,R0
    		adc R25,R1
    
    		mov R18,R24
    		rcall wyslij_dane
    		mov R18,R25
    		rcall wyslij_dane
    		ldi R18,SET_ADRESS_POINTER 
    		rcall wyslij_instrukcje 
    
    		pop R16
    		ldi R18,0xF8 ;zapalenie piksela
    		or R18,R16
    		rcall wyslij_instrukcje
       ret
    
       init_LCD:
       		;configuracja szyny danych LCD
    	   ldi R17, 0x00 
    	   out DANE_LCD_DDR, R17 ;DDRB 
    	   
    	   ldi R17, 0xFF
    	   out DANE_LCD, R17 ;PORTB 
    	   
    	   ;konfiguracja linii sterujących LCD
    	   clr R17 
    	   ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)|(1<<RST)
    	   out STER_LCD_DDR,R17
    	   ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)
    	   out STER_LCD,R17 
    	   
    	   rcall reset_LCD 
    	   rcall wyczysc_RAM_LCD
    	   
    	   ldi R18,GRAPHIC_HOME_ADRESS & 0xFF ;młodszy bajt adresu
    	   rcall wyslij_dane
    	   ldi R18,(GRAPHIC_HOME_ADRESS & 0xFF00) >> 8 ;starszy bajt adresu
    	   rcall wyslij_dane
    	   ldi R18,SET_GRAPHIC_HOME_ADRESS ;!!!
    	   rcall wyslij_instrukcje 
    	   
    	   ldi R18,GRAPHIC_AREA
    	   rcall wyslij_dane 
    	   ldi R18,0x00 
    	   rcall wyslij_dane 
    	   ldi R18,SET_GRAPHIC_AREA 
    	   rcall wyslij_instrukcje 
    	   
    	   ldi R18,TEXT_HOME_ADRESS & 0xFF
    	   rcall wyslij_dane 
    	   ldi R18,(TEXT_HOME_ADRESS & 0xFF00) >> 8
    	   rcall wyslij_dane 
    	   ldi R18,SET_TEXT_HOME_ADRESS 
    	   rcall wyslij_instrukcje 
    	   
    	   ldi R18,TEXT_AREA
    	   rcall wyslij_dane 
    	   ldi R18,0x00 
    	   rcall wyslij_dane 
    	   ldi R18,SET_TEXT_AREA 
    	   rcall wyslij_instrukcje 
    	   
    	   ldi R18,MODE_SET 
    	   rcall wyslij_instrukcje 
    	   
    	   ldi R18,DISPLAY_MODE 
    	   rcall wyslij_instrukcje 
    	   
    	   ldi R18,0x04 ;X 
    	   rcall wyslij_dane 
    	   ldi R18,0x01 ;Y 
    	   rcall wyslij_dane 
    	   ldi R18,SET_CURSOR_POINTER 
    	   rcall wyslij_instrukcje 
    	   
    	   ldi R18,CURSOR_PATTERN_SELECT
    	   rcall wyslij_instrukcje 
    	 ret
    RESET: 
    
    ldi R17, high(RAMEND) ;inicjalizacja wskaźnika stosu 
    ldi R16, low(RAMEND) 
    out SPH, R17 
    out SPL, R16 
    
    rcall init_LCD
    
    ldi R18,0x29 ;młodszy 
    rcall wyslij_dane 
    ldi R18,0x00 ;starszy 
    rcall wyslij_dane 
    ldi R18,SET_ADRESS_POINTER 
    rcall wyslij_instrukcje 
    
    ldi R18,0x48 ;znak 'h' 
    rcall wyslij_dane 
    ldi R18,DATA_WRITE_INC_ADP 
    rcall wyslij_instrukcje 
    
    ldi R18,0x22 ;znak 'B' 
    rcall wyslij_dane 
    ldi R18,DATA_WRITE_INC_ADP 
    rcall wyslij_instrukcje 
    
    ldi R18,0x23 ;znak 'C' 
    rcall wyslij_dane 
    ldi R18,DATA_WRITE_INC_ADP 
    rcall wyslij_instrukcje 
    
    ldi R18,0x21 ;znak 'A' 
    rcall wyslij_dane 
    ldi R18,DATA_WRITE_INC_ADP 
    rcall wyslij_instrukcje 
    
    ldi R18,0x00 ;nic
    rcall wyslij_dane 
    ldi R18,DATA_WRITE_INC_ADP 
    rcall wyslij_instrukcje 
    
    
    
    ldi R18,0x00 ;młodszy 
    rcall wyslij_dane 
    ldi R18,0x02 ;starszy 
    rcall wyslij_dane 
    ldi R18,SET_ADRESS_POINTER 
    rcall wyslij_instrukcje 
    
    ldi R18,0xFF 
    rcall wyslij_dane 
    ldi R18,DATA_WRITE_NONV_ADP 
    rcall wyslij_instrukcje 
    
    
    petla_glowna: 
    rjmp petla_glowna
    
  • REKLAMA
  • Pomocny post
    #13 8737362
    Andrzej__S
    Poziom 28  
    Cytat:

    Jednak teraz jeżeli mam załączony tryb tekstowy i graficzny, to wysłanie bajtu 0xFF pod GRAPHIC_HOME_ADRESS=0x0200 powinno spowodować zapalenie wszystkich pikseli tego bajtu pamięci. Tak, się dzieje, ale zapalają się piksele na samym początku ekranu, gdzie teoretycznie jest pole tekstu.

    Tak właśnie powinno być. Zarówno tryb graficzny jak i tekstowy mają do dyspozycji cały ekran. Wpisywanie danych pod adresy TEXT_HOME_ADRESS lub GRAPHIC_HOME_ADRESS powoduje wyświetlanie tych danych w lewym górnym rogu. Relacja między danymi tekstowymi i graficznymi jest określona poprzez MODE_SET:
    OR - dany piksel "zapala się", jeżeli w trybie tekstowym LUB w trybie graficznym jego wartość jest równa 1
    AND - dany piksel "zapala się", jeżeli w trybie tekstowym ORAZ w trybie graficznym jego wartość jest równa 1
    EXOR - dany piksel "zapala się", jeżeli w trybie tekstowym ma wartość 1 a w trybie geaficznym ma wartość 0, ORAZ, jeżeli w trybie tekstowym ma wartość 0 a a trybie geaficznym ma wartość 1; jeżeli w obydwu trybach piksel ma wartość 0 LUB w obydwu trybach ma wartość 1 piksel jest "zgaszony"

    Masz to przedstawione graficznie np. w dokumencie - podanym przez Ciebie w pierwszym poście - na stronie 20.
  • Pomocny post
    #14 8738073
    Konto nie istnieje
    Konto nie istnieje  
  • #15 8739622
    maciej_333
    Poziom 38  
    Myślę, że rozwiązałem już większość problemów z tym LCD. Mam już działającą funkcję zapal_piksel. Poniżej dość ostateczny kod (może ktoś skorzysta):
    .nolist 
    .include "m16def.inc" 
    .list 
    .cseg 
    
    ;parametry LCD
    .EQU MAX_RAM_LCD = 0x7FFF ;256Kb=32KB
    .EQU MAX_X = 240
    .EQU MAX_Y = 128
    .EQU FONT_WIDTH = 6 ;6x8 font
    
    .EQU TEXT_AREA           = MAX_X / FONT_WIDTH
    .EQU GRAPHIC_AREA        = MAX_X / FONT_WIDTH
    .EQU GRAPHIC_SIZE        = (GRAPHIC_AREA * MAX_Y)
    .EQU TEXT_SIZE           = (TEXT_AREA * (MAX_Y/8))
    
    .EQU TEXT_HOME_ADRESS    = 0x0000
    .EQU GRAPHIC_HOME_ADRESS = TEXT_HOME_ADRESS + TEXT_SIZE
    
    .EQU OFFSET_REGISTER     = 2
    .EQU EXTERNAL_CG_HOME    = OFFSET_REGISTER << 11
    
    ;sterowanie LCD 
    .EQU WR   = 7 
    .EQU RD   = 6 
    .EQU CE   = 5 
    .EQU C_D  = 4 
    .EQU RST  = 3 
    .EQU STER_LCD     = PORTA 
    .EQU STER_LCD_DDR = DDRA 
    
    ;dane LCD 
    .EQU DANE_LCD     = PORTB 
    .EQU DANE_LCD_DDR = DDRB 
    .EQU DANE_LCD_PIN = PINB 
    
    ;instrukcje LCD 
    .EQU TEXT_ATTRIBUTE_MODE     = 0x8C 
    .EQU SET_GRAPHIC_HOME_ADRESS = 0x42 
    .EQU SET_GRAPHIC_AREA        = 0x43 
    .EQU SET_TEXT_HOME_ADRESS    = 0x40 
    .EQU SET_TEXT_AREA           = 0x41 
    
    ;Mode Set
    .EQU MD = 0
    ;MD=0 -> OR  MODE
    ;MD=1 -> XOR MODE
    ;MD=2 -> AND MODE
    ;MD=4 -> TEXT ATTRIBUTE MODE
    ;CG=0 -> Internal CG ROM; 1 -> RAM CG
    .EQU CG = 0
    .EQU MODE_SET = MD + 8*CG + 0x80
    
    ;Display Mode
    .EQU GRAPH  = 1
    .EQU TEXT   = 1
    .EQU CURSOR = 1
    .EQU BLINK  = 1
    .EQU DISPLAY_MODE = BLINK + 2*CURSOR + 4*TEXT + 8*GRAPH + 0x90
    
    .EQU SET_CURSOR_POINTER  = 0x21 
    .EQU SET_ADRESS_POINTER  = 0x24 
    .EQU SET_OFFSET_REGISTER = 0x22
    .EQU DATA_WRITE_INC_ADP  = 0xC0 
    .EQU DATA_WRITE_NONV_ADP = 0xC4
    
    ;Cursor Pattern Select
    .EQU LINE = 7
    ;LINE = 0 -> 1-line cursor
    ;LINE = 1 -> 2-line cursor
    ;LINE = 2 -> 3-line cursor
    ;LINE = 3 -> 4-line cursor
    ;LINE = 4 -> 5-line cursor
    ;LINE = 5 -> 6-line cursor
    ;LINE = 6 -> 7-line cursor
    ;LINE = 7 -> 8-line cursor
    .EQU CURSOR_PATTERN_SELECT = LINE + 0xA0
    
    .org 0 rjmp RESET 
       reset_LCD: 
          cbi STER_LCD,RST
    
    ;      ldi R17,200 ;1
          ldi R17,155 ;1
          delay:
    	  	ldi R16,230 ;1
    		delay2:
    			inc R16 ;1
    		brne delay2 ;2/1, 1+25*3+1+1=78
    
            inc R17 ;1 cykl
          brne delay ;2 cykle / 1 gdy nie ma skoku
    	  			;pętla wykona się 155 razy, czyli 1+100*81 cykli
    				;w 256 skoku mamy 1+100*81+1+1=8103*(4MHz)^-1=2,02575ms
          sbi STER_LCD,RST
       ret 
    
       wyczysc_RAM_LCD:
    		ldi R18,0x00 ;młodszy 
    		rcall wyslij_dane 
    		ldi R18,0x00 ;starszy 
    		rcall wyslij_dane 
    		ldi R18,SET_ADRESS_POINTER 
    		rcall wyslij_instrukcje 
    
    		clr R25
    		clr R24
    
    		wysylaj:
    			ldi R18, 0x00
    			rcall wyslij_dane
    			ldi R18, DATA_WRITE_INC_ADP
    			rcall wyslij_instrukcje
    
    			cpi R24, MAX_RAM_LCD & 0xFF
    			brne przeskocz
    				cpi R25, (MAX_RAM_LCD & 0xFF00) >> 8
    				brne przeskocz
    					ret
    			przeskocz:
    			adiw R24, 1
    		rjmp wysylaj
       ret
    
       zajety: 
             ;szyna danych LCD - jako wejście 
             clr R17 
             out DANE_LCD_DDR, R17 ;DDRB 
    
             sbi STER_LCD, C_D   ; C/D = 1 
             sbi STER_LCD, WR    ; WR = 1 
             cbi STER_LCD, RD    ; RD = 0 
             ldi r16, 0x03       ; STA0 = 1 , STA1 = 1 
    
            status_loop1: 
                cbi STER_LCD, CE 
                nop                  ; opóźnienie na ustawienie danych przez LCD 
                in R17,DANE_LCD_PIN 
                andi R17, 0x03 
                sbi STER_LCD, CE 
                cpse R17, R16       ; sprawdzenie czy STA0 = 1 i STA1 = 1 
            rjmp status_loop1   ; jeżeli nie, ponów pętlę 
             sbi STER_LCD, RD    ; jeżeli tak, zakończ działanie procedury 
        ret 
    
       wyslij_instrukcje: 
             ;w R18 wysyłane polecenie 
    		 rcall zajety
             sbi STER_LCD,RD 
             cbi STER_LCD,WR 
             sbi STER_LCD,C_D 
    
             ;szyna danych LCD - jako wyjście 
             ser R16 
             out DANE_LCD_DDR,R16 
             out DANE_LCD,R18
    
             nop 
             nop 
             cbi STER_LCD,CE 
             nop 
             nop 
             sbi STER_LCD,CE 
       ret 
    
       wyslij_dane: 
             ;w R18 wysyłane dane 
    		 rcall zajety
             sbi STER_LCD,RD 
             cbi STER_LCD,WR 
             cbi STER_LCD,C_D 
    
             ;szyna danych LCD - jako wyjście 
             ser R16 
             out DANE_LCD_DDR,R16 
             out DANE_LCD,R18
    
             nop 
             nop 
             cbi STER_LCD,CE 
             nop 
             nop 
             sbi STER_LCD,CE 
       ret 
    
       dzielenie:
       		;R17 dzielna
       		;R16 dzielnik
    		;w R17 wynik ; w R16 reszta
    		cp R17,R16
    		brsh mniejszy
    			mov R16,R17
    			clr R17
    			ret
    		mniejszy:
    
    		tst R17
    		brne zero
    			clr R16
    			ret
    		zero:
    
    		clr R18
    		petla:
    			inc R18
    			mul R18,R16 ;sprawdzenie czy R18 jest wynikiem
    			push R17
    			sub R17,R0 ;obliczenie reszty
    			cp R17,R16 ;jeżeli R17=<R16 to R18 jest wynikiem
    			brsh koniec
    				mov R16,R17
    				mov R17,R18
    				pop R18 ;kasowanie wierzchołka stosu, by dało się wrócić
    				ret
    			koniec:
    			pop R17
    		rjmp petla
       ret
    
       zapal_piksel:
       		;X=R18 ; Y=R19
    		ldi R25,(GRAPHIC_HOME_ADRESS & 0xFF00) >> 8
    		ldi R24,GRAPHIC_HOME_ADRESS & 0xFF
    
    		mov R17,R18
    		ldi R16,FONT_WIDTH
    		rcall dzielenie
    		push R16
    		add R24,R17
    		clr R18
    		adc R25,R18
    
    		ldi R18,GRAPHIC_AREA
    		mul R18,R19
    
    		add R24,R0
    		adc R25,R1
    
    		mov R18,R24
    		rcall wyslij_dane
    		mov R18,R25
    		rcall wyslij_dane
    		ldi R18,SET_ADRESS_POINTER 
    		rcall wyslij_instrukcje 
    
    		pop R16
    		ldi R18,FONT_WIDTH-1
    		sub R18,R16
    		mov R16,R18
    
    		ldi R18,0xF8 ;zapalenie piksela
    		or R18,R16
    		rcall wyslij_instrukcje
       ret
    
       init_LCD:
       		;configuracja szyny danych LCD
    	   ldi R17, 0x00 
    	   out DANE_LCD_DDR, R17 ;DDRB 
    	   
    	   ldi R17, 0xFF
    	   out DANE_LCD, R17 ;PORTB 
    	   
    	   ;konfiguracja linii sterujących LCD
    	   clr R17 
    	   ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)|(1<<RST)
    	   out STER_LCD_DDR,R17
    	   ldi R17,(1<<RD)|(1<<WR)|(1<<CE)|(1<<C_D)
    	   out STER_LCD,R17 
    	   
    	   rcall reset_LCD 
    	   rcall wyczysc_RAM_LCD
    	   
    	   ldi R18,GRAPHIC_HOME_ADRESS & 0xFF ;młodszy bajt adresu
    	   rcall wyslij_dane
    	   ldi R18,(GRAPHIC_HOME_ADRESS & 0xFF00) >> 8 ;starszy bajt adresu
    	   rcall wyslij_dane
    	   ldi R18,SET_GRAPHIC_HOME_ADRESS ;!!!
    	   rcall wyslij_instrukcje 
    	   
    	   ldi R18,GRAPHIC_AREA
    	   rcall wyslij_dane 
    	   ldi R18,0x00 
    	   rcall wyslij_dane 
    	   ldi R18,SET_GRAPHIC_AREA 
    	   rcall wyslij_instrukcje 
    	   
    	   ldi R18,TEXT_HOME_ADRESS & 0xFF
    	   rcall wyslij_dane 
    	   ldi R18,(TEXT_HOME_ADRESS & 0xFF00) >> 8
    	   rcall wyslij_dane 
    	   ldi R18,SET_TEXT_HOME_ADRESS 
    	   rcall wyslij_instrukcje 
    	   
    	   ldi R18,TEXT_AREA
    	   rcall wyslij_dane 
    	   ldi R18,0x00 
    	   rcall wyslij_dane 
    	   ldi R18,SET_TEXT_AREA 
    	   rcall wyslij_instrukcje 
    	   
    	   ldi R18,MODE_SET 
    	   rcall wyslij_instrukcje 
    	   
    	   ldi R18,DISPLAY_MODE 
    	   rcall wyslij_instrukcje 
    	   
    	   ldi R18,0x04 ;X 
    	   rcall wyslij_dane 
    	   ldi R18,0x01 ;Y 
    	   rcall wyslij_dane 
    	   ldi R18,SET_CURSOR_POINTER 
    	   rcall wyslij_instrukcje 
    	   
    	   ldi R18,OFFSET_REGISTER
    	   rcall wyslij_dane 
    	   ldi R18,0x00
    	   rcall wyslij_dane 
    	   ldi R18,SET_OFFSET_REGISTER
    	   rcall wyslij_instrukcje 
    
    	   ldi R18,CURSOR_PATTERN_SELECT
    	   rcall wyslij_instrukcje 
    	 ret
    RESET: 
    
    ldi R17, high(RAMEND) ;inicjalizacja wskaźnika stosu 
    ldi R16, low(RAMEND) 
    out SPH, R17 
    out SPL, R16 
    
    rcall init_LCD
    
    ldi R18,0x29 ;młodszy 
    rcall wyslij_dane 
    ldi R18,0x00 ;starszy 
    rcall wyslij_dane 
    ldi R18,SET_ADRESS_POINTER 
    rcall wyslij_instrukcje 
    
    ldi R18,0x48 ;znak 'h' 
    rcall wyslij_dane 
    ldi R18,DATA_WRITE_INC_ADP 
    rcall wyslij_instrukcje 
    
    ldi R18,0x22 ;znak 'B' 
    rcall wyslij_dane 
    ldi R18,DATA_WRITE_INC_ADP 
    rcall wyslij_instrukcje 
    
    ldi R18,0x23 ;znak 'C' 
    rcall wyslij_dane 
    ldi R18,DATA_WRITE_INC_ADP 
    rcall wyslij_instrukcje 
    
    ldi R18,0x21 ;znak 'A' 
    rcall wyslij_dane 
    ldi R18,DATA_WRITE_INC_ADP 
    rcall wyslij_instrukcje 
    
    ldi R18,0x00 ;nic
    rcall wyslij_dane 
    ldi R18,DATA_WRITE_INC_ADP 
    rcall wyslij_instrukcje 
    
    
    
    ldi R18,GRAPHIC_HOME_ADRESS & 0xFF ;młodszy 
    rcall wyslij_dane 
    ldi R18,(GRAPHIC_HOME_ADRESS & 0xFF00) >> 8;starszy 
    rcall wyslij_dane 
    ldi R18,SET_ADRESS_POINTER 
    rcall wyslij_instrukcje 
    
    ldi R18,0xFF 
    rcall wyslij_dane 
    ldi R18,DATA_WRITE_INC_ADP 
    rcall wyslij_instrukcje 
    
    ldi R18,180 ;X
    ldi R19,100 ;Y
    rcall zapal_piksel
    
    petla_glowna: 
    rjmp petla_glowna
    

    Bardzo dziękuję kolegom za okazaną pomoc, bez tego nie udałoby mi się napisać procedur obsługi dla tego wyświetlacza. Teraz zabiorę się za funkcje graficzne i definiowanie własnych znaków. W razie problemów odezwę się w tym temacie. Dlatego też proszę o nie zamykanie tego tematu.
  • #16 8745267
    maciej_333
    Poziom 38  
    Próbuję wyświetlić znak zdefiniowany samodzielnie.
    OFFSET_REGISTER=2
    EXTERNAL_CG_HOME=OFFSET_REGISTER << 11

    Kod funkcji wysyłającej wzorzec znaku. Znajduje się on w tablicy "znak" (8 bajtów).
           definiuj_znak:
    		;R20=kod definiowanego znaku
    		ldi R31, high(znak*2+1)
    		ldi R30, low(znak*2)
    
    		ldi R24,EXTERNAL_CG_HOME & 0xFF
    		ldi R25,(EXTERNAL_CG_HOME & 0xFF00) >> 8
    
    		ldi R18,8
    		mul R20,R18
    
    		add R24,R0
    		adc R25,R1
    
    
    		mov R18,R24
    		rcall wyslij_dane
    		mov R18,R25
    		rcall wyslij_dane
    		ldi R18,SET_ADRESS_POINTER
    		rcall wyslij_instrukcje
    
    		ldi R19,8
    		wysylanie_znaku:
    			lpm R18,Z+
    			rcall wyslij_dane 
    			ldi R18,DATA_WRITE_INC_ADP 
    			rcall wyslij_instrukcje 
    
    			dec R19
    		brne wysylanie_znaku
    	ret

    W obszarze grafiki widać wysłane bajty, definiujące znak. Jako kod znaku przyjąłem 0x80. Załączony mam tryb internal CG ROM. Jeżeli próbuję wyświetlić znak o kodzie 0x80, to wyświetla mi zupełnie co innego niż zdefiniowałem (zamiast tego co ma być jest znak o kodzie 0x60).
  • #17 8745407
    Konto nie istnieje
    Konto nie istnieje  
  • #18 8746028
    maciej_333
    Poziom 38  
    _marek napisał:
    W internal_cg_ROM nie definiuje się znaków .

    Zobacz to:
    Cytat:
    In internal CG ROM mode, character codes 00H to 7FH represent the predefined“internal CG ROM characters, and codes 80H to FFH represent the user's own external characters. In external CG RAM mode, all 256 codes from 00H to FFH can be used to represent the user' s own characters. The three least significant bits indicate one of the eight rows of eight dots that define the character's shape.

    No chyba, że ja to źle rozumiem.
  • Pomocny post
    #19 8746104
    Andrzej__S
    Poziom 28  
    maciej_333 napisał:

    W obszarze grafiki widać wysłane bajty

    ...bo obszary pamięci dla grafiki i CG_RAM nachodzą na siebie. Jak dobrze policzysz to potrzebujesz na TEXT_SIZE + GRAPHIC_SIZE łącznie 5760 bajtów, czyli pierwszy wolny adres dla CG_RAM jest równy 0x1680. Ustawiając OFFSET_REGISTER na 2 otrzymujesz adres startowy EXTERNAL_CG_HOME równy 0x1000. Spróbuj ustawić na OFFSET_REGISTER na 3.

    Mała uwaga: zamiast pisać ldi R24,EXTERNAL_CG_HOME & 0xFF i ldi R25,(EXTERNAL_CG_HOME & 0xFF00) >> 8 prościej (i czytelniej) chyba użyć ldi R24, low(EXTERNAL_CG_HOME) i ldi R25, high(EXTERNAL_CG_HOME).
  • #21 8746196
    Andrzej__S
    Poziom 28  
    Cytat:

    OFFSET_REGISTER ustawiłem na 3, ale dalej nie widzę zdefiniowanego znaku, który ma mieć kod 0x80.

    Na razie chodziło mi o to, żeby nie było widać danych CG_RAM na wyświetlaczu graficznym. Co do tego znaku, to w tej chwili nie mam czasu na dokładną analizę.
  • #22 8746228
    maciej_333
    Poziom 38  
    Problem był trywialny. Mam już zrobioną funkcję do wysyłania łańcuchów, zapisanych w tablicach pamięci programu Atmegi. W tej funkcji musiałem zrobić odejmowanie od każdego odczytanego kodu znaku 32, bo w tym LCD znaki mają kody od zera. W związku z tym spacja ma kod 0, a nie jak w zwykłym ASCII 32. Teraz oczywiście widzę zdefiniowany znak. Zabiorę się za definicję wszystkich ogonków.

    Jednak mam nieco inne pytanie. Dlaczego przy obliczaniu adresu dla rejestru indeksowego Z muszę mieć coś takiego:
    ldi R31, high(znak*2+1)
    ldi R30, low(znak*2)


    Coś takiego nie wystarczy:
    ldi R31, high(znak)
    ldi R30, low(znak)

    Chodzi o to, że pamięć programu jest podzielona na 16-bitowe słowa ? W związku z tym za pomocą LPM adresuję nie bajty tylko 16-bitowe słowa ??? A co jeżeli w tablicy umieściłbym stałą 16-bitową ?
  • #23 8746229
    Konto nie istnieje
    Konto nie istnieje  
  • #24 8746300
    Andrzej__S
    Poziom 28  
    maciej_333 napisał:

    
    ldi R31, high(znak*2+1) 
    ldi R30, low(znak*2)
    


    W zasadzie powinno być ldi R31, high(znak*2) a nie ldi R31, high(znak*2+1). Jedynkę musisz dodać, jak chcesz odczytać wyższy bajt 16-bitowego słowa.
    maciej_333 napisał:

    A co jeżeli w tablicy umieściłbym stałą 16-bitową?

    Musiałbyś ją odczytać dwoma instrukcjami np.:
    
    LPM R18, Z+ ;niższy bajt
    LPM R19, Z+ ;wyższy bajt
    


    Dodano po 9 [minuty]:

    maciej_333 napisał:

    Dlaczego przy obliczaniu adresu dla rejestru indeksowego Z muszę mieć coś takiego...
    .........
    Chodzi o to, że pamięć programu jest podzielona na 16-bitowe słowa ? W związku z tym za pomocą LPM adresuję nie bajty tylko 16-bitowe słowa ???

    W zasadzie sam sobie odpowiedziałeś. Instrukcja LPM odczytuje bajt a nie słowo 16-bitowe. Pomnożenie przez 2 daje przesunięcie o jeden bit w lewo, dzięki czemu najmniej znaczący bit adresu w rejestrze Z można wykorzystać do rozróżnienia, który bajt 16-bitowego słowa odczytujemy (0 - niższy, 1 - wyższy).
  • #25 9071421
    maciej_333
    Poziom 38  
    Jestem zmuszony zadać kolegom kolejne pytania związane z tym wyświeltaczem.
    1. Jakie praktyczne znaczenie mają polecenia SCREEN PEEK i SCREEN COPY ?
    2. Czy można w jakiś prosty sposób skopiować TEXT AREA do GRAPHIC AREA ? Chodzi mi o odczytanie tekstu, jako grafikę. Wykonuję funkcję zrzutów ekranu wyświetlacza. W związku z tym wysyłam do PC całe GRAPHIC AREA poprzez RS232. Jednak w ten sposób nie jestem w stanie odczytać tekstu.
  • #26 9074683
    Konto nie istnieje
    Konto nie istnieje  
  • #27 9074787
    maciej_333
    Poziom 38  
    _marek napisał:
    Spróbuj wykonać screen_copy i wyczyścić text_area .

    Aby coś takiego zrobić musiałbym postępować wg. tego grafu:
    [Atmega16][asm]Graficzny wyświetlacz LCD.
    Jeżeli dobrze rozumiem, to najpierw ustawiam Adress Pointer na Text Home Adress. Następnie sprawdzam status i wysyłam polecenie Screen Copy. Potem odczytuję status z STA6. Jeżeli jest tam 1, to wracam do początku i inkrementuję wskaźnik rozkazów. Jeżeli nie ma 1 to dalej zgodnie z grafem.

    Jak rozumiem ten algorytm sam się zakończy po dojechaniu do Text Home Adress + Text Size ???
  • #28 9074908
    Konto nie istnieje
    Konto nie istnieje  
REKLAMA