Skocz do zawartości

Wyświetlacz z ili9325 - błąd w obsłudze czcionek


resonator

Pomocna odpowiedź

Witam męczę się z tym problemem od kilku dni, bezskutecznie, więc postanowiłem wreszcie poprosić o pomoc z zewnątrz. Co do samego mechanizmu rysowania to nie mam zarzutów, aczkolwiek problem tkwi w tym, że znak z czcionki da się narysować jedynie na współrzędnych gdzie x==y !!! Jeśli nie są sobie równe to znak jest dziwnie przesunięty.

Tu jest poprawnie narysowany znak na współrzędnych 100;100:

ZDJECIE

A tu już źle na współrzędnych 105;100:

ZDJECIE

Funkcja wygląda tak:

void LCD_DrawChar(unsigned int x, unsigned int y, char Char)
{
register uint8_t Width, widthIndex, heightIndex, widthByteNr, readByte, pixelsNr;
uint16_t Offset;

/* Odczytujemy offset położenia wzorca znaku ASCII (zmienna char) w tablicy
wzorców znaków */
Offset = pgm_read_word(&currentFont.CharInfo[Char-currentFont.FirstCharCode].Offset);

/* Odczytujemy szerokość znaku ASCII (zmienna char) */
Width = pgm_read_byte(&currentFont.CharInfo[Char-currentFont.FirstCharCode].Width);

/* Ustawiamy aktywne okno pamięci obrazu DDRAM */
LCD_SetArea(x, y, x+Width-1, y+currentFont.Height-1);

for(heightIndex = 0; heightIndex < currentFont.Height; ++heightIndex)
{
	for(widthIndex = 0, widthByteNr = 0; widthIndex < Width; widthIndex += 8, ++widthByteNr)
	{
		/* Odczytujemy kolejny bajt definicji znaku umieszczony w tablicy Bitmap pod
		odpowiednim adresem */
		readByte = pgm_read_byte(&currentFont.Bitmap[Offset++]);

		/* Dla czcionek o szerokości niebędącej wielokrotnością liczby 8 każdy,
		ostatni w wierszu bajt definicji wzorca nie jest w pełni wykorzystany, jeśli
		chodzi o poszczególne bity, w związku z czym musimy ustalić użyteczną liczbę
		pikseli przeznaczonych do przesłania do sterownika ekranu */
		pixelsNr = ((widthByteNr+1)*8) <= Width ? 8 : Width - (widthByteNr*8);

		for(uint8_t i = 0; i < pixelsNr; ++i)
		{
			/* Wysyłamy 2 bajty do pamięci ekranu reprezentujące kolor jednego piksela
			(lub tła-czarny) */
			readByte & 0x80 ? LCD_WrDat(_color) : LCD_WrDat(_bcolor);
			readByte <<= 1;
		}
	}
}
}

Może ktoś z was już spotkał się z czymś takim? Będę wdzięczny za każdą wskazówke.

PS Fonty generuje w PixeLab.

__________

Komentarz dodany przez: Sabre

Dziękuję za cenną radę! Mam nadzieję, że 3Mb-owe zdjęcia uda mi sie upchnąć w limicie do 1Mb 😉

Link do komentarza
Share on other sites

Wygląda na to, że pętla przepisująca znak pixel po pixelu z generatora znaków do pamięci GRAM wyświetlacza jest OK. Ona "nic nie wie" o położeniu znaku a ponieważ dobrze rysuje w jakichś współrzędnych, to w innych narysuje go tak samo dobrze, bo rysowanie polega tu na prostym wysyłaniu kolorów kolejnych pixeli z kolejnych linii znaku. Sekwencja wysyłanych bajtów będzie taka sama dla współrzędnych obrazu 100x100 jak i 105x100, prawda?

Problem jest zatem w funkcji LCD_SetArea(). Czy fragment kodu i funkcje które w nim wołasz są Twojego autorstwa? Jeżeli tak, to powinno być dla Ciebie oczywiste gdzie szukać. Zajrzyj do niej i zobacz jak ustawiasz rejestry 9325 odpowiedzialne za definiowanie okna do zapisu/odczytu (R50h-53h, rozdz. 7.2.24 dokumentacji układu). Scalak potrzebuje określenia współrzędnych lewego górnego i prawego dolnego rogu obszaru. Wystarczyło, że zamieniłeś w tej funkcji któreś współrzędne i dostajesz taką kaszanę jaką widzisz. Przyjrzyj się dobrze co tam robisz albo wstaw do funkcji wypisywanie (np. terminalu szeregowym) wszystkich 4 współrzędnych obszaru i zobaczysz co jest źle.

Link do komentarza
Share on other sites

Ale przecież sam widzisz, że reszta tego co pokazałeś jest niezależna od położenia znaku na ekranie. Więc co? Czary?

Żeby się upewnić, ze zawsze wysyłasz ten sam strumień pixeli (wygląd znaku) do GRAM, zamień oba wywołania LCD_WrDat() na wypisywanie prostych znaków np. '0' i '1' na terminal. Jeżeli to co zobaczysz (co prawda w jednej linii, ale jakoś to ogarniesz) będzie podobne do rozwałkowanej bitmapy litery 'A' niezależnie od otrzymanych przez Twoją funkcję współrzędnych x,y to znaczy, że jednak w definiowaniu okna jest jakiś problem a współpraca z fontem jest poprawna.

Może po prostu pokaż tę LCD_SetArea() zamiast pisać, że na pewno jest OK. Naiwnie jest sądzić, że znalazło się wszystkie błędy.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

void LCD_SetArea(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2)
{
if(_orientation == LANDSCAPE)
{
	LCD_WrCmd(0x0050);LCD_WrDat(y1);
	LCD_WrCmd(0x0051);LCD_WrDat(y2);
	LCD_WrCmd(0x0052);LCD_WrDat(x1);
	LCD_WrCmd(0x0053);LCD_WrDat(x2);
}
else
{
	LCD_WrCmd(0x0050);LCD_WrDat(x1);
	LCD_WrCmd(0x0051);LCD_WrDat(x2);
	LCD_WrCmd(0x0052);LCD_WrDat(y1);
	LCD_WrCmd(0x0053);LCD_WrDat(y2);
}
LCD_WaitMs(1);
LCD_SetCursor(x1, y1);
}

Masz rację, zaraz sprawdzę co dokładnie uC wysyła.

@EDIT

Okazało się że dane dla poprawnego znaku i błędnego są identyczne...

1000001110000
0000001110000
0000011011000
0000011011000
0000011011000
0000110001100
0000110001100
0000110001100
0001111111110
0001111111110
0011000000011
0011000000011
0011000000011
0110000000001
1110000000001
10000000000000

Jednak zastanawia mnie ta "1" na początku łańcucha. Znak ma szerokość 13 pikseli więc po rozdzieleniu wygląda tak:

1000001110000
0000001110000
0000011011000
0000011011000
0000011011000
0000110001100
0000110001100
0000110001100
0001111111110
0001111111110
0011000000011
0011000000011
0011000000011
0110000000001
1110000000001
1000000000000
0

Na wyświetlaczu nie ma piksela reprezentowanego przez tę jedynkę.

Link do komentarza
Share on other sites

To może wskazywać jednak na jakąś niekompatybilność z fontem. To co pokazałeś (to ładne A z jedynek i zer) ma jednak o jeden pixel za dużo. Nadmiarowe, końcowe zero być może nadpisuje tę dziwną, początkową jedynkę bo licznik adresów "zawija się" do początku okna.

Jednak wydaje mi się, że ta jedynka nie wchodzi do strumienia pixeli, bo teraz (z tą jedynką) Twoje 'A' jest wyraźnie przesunięte w prawo. Gdybyś najpierw usunął tę jedynkę a dopiero resztę strumienia podzielił na linie, litera byłaby symetryczna. Na LCD na pewno byś zobaczył takie obcięcie. Podrąż temat pochodzenia tej jedynki. Może wysyłasz coś "niechcący" w innym miejscu kodu?

W każdym razie identyczność ciągu pixeli chyba przesuwa problem jednak na definiowanie okna lub (generalnie) trybu pracy sterownika LCD. W jakim położeniu pracujesz? pokaż funkcję inicjalizacji. Jeżeli używasz trybu obróconego (LANDSCAPE), to nie sprowadza się jedynie do zamiany współrzędnych okna, ale musi mieć wpływ na wiele innych rzeczy (np. rejestr 0x03 i Figure 25 w dokumentacji).

EDIT: Czy inne, niesymetryczne litery np. 'F' wyświetlają się dobrze w "dobrych" współrzędnych 100x100?

Link do komentarza
Share on other sites

W każdym razie identyczność ciągu pixeli chyba przesuwa problem jednak na definiowanie okna lub (generalnie) trybu pracy sterownika LCD. W jakim położeniu pracujesz? pokaż funkcję inicjalizacji. Jeżeli używasz trybu obróconego (LANDSCAPE), to nie sprowadza się jedynie do zamiany współrzędnych okna, ale musi mieć wpływ na wiele innych rzeczy (np. rejestr 0x03 i Figure 25 w dokumentacji).

Tak używam trybu LANDSCAPE. Co do Figure 25 z rejestru Entry Mode to mam tam ustawione I/D1, I/D2 i AM na 1. Próbowałem z tym eksperymentować ale nic się nie działo.

EDIT: Czy inne, niesymetryczne litery np. 'F' wyświetlają się dobrze w "dobrych" współrzędnych 100x100?

Tak.

Edit

inicjalizacja:

//************* Start Initial Sequence **********//
LCD_WrCmd(0x00e3); LCD_WrDat(0x3008); // set SRAM internal timing ##Changed
LCD_WrCmd(0x00e7); LCD_WrDat(0x0012); 
LCD_WrCmd(0x00ef); LCD_WrDat(0x1231); 

LCD_SetOrientation(_orientation);

LCD_WrCmd(0x0004); LCD_WrDat(0x0000); // Resize register SAME
LCD_WrCmd(0x0008); LCD_WrDat(0x0202); // set the back porch and front porch ##Changed

LCD_WrCmd(0x0009); LCD_WrDat(0x0000); // set non-display area refresh cycle ISC[3:0]
LCD_WrCmd(0x000A); LCD_WrDat(0x0000); // FMARK function
LCD_WrCmd(0x000C); LCD_WrDat(0x0000); // RGB interface setting
LCD_WrCmd(0x000D); LCD_WrDat(0x0000); // Frame marker Position
LCD_WrCmd(0x000F); LCD_WrDat(0x0000); // RGB interface polarity

//*************Power On sequence ****************//
LCD_WrCmd(0x0010); LCD_WrDat(0x0000); // SAP, BT[3:0], AP, DSTB, SLP, STB
LCD_WrCmd(0x0011); LCD_WrDat(0x0007); // DC1[2:0], DC0[2:0], VC[2:0]
LCD_WrCmd(0x0012); LCD_WrDat(0x0000); // VREG1OUT voltage
LCD_WrCmd(0x0013); LCD_WrDat(0x0000); // VDV[4:0] for VCOM amplitude

LCD_WaitMs(200); // Dis-charge capacitor power voltage ##Changed was 50

LCD_WrCmd(0x0010); LCD_WrDat(0x1690); // 1490//SAP, BT[3:0], AP, DSTB, SLP, STB  ##Changed

LCD_WrCmd(0x0011); LCD_WrDat(0x0220); // DC1[2:0], DC0[2:0], VC[2:0]  ##Changed

LCD_WaitMs(50); // Delay 50ms
LCD_WrCmd(0x0012); LCD_WrDat(0x0091); //001C// Internal reference voltage= Vci;  ##Changed

LCD_WaitMs(50); // Delay 50ms
LCD_WrCmd(0x0013); LCD_WrDat(0x1700); //0x1000//1400   Set VDV[4:0] for VCOM amplitude  1A00  ##Changed
LCD_WrCmd(0x0029); LCD_WrDat(0x001A); //0x0012 //001a  Set VCM[5:0] for VCOMH  //0x0025  0034 ##Changed

LCD_WaitMs(50); // Delay 50ms ##Changed added

LCD_WrCmd(0x002B); LCD_WrDat(0x000B); // Set Frame Rate   000C ##Changed

LCD_WaitMs(50); // Delay 50ms

LCD_WrCmd(0x0020); LCD_WrDat(0x0000); // GRAM horizontal Address
LCD_WrCmd(0x0021); LCD_WrDat(0x0000); // GRAM Vertical Address

// ----------- Adjust the Gamma Curve ----------//
LCD_WrCmd(0x0030); LCD_WrDat(0x0007);	//##Changed
LCD_WrCmd(0x0031); LCD_WrDat(0x0507);	//##Changed
LCD_WrCmd(0x0032); LCD_WrDat(0x0006);	//##Changed
LCD_WrCmd(0x0035); LCD_WrDat(0x0001);

LCD_WrCmd(0x0036); LCD_WrDat(0x0709);//0207	##Changed
LCD_WrCmd(0x0037); LCD_WrDat(0x0104);//0306  ##Changed
LCD_WrCmd(0x0038); LCD_WrDat(0x0502);//0102  ##Changed

LCD_WrCmd(0x0039); LCD_WrDat(0x0706);//0707	##Changed
LCD_WrCmd(0x003C); LCD_WrDat(0x0500);//0702  ##Changed
LCD_WrCmd(0x003D); LCD_WrDat(0x000C);//1604  ##Changed

//------------------ Set GRAM area ---------------//
LCD_WrCmd(0x0050); LCD_WrDat(0x0000); // Horizontal GRAM Start Address
LCD_WrCmd(0x0051); LCD_WrDat(0x00EF); // Horizontal GRAM End Address
LCD_WrCmd(0x0052); LCD_WrDat(0x0000); // Vertical GRAM Start Address
LCD_WrCmd(0x0053); LCD_WrDat(0x013F); // Vertical GRAM Start Address

LCD_WrCmd(0x0060); LCD_WrDat(0xA700); // Gate Scan Line
LCD_WrCmd(0x0061); LCD_WrDat(0x0001); // NDL,VLE, REV
LCD_WrCmd(0x006A); LCD_WrDat(0x0000); // set scrolling line

//-------------- Partial Display Control ---------//
LCD_WrCmd(0x0080); LCD_WrDat(0x0000);
LCD_WrCmd(0x0081); LCD_WrDat(0x0000);
LCD_WrCmd(0x0082); LCD_WrDat(0x0000);
LCD_WrCmd(0x0083); LCD_WrDat(0x0000);
LCD_WrCmd(0x0084); LCD_WrDat(0x0000);
LCD_WrCmd(0x0085); LCD_WrDat(0x0000);

//-------------- Panel Control -------------------//
LCD_WrCmd(0x0090); LCD_WrDat(0x0010);
LCD_WrCmd(0x0092); LCD_WrDat(0x0000);	//##Changed
LCD_WrCmd(0x0093); LCD_WrDat(0x0003);	//##Changed added
LCD_WrCmd(0x0095); LCD_WrDat(0x0110);	//##Changed added
LCD_WrCmd(0x0097); LCD_WrDat(0x0000);	//##Changed added
LCD_WrCmd(0x0098); LCD_WrDat(0x0000);	//##Changed added

LCD_WrCmd(0x0007); LCD_WrDat(0x0173); // 262K color and display ON ##Changed

Poszperam jeszcze w kodzie może znajdę jakiegoś robala.

Link do komentarza
Share on other sites

Gdzie ustawiasz rejestr 0x03? Masz jakąś funkcję przestawiającą cały sterownik z Portrait na Landscape?

Wybacz, zapomniałem wstawic listing tej funkcji 😋

void LCD_SetOrientation(uint8_t orientation)
{
switch(orientation)
{
case LANDSCAPE:
	LCD_WrCmd(0x0001); LCD_WrDat(0x0000);
	LCD_WrCmd(0x0003); LCD_WrDat(0x1038);
	_hor_size = (uint16_t) LANDSCAPE_HOR_SIZE;
	_ver_size = (uint16_t) LANDSCAPE_VER_SIZE;
	break;
case PORTRAIT:
	LCD_WrCmd(0x0001); LCD_WrDat(0x0100);
	LCD_WrCmd(0x0003); LCD_WrDat(0x1030);
	_hor_size = (uint16_t) PORTRAIT_HOR_SIZE;
	_ver_size = (uint16_t) PORTRAIT_VER_SIZE;
	break;
}
_orientation = orientation;
LCD_SetCursor(0, 0);
}

Potem wywołuje tę funkcję w inicjalizacji

LCD_SetOrientation(LANDSCAPE);
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.