OLED display met ST7789 en MikroBasic

Bavelt

Golden Member

ALs ik naar een eerdere post kijk van Arco, dan ziet dat displaytje er net wat anders uit.

Mijn exemplaar heeft D0, D1 en RES (Die ik inderdaad op hoog heb staan).

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Ik heb nog zitten kijken of de SPI nog moet worden 'aangezet', maar het lijkt er op dat dat niet hoeft.

Zou de SPI1_Init (ipv advanced) overigens ook niet toereikend moeten zijn?

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Meeste displays zijn nu 7 pins. SPI_Init is voldoende.
Als je alleen het kleinste font gebruikt, kan een 1847 wel. Met groter font of graphics is het geheugen te klein voor zinvol gebruik.
(of je moet de displaydata op een externe serial flash of sd card zetten)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

ah, Ok.
Het displaytje zelf is overigens goed, als ik het in de Arduino UNO stop met de standaard Adafruit SSD1306-sketch, dan werkt het.

Met MikroBasic is het display zwart, er lijkt niks te gebeuren. Daar moet dus iets in zitten waardoor het display niet wordt aangestuurd.

LAT is toch goed ipv Port omdat het output is?

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Inmiddels is er wat 'licht' in de tunnel.

Het displaytje gaat nu aan. Alleen worden de karakters in spiegelbeeld getoond...

Fouten zijn het bewijs dat je het probeert..
KGE

Golden Member

Op 30 maart 2020 14:25:03 schreef Bavelt:
Inmiddels is er wat 'licht' in de tunnel.

Het displaytje gaat nu aan. Alleen worden de karakters in spiegelbeeld getoond...

Dat is met één van de intialisatieparameters wel in te stellen. Net als wanner je het display 'op de kop' zou willen/moeten gebruiken e.d.

Misschien heb je hier iets aan:

https://forum.arduino.cc/index.php?topic=545883.msg3721206#msg3721206

[Bericht gewijzigd door KGE op maandag 30 maart 2020 17:18:59 (21%)

Bavelt

Golden Member

Ik krijg er (nog) niet echt de vinger achter.
Om het goed te kunnen testen heb ik het programmaatje helemaal terug geschroefd.
Het blankt eerst alle pixels één voor één, om vervolgens per 'page' in ieder segment (kolom) 1 pixeltje aan te steken.

Het resultaat is dat het "ongeveer" werkt, maar het gedraagt zich heel onvoorspelbaar en wispelturig. Soms wordt de rij niet afgemaakt en stopt hij op segment (kolom) 120, dan weer slaat het een 'page' over om die vervolgens later toch weer even te doen.
Ik heb de snleheid van 16Mhz teruggebracht naar 8 Mhz en dat leek iets te helpen. Maar dat is niet de oorzaak.

Het programma:

pic basic code:



Program OledSPI
'==================================================================================================
' Project name: OledSPI
' MCU:          PIC16F1847
' Oscillator:   Internal 16 MHz
'==================================================================================================

Dim SSel   As sBit At LATB.1                              'Display select
    D_C    As sBit At LATB.0                              'Data/Command

    i1 as byte
    SEG As Byte
    BLOK as Byte
    
    Dim lx, ly As Byte

'====================================================================================================
Sub Procedure Lcd_WrCmd(Dim pCmd As Byte)                       'Write command to display
'====================================================================================================
  D_C = 0
  Spi1_Write(pCmd)
End Sub

'====================================================================================================
Sub Procedure Lcd_WrDat(Dim pDat As Byte)                       'Write data to display
'====================================================================================================
  Dim lCnt As Byte
  D_C = 1
  Spi1_Write(pDat)
End Sub

'====================================================================================================
Sub Procedure Lcd_SetPos(Dim px, py as Byte)                    'Set write position on display
'====================================================================================================
  delay_us(1)
  Lcd_WrCmd(0xB0 + py)
  Lcd_WrCmd((px  >> 4) Or 0x10)
  Lcd_WrCmd((px And 0x0F))
  delay_us(1)
End Sub

'====================================================================================================
Sub Procedure LCD_Fill(Dim pFill As Byte)                       'Fill display with character pFill
'====================================================================================================
  Dim lx, ly As Byte
  For ly = 0 To 7
    Lcd_WrCmd(0xB0+ly)
    Lcd_WrCmd(0x01)
    Lcd_WrCmd(0x10)
    For lx = 0 to 127
      Lcd_WrDat(pFill)
    Next lx
  Next ly
End Sub

'===============================================================================
Sub Procedure Display_Init()
'===============================================================================
  Lcd_WrCmd(0xAF)                                 'Turn OLED panel off
  Lcd_WrCmd(0xA8)                                 'Multiplex ratio set to
  Lcd_WrCmd(0x3F)                                 '63
  Lcd_WrCmd(0xD3)                                 'Display offset RAM counter
  Lcd_WrCmd(0x00)                                 'none
  Lcd_WrCmd(0x40)                                 'Start line address
  Lcd_WrCmd(0xA1)                                 'Set segment remap rotation to left
  Lcd_WrCmd(0xC8)                                 'Common output scan direction
  Lcd_WrCmd(0xDA)                                 'Common signals pad
  Lcd_WrCmd(0x12)                                 'value
  Lcd_WrCmd(0x81)                                 'Contrast control
  Lcd_WrCmd(0xFF)                                 'value
  Lcd_WrCmd(0xA4)
  Lcd_WrCmd(0xA6)                                 'Normal display
  Lcd_WrCmd(0xD5)                                 'Clock ratio:oscillator frequency
  Lcd_WrCmd(0x80)                                 'oooo:rrrr
  Lcd_WrCmd(0x8D)
  Lcd_WrCmd(0x14)
  Lcd_WrCmd(0x00)                                 'Set lower column address
  Lcd_WrCmd(0x10)                                 'Set higher column address
  Lcd_WrCmd(0xD9)                                 '15 clocks, discharge 1 clock
  Lcd_WrCmd(0xF1)                                 'dddd:pppp
  Lcd_WrCmd(0xDB)                                 'Common output voltage
  Lcd_WrCmd(0x40)                                 'level
  Lcd_WrCmd(0x20)                                 'Addressing mode
  Lcd_WrCmd(0x02)                                 'value
  Lcd_WrCmd(0xAE)                                'Turn OLED panel off
End Sub

'====================================================================================================
Main:                                                            'Main program
'====================================================================================================
 
  ANSELB = 0                                                     'All Port B digital
  TRISB  = %11110100                                             'PortB.0, PortB.1, B.3 output
  PORTB =  %00000000
  OSCCON = %01110000                                             '8Mhz internal

  SPI1_Init()
  Delay_ms(100)
  Display_Init()
  Delay_ms(100)
  
  Lcd_WrCmd(0xAF)                                               'Turn OLED panel on

  SSel = 0
  delay_ms(500)
  SSEL = 1                                                      'Only for 0.96", for 1.3" remove it

while true
  'Blank all pixels
   LCD_Setpos(0, 0)
   For ly = 0 To 7
    Lcd_WrCmd(0xB0+ly)
    Lcd_WrCmd(0x01)
    Lcd_WrCmd(0x10)
    For lx = 0 to 126
      Lcd_WrDat(0x00)
      delay_ms(10)
    Next lx
  Next ly
  
  Delay_ms(250)

 'Every segment 0x01 (1 pixel lighted)
  LCD_Setpos(0, 0)
   For ly = 0 To 7
    Lcd_WrCmd(0xB0+ly)
    Lcd_WrCmd(0x01)
    Lcd_WrCmd(0x10)
    For lx = 0 to 126
      Lcd_WrDat(%00000001)
      delay_ms(10)
    Next lx
  Next ly
 
 Wend

End.

Daarbij begrijp ik nog niet goed wat de volgende statements nu precies doen

pic basic code:


Lcd_WrCmd(0x01)
Lcd_WrCmd(0x10)

(Lower and higher Colom address?)

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Instellen van de startcolumn:

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Hmm. Maar er staat een note dat dit alleen voor Page Adressing Mode geldt.
Is dat dan zo? Wordt die dan gebruikt?

In het programma is daarnaast ook een Subroutine om de positie te zetten.

pic basic code:

'====================================================================================================
Sub Procedure Lcd_SetPos(Dim px, py as Byte)                    'Set write position on display
'====================================================================================================
  delay_us(1)
  Lcd_WrCmd(0xB0 + py)
  Lcd_WrCmd((px  >> 4) Or 0x10)
  Lcd_WrCmd((px And 0x0F))
  delay_us(1)
End Sub

Het ontgaat me eveneens wat

pic basic code:

Lcd_WrCmd((px  >> 4) Or 0x10)
Lcd_WrCmd((px And 0x0F))

Hier nu doen.

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Is page addressing mode (page0 = regel 0...7, page1= regel 8...15,...)
LcdSetpos doet hetzelfde, alleen met 'x' erbij in...

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Het is dat de paracetamol is uitverkocht, anders had ik er eentje genomen ;)

Ik heb de datasheet van de SSD1306 doorgepluisd:

Page addressing mode (A[1:0]=10xb)
In page addressing mode, after the display RAM is read/written, the column address pointer is increased
automatically by 1. If the column address pointer reaches column end address, the column address pointer is
reset to column start address and page address pointer is not changed. Users have to set the new page and
column addresses in order to access the next page RAM content. The sequence of movement of the PAGE
and column address point for page addressing mode is shown in Figure 10-1.
Figure 10-1 : Address Pointer Movement of Page addressing mode
COL0 COL 1 ….. COL 126 COL 127
PAGE0
PAGE1
: : : : : :
PAGE6
PAGE7
In normal display data RAM read or write and page addressing mode, the following steps are required to
define the starting RAM access pointer location:
• Set the page start address of the target display location by command B0h to B7h.
• Set the lower start column address of pointer by command 00h~0Fh.
• Set the upper start column address of pointer by command 10h~1Fh.
For example, if the page address is set to B2h, lower column address is 03h and upper column address is 10h,
then that means the starting column is SEG3 of PAGE2. The RAM access pointer is located as shown in
Figure 10-2. The input data byte will be written into RAM position of column 3.
Figure 10-2 : Example of GDDRAM access pointer setting in Page Addressing Mode (No row and columnremapping)
LSB D0
MSB D7
Each lattice represents
one bit of image data
PAGE2 ....................
(Starting page)
COM16
COM17
:
:
:
:
:
COM23
SEG0 SEG3 (Starting column)

Ik begrijp het Lower Start address (het segment waar je begint. Maar wat is dan de Upper Colomn address?

In het programma is 0x01 dus starten op Segment (kolom) 1.
Maar wat is nu 0x10 voor Higher column address? Betekent dat dat hij na het laatste segment naar kolom 0 terug moet?

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Het zijn universele driver ic's. Bij 128 columns moet de high byte dus altijd op '0' staan. (er zijn er ook met veel meer columns)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Het zijn universele driver ic's. Bij 128 columns moet de high byte dus altijd op '0' staan. (er zijn er ook met veel meer columns)

Ok. Maar waarom zou je dan starten op kolom 1 met het commando 0x01? Is het dan niet logischer om met 0x00, dwz kolom 0 te starten?
Anders krijg je toch dat het begint op kolom 1 en de volgende page op kolom 1?

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Het schrijven van het karakter 0x01 (1 pixel per kolom) gaat nu redelijk goed.

Redelijk, omdat soms een regel niet wordt afgemaakt; dan springt hij ergens halverwege naar een volgende page en plaatst het restant daar.

M.a.w. waar komt die sprong naar een andere page (Row) vandaan terwijl hij de 127 nog niet had bereikt?

Kan dat wellicht iets te maken hebben met de kloksnelheid? Dat de display-RAM het bv niet kan bijhouden?
ik heb het nu op 4Mhz staan.

pic basic code:

'Every segment 0x01 (1 pixel lighted)
  LCD_Setpos(0, 0)
   For ly = 0 To 7
    Lcd_WrCmd(0xB0+ly)
    Lcd_WrCmd(0x00)
    Lcd_WrCmd(0x10)
    For lx = 0 to 126
      Lcd_WrDat(%00000001)
      delay_ms(10)
    Next lx
  Next ly

[Bericht gewijzigd door Bavelt op dinsdag 31 maart 2020 01:30:29 (22%)

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Ik blijf wat probleenpjes ondervinden met de SPI-Oled 0,96"-SPI.
De I2C variant van dit displaytje met SSD1306 chip werkt prima, met de SPI variant heb ik toch wat meer problemen.
(wat nog niet persé wil zeggen dat het aan het protocol ligt).

Hij doet het wel, maar het opstarten is lastig.
Na het schrijven van het programma in de uc (1847), is het spanning aan, nee doet niks, nog een keer, nee nog niet. Nog keer aan, dan zit het scherm vol rommel. Na nog een paar keer, ja nu doet hij het.

Ergens krijg ik het zaakje niet gerest of het geheugen van de chip/Display niet leeg.

Power-Up timer is enabled.

Dan zag ik dit nog staan in het programma:

pic basic code:

SSel = 0
Delay_ms(500)[
SSEL = 1       'Only for 0.96", for 1.3" remove it

Wat klaarblijkelijk alleen geldt voor een 0,96" display.
Waar is dit voor? Hoeft dat maar 1 keer bij de start van het programma?

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Ja,

Zonder start het display niet altijd goed op. (ik heb de reset daarom ook aangesloten, kun je het display indien nodig resetten)
De i2c en spi versie zijn trouwens gelijk: alleen wat weerstandjes verplaatsen aan de achterzijde.

[Bericht gewijzigd door Arco op woensdag 1 april 2020 00:04:55 (27%)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Die Reset is active-low begrijp ik. Maakt die de buffer van de display dan ook helenmaal leeg?

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Is er trouwens nog iets te zeggen of je beter voor I2C kunt kiezen dan SPI?

I2C heeft m.i. het voordeel dat je de devices parallel kunt hangen aan andere devices (zoals een klokje, etc) omdat ze worden benaderd dmv het Slave adres.
En ze hebben maar 2 draden nodig.

Bij SPI zijn dat er minimaal 3.

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

ik heb de reset daarom ook aangesloten, kun je het display indien nodig resetten

Ik heb de Reset ook aangesloten en maak deze na een paar keer tekst tonen laag.
Het display gaat uit.
Vervolgens de Reset weer hoog.
Daarna moet het display wel weer opnieuw worden geinitialiseerd merk ik.
(anders blijft hij zwart).

Maar de oude inhoud staat er dan nog, dwz er wordt niets leeggemaakt wat ik had verwacht.

Fouten zijn het bewijs dat je het probeert..
KGE

Golden Member

Op 1 april 2020 00:43:12 schreef Bavelt:
[...]

Ik heb de Reset ook aangesloten en maak deze na een paar keer tekst tonen laag.
Het display gaat uit.
Vervolgens de Reset weer hoog.
Daarna moet het display wel weer opnieuw worden geinitialiseerd merk ik.
(anders blijft hij zwart).

Dat lijkt mij logisch, je reset de display controller en die moet weer opnieuw weten wat voor soort/maat display er aan hangt.

Maar de oude inhoud staat er dan nog, dwz er wordt niets leeggemaakt wat ik had verwacht.

Nee, de meeste controllers wissen niet zelf het geheugen.

Arco

Special Member

Da's hetzelfde als met microcontrollers: die behouden ook hun geheugenwaardes bij een reset. (op sommige registers na)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Da's hetzelfde als met microcontrollers: die behouden ook hun geheugenwaardes bij een reset. (op sommige registers na)

Ok, de Reset heeft dan in feite dus een beperk effect.
In ieder geval dus niet de oplossing van mijn probleem dat ik de voedingsspanning er een keer of 6 af moet halen en weer aansluiten om het geheel aan de praat te krijgen.
Ik zou het eens kunnen proberen met een andere processor, bv de 887.

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

pic basic code:

 lIndex = (lIndex << 2) + (lIndex << 1)

is toch hetzelfde als:

pic basic code:

lIndex = (lIndex * 6)

?

Tenminste dat dacht ik. Maar als ik het tweede statement gebruik ipv de eerste dan leidt dat tot rare tekens op het scherm.

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Is er trouwens nog iets te zeggen of je beter voor I2C kunt kiezen dan SPI?

Nee,

I2C is slaapverwekkend traag bij grafische toepassingen (spi is 50x of meer sneller)

Shift en vermenigvuldigen is hetzelfde, alleen gaat shift veel sneller, omdat dat een 'native' instructie is.
(voor vermenigvuldigen heb je een library nodig)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Shift en vermenigvuldigen is hetzelfde, alleen gaat shift veel sneller, omdat dat een 'native' instructie is.

Maar wel heel apart dan dat

pic basic code:

lIndex = (lIndex * 6)

Een vreemd resultaat geeft. Ik heb het een paar keer getest, eerst de shift (die werkt) en daarna de vermenigvuldiging. Ondanks dat het trager is, zou het wel moeten werden, lijkt me.

(Lindex is als Word gedefiniëerd).

Fouten zijn het bewijs dat je het probeert..