# [SOLVED] ST7567 Graphic Display

#### jpanhalt

Joined Jan 18, 2008
9,037
I have an LG132643-DW-P1 graphic display from China (Yuxian, Laurellcd Store) that came with a 12-conductor FFC connector for SPI only. The controller is the Siltronics ST7567. The ST7565 is similar.

The specific chip I am using is the 16F1829 with Assembly. The SPI for that device does not allow a read, so it is send only. My problem is that regardless of the mode I use (0,1,2,3) a trial print to screen does nothing.

My question is whether anyone here has experience with either of those controllers in SPI mode? As you know, contrast is handled by code from the MCU and I have tried a range of contrasts from lowest to highest (i.e., 0..63 decimal). I can't rule out a defective screen. Two replacements are on order from mid-January via AliExpress. They presumably shipped January 20th by expedited e-packet, so the new year celebrations should not affect them, but they have not been received yet.

#### BobaMosfet

Joined Jul 1, 2009
1,056
And have you gotten the datasheet for the SITRONIX ST7567 (note the spelling) controller, which is what you need? Perhaps the display needs configured? I would first simply see if it response via SPI without an error in signal. Easy to do with a push-button to control signal input, and a scope to monitor signal lines.

https://www.newhavendisplay.com/appnotes/datasheets/LCDs/ST7567.pdf

Page 13, in particular begins to talk about the SPI signaling, which should be of interest to you.

Last edited:

#### jpanhalt

Joined Jan 18, 2008
9,037
Yes, I have the current datasheet v.1.7. I am using an SPI hook-up and code that I have used before. The timing diagrams seem to show the clock idles high and data are read on low to high transition (CKP= CKE = 1, Mode 2). The other common mode I have used in Mode 1 (CKP= CKE =0), but I have also tried the other two modes. Unlike some other SPI protocols I have used, commands are distinguished by the status of a separate pin, A0, and that status is read at the end of the byte. That is, somewhat like a 9th bit, but it is a separate pin. I keep that pin's status set (high or low) until after the byte is read (i.e., BF flag is set) and have tried several different delays from a few NOP's to 12 usec (MCU = 32 MHz, Tcy = 8 MHz, SPI clock = 2 MHz) without success.

That chip has a hardware reset. I have followed the sequence in the datasheet, which is also the same as an individual posted on the Internet. Spent this morning reconfirming the pinouts with a VOM.

It also hardware simulates, and I can see the data exchange from the PIC to the display in a watch window . Since in SPI, that display cannot be read, it returns all 1's to the SSP1BUF (buffer). The SSP1STAT,BF flag works as expected.

My replacement displays will hopefully get here this weekend so I an try another one.

Regards, John

#### Ian Rogers

Joined Dec 12, 2012
741
Hi John....
Looking at the datasheet it looks like there needs to be a latch on the 8th clock an A0 signal..

Lucky for us the SSPxIF is triggered just at that point, so using the interrupts you can set the latch on the 4th pin...

I haven't one to try but it looks easy enough to do..

#### BobaMosfet

Joined Jul 1, 2009
1,056
Looking at the pinout information (12-pin), I see A0 is held high when sending data, Low when sending instructions. Beyond that, I'd get a clear understanding of exactly how pins 10, 11, and 12 are powered. LCDs do not use constant voltage, they use a squarewave. Constant DC can burn them out. Make sure of what kind of power they are expecting you to provide for the LCD. It is unclear (since I don't have a datasheet for your display itself) as to whether or not they handle that aspect or not.

Here is another link you might find extremely helpful. You need to send a command to turn it on...

https://edeca.net/pages/the-st7565-display-controller/

Last edited:

#### jpanhalt

Joined Jan 18, 2008
9,037
Hi Ian and Boba,

My interpretation of the A0 latch it that it can be done either way. That is, one could use the IF or BF to set or clear A0 or just have it set appropriately before it is read . The later is a bit easier and seems to be what the examples I found use.

Here is what I am going on:

The datasheet is specific about reading data on the low-to-high transition, It also shows the idle states for CS and clock, but for A0 it doesn't show an edge transition and the idle state is what I interpreted as undefined (my code keeps it high). Later, I'll try using the BF (since I poll it) to toggle A0, since it is only a couple of lines of code.

As for pins 10-12, this device is only available as for <=3.3V. I didn't look at the schematics that carefully, but the configuration of the two capacitors is suggestive of a voltage doubler or quadrupler.

Here is snippet from a post by PAX Instruments that sold a device using this display through Adafruit for awhile (http://forum.espruino.com/conversations/271285/ )

C:
[LIST=1]
[*]spi.write([
[*]0xA2,//set the LCD bias to 1/9th
[*]0xA0,//horizontally "normal" (not flipped)
[*]0xC8,//vertically "flipped" (complements the command above)
[*]0x23,//the internal resistor divider set to 3 (from 0..7)
[*]0x2F,//power control, all internal blocks ON
[*]0x81,//enter dynamic contrast mode
[*]31,// Data for the dynamic contrast mode, set to 31 (from 0..63)
[*]0x40,//go back to the top left of the display
[/LIST]
And here is what I do:

Code:
;Mode 2
banksel   SSP1STAT       ;all SPI controls in Bank4                   |B4
clrf      SSP1STAT       ;CKE=1, SMP=1 (sample at middle)             |B4
bsf       SSP1STAT,6
movlw     b'00110001'    ;enable SPEN, set SPI CLK to Fosc/16
movwf     SSP1CON1       ;CKP=1,master clk =Fosc/x (see below)        |B4
movlb     2              ;                                            |B2
bsf       CSn            ;set high                                    |B2 WPU needed?
bsf       A0             ;idle high
bsf       RST            ;idle high
DelayCy   (10*msecs)
;*******************************************************************************
;Initialize 132x64 display
;*******************************************************************************
POR
bcf       RST
DelayCy   (100*msecs)
bsf       RST            ;use hardware reset
DelayCy   (1*msecs)      ;wait for reset to finish
That toggles RST to enter reset. Having A0 high or low didn't make a difference. Nor do those delays, but some authors say to give at least 1 us for the reset; some say more. Again, that made no difference. I then follow that with :
Code:
     movlw     b'10100010'    ;0xA2, bias 10 = 1/9, 11 = 1/7
call      PutCMD
movlw     b'10100000'    ;0xA0, seg direction = normal
call      PutCMD
movlw     b'11001000'    ;0xC8, com direction = flipped
;     movlw     b'11000000'    ;0xC0, com direction = normal
call      PutCMD
movlw     b'00100011'    ;0x23, set Regulation Ratio = 3.0
call      PutCMD
movlw     b'00101111'    ;0x2F, set power control
call      PutCMD         ;all internal blocks on
;     movlw     b'00011111'    ;0x1F, EV= 31 (center)
;     movwf     temp           ;second byte sent
;     movlw     b'10000001'    ;0x81, double command: Set EV
;     call      PutCMD2
movlw     b'10000001'    ;0x81, double command: Set EV
call      PutCMD
movlw     b'00011111'    ;0x1F, EV= 31 (center)
call      PutCMD         ;second byte sent
movlw     0x40           ;position start
call      PutCMD         ;
movlw     b'10101111'    ;0xAF, turn display ON
call      PutCMD
Lines 13-16 are an alternative to separate commands for a 2-command instruction. That made no difference. Line 23 is supposed to turn the display on, and it too makes no difference as the display is not on.

John

Edit: Toggling A0 didn't make a difference. Just hope the new displays arrive soon. Very unhappy with AliExpress.

Edit2: Fixed typo in code. The binary in line 9 for OX23 was shown as Ox25. That was a typo introduced in copying from my highly comment working version. Just to be safe, I retested with 0x23 and no change.

Last edited:

#### Ian Rogers

Joined Dec 12, 2012
741
Yeah! I think I misread that.... As long as A0 is HIGH/LOW at that clock point... I wish I had one to test..

#### Ian Rogers

Joined Dec 12, 2012
741
Hang on a Mo!! I have code for the ST7565 Looks identical... The SED1565 is the one they have copied from..

But As usual... I write in C..

#### jpanhalt

Joined Jan 18, 2008
9,037
Thanks for the encouragement. My displays (2) arrived today. Only one was broken that I can tell.

Anxious to try it, but the FPC cable pitch was smaller (0.5 mm pitch x 0.3 mm thick at the tab). So much for "specifications" that aren't there. Right now, I am trying to find a place that can get something to me next week. There are some options, Adafruit, eBay, Amazon, Proto-advantage, DigiKey, and others. I am trying to avoid buying the connector separately and doing the soldering. And so many specifications (like Amazon's) do not include thickness; although, 0.3 mm seems to be quite common.

I can't write C, but sometimes I can read enough of it for something like this to see the similarities. Anyway, my plans have stalled for another week. One of the things I like about this display is that it doesn't have a large surrounding bezel and the plastic has little legs on back that can snap into two slots on the PCB.

John

#### BobaMosfet

Joined Jul 1, 2009
1,056
@jpanhalt- The datasheet is pretty clear. You hold A0 high all the while that you send the display one type of data, and you hold it low all the while you send it another. This is the only way it knows whether you are sending it command data, or display data. You don't toggle it up and down on each clock cycle. So if a command takes 5 bytes of data, you hold A0 one way all the while sending that data, and then flip it the other way so the display knows the command is done. Same thing with data.

And yes, regarding pins 10,11, and 12, the caps are their to support the voltage doubling circuit in the chip-- but usually cap-based voltage doublers require pulsed waveforms. This is why I say this needs to be confirmed. Raw LCD displays are driven off of square wave-forms not straight DC, and so they may be utilizing this potentially already possible aspect for the doubler circuit. You could reach out to the LCD controller maker, if they have a web-page and perhaps they can answer this.

#### jpanhalt

Joined Jan 18, 2008
9,037
1) As for pulses, the ST chip has an oscillator,
Source=ST7567 datasheet
With built-in oscillation circuit and low power consumption power circuit, ST7567 generates LCD driving signal without external clock or power...
2) My reading of the byte transfer logic is that the status of A0 doesn't matter until the end, a "9th bit" so to speak. Albeit, it is on a different signal line. It is, of course, easy to do that before starting the SPI exchange, particularly since the LATx registers that should be used are in Bank 2 . Thus, CSn (out) and A0 are effectively in the same bank. Most of the other SPI-related (and I2C BTW) registers are in Bank 4. When I get a display working, I will test that assumption.

If I can trust Digikey and FedEx, I should be up and testing by Wednesday. I hate ordering from Digikey. It has so many goodies that I ended up spending $64 for a simple BOB (Adafruit) and FPC connector. I did add a few other things. #### BobaMosfet Joined Jul 1, 2009 1,056 Hi Ian and Boba, My interpretation of the A0 latch it that it can be done either way. That is, one could use the IF or BF to set or clear A0 or just have it set appropriately before it is read . The later is a bit easier and seems to be what the examples I found use. Here is what I am going on: View attachment 169778 The datasheet is specific about reading data on the low-to-high transition, It also shows the idle states for CS and clock, but for A0 it doesn't show an edge transition and the idle state is what I interpreted as undefined (my code keeps it high). Later, I'll try using the BF (since I poll it) to toggle A0, since it is only a couple of lines of code. As for pins 10-12, this device is only available as for <=3.3V. I didn't look at the schematics that carefully, but the configuration of the two capacitors is suggestive of a voltage doubler or quadrupler. Here is snippet from a post by PAX Instruments that sold a device using this display through Adafruit for awhile (http://forum.espruino.com/conversations/271285/ ) C: [LIST=1] [*]spi.write([ [*]0xA2,//set the LCD bias to 1/9th [*]0xA0,//horizontally "normal" (not flipped) [*]0xC8,//vertically "flipped" (complements the command above) [*]0x23,//the internal resistor divider set to 3 (from 0..7) [*]0x2F,//power control, all internal blocks ON [*]0x81,//enter dynamic contrast mode [*]31,// Data for the dynamic contrast mode, set to 31 (from 0..63) [*]0x40,//go back to the top left of the display [/LIST] And here is what I do: Code: ;Mode 2 banksel SSP1STAT ;all SPI controls in Bank4 |B4 clrf SSP1STAT ;CKE=1, SMP=1 (sample at middle) |B4 bsf SSP1STAT,6 movlw b'00110001' ;enable SPEN, set SPI CLK to Fosc/16 movwf SSP1CON1 ;CKP=1,master clk =Fosc/x (see below) |B4 movlb 2 ; |B2 bsf CSn ;set high |B2 WPU needed? bsf A0 ;idle high bsf RST ;idle high DelayCy (10*msecs) ;******************************************************************************* ;Initialize 132x64 display ;******************************************************************************* POR bcf RST DelayCy (100*msecs) bsf RST ;use hardware reset DelayCy (1*msecs) ;wait for reset to finish That toggles RST to enter reset. Having A0 high or low didn't make a difference. Nor do those delays, but some authors say to give at least 1 us for the reset; some say more. Again, that made no difference. I then follow that with : Code:  movlw b'10100010' ;0xA2, bias 10 = 1/9, 11 = 1/7 call PutCMD movlw b'10100000' ;0xA0, seg direction = normal call PutCMD movlw b'11001000' ;0xC8, com direction = flipped ; movlw b'11000000' ;0xC0, com direction = normal call PutCMD movlw b'00100011' ;0x23, set Regulation Ratio = 3.0 call PutCMD movlw b'00101111' ;0x2F, set power control call PutCMD ;all internal blocks on ; movlw b'00011111' ;0x1F, EV= 31 (center) ; movwf temp ;second byte sent ; movlw b'10000001' ;0x81, double command: Set EV ; call PutCMD2 movlw b'10000001' ;0x81, double command: Set EV call PutCMD movlw b'00011111' ;0x1F, EV= 31 (center) call PutCMD ;second byte sent movlw 0x40 ;position start call PutCMD ; movlw b'10101111' ;0xAF, turn display ON call PutCMD Lines 13-16 are an alternative to separate commands for a 2-command instruction. That made no difference. Line 23 is supposed to turn the display on, and it too makes no difference as the display is not on. John Edit: Toggling A0 didn't make a difference. Just hope the new displays arrive soon. Very unhappy with AliExpress. Edit2: Fixed typo in code. The binary in line 9 for OX23 was shown as Ox25. That was a typo introduced in copying from my highly comment working version. Just to be safe, I retested with 0x23 and no change. Your interpretation of A0 is wrong. I'm trying to tell you how it actually works. This is not guesswork on my part. Most of the LCD with controllers attached s out there work this way regarding a signal line telling the display whether you are sending it commands or data. Furthermore, you need to usually wait 5-15ms after each toggling for it to take effect. Thread Starter #### jpanhalt Joined Jan 18, 2008 9,037 I received a datasheet for my actual display, not just its controller. It differs mainly in recommended settings for the Booster ( 5 ver. 4), Regulator ratio (6.5 ver. 3.0), and EV (44 ver. 31) . New settings are given first. In brief, it was probably working, but the pixels weren't showing. It is fairly sensitive to those settings. Apparently my broad screens with different values did not hit the sweet spot. I will post cleaned code in the next day or two. I wanted to first clear up some things about delays and the timing of setting A0 low for commands, and by implication, high for data too. First off, I set the SPI clock to Fosc/4 = 8 MHz. That was just a convenience to make testing A0 easier. But it worked great at that 4xhigher clock rate. NO DELAYS were needed for writing commands or data. The only delay so far included in the code is 12 usecs right after Reset (RST) is released and set high. I have not taken the time to see whether even that is necessary. Second, A0 does NOT need to be set before starting the SPI exchange. Of course it works when that is done, and it requires less code to do, but it is not necessary. Here is my test code for PutCMD (A0 idles high): Code: PutCMD movlb 2 bcf CSn ; bcf A0 ;CMD/DAT bit, L=CMD movlb 4 movwf SSP1BUF ;set address to write to movlb 2 nop ;1 nop ;2 nop ;3 nop ;4 nop ;5 nop ;6 ; nop ;7 fail ; nop ;8 fail bcf A0 movlb 4 btfss SSP1STAT,BF bra$-1
movlb     2
bsf       A0             ;new 02/05  3:32
bsf       CSn
movlb     0
return
What that code does is move the byte to SSP1BUF to start the SPI exchange, then waits awhile, sets A0 low, then tests the BF flag to see whether transmission is done before returning. I determined that setting A0 low AFTER the BF is set will not work, and the timing sheets seems to show that it only needs to be set low before completion of the last bit (D0) to be transmitted. Of course, splitting that bit (D0) would be tricky.

My tests showed that I can add 6 NOP's, which corresponds to 6 SPI clocks, and it still works. With a 7th NOP, it fails.

Regards,
John

Edit: It has not escaped my attention that the "movlb 2" and "bcf A0" instructions count as 2 NOP's. I am just too lazy to slow the SPI clock down to refine the test. In any event, the time limit for clearing A0 is very close to the end of the 8th bit, which is what the datasheet says.

Last edited:

#### jpanhalt

Joined Jan 18, 2008
9,037
UPDATE

The display seems to be working fine. For reference, it is an LG132643-FFDWHUV from Laurel Electronics Co. , LTD in China. I have put a lot of comments in the code, which is how I keep my working routines.

Code:
;*******************************************************************************
;Setup SPI serial port
;*******************************************************************************
;;Mode 0                      ;CKP=0, CKE=1
banksel   SSP1STAT
clrf      SSP1STAT
bsf       SSP1STAT,6     ;CKE=1
movlw     b'00100000'    ;SPI clk = Fosc/16
movwf     SSP1CON1       ;CKP=0

;;Mode 1                      ;CKP=0,CKE=0
;     banksel   SSP1STAT       ;all SPI controls in Bank4                   |B4
;     clrf      SSP1STAT       ;CKE=0, SMP=0 (sample at middle)             |B4
;     movlw     b'00100001'    ;enable SPEN, set SPI CLK to Fosc/16
;     movwf     SSP1CON1       ;CKP=0,master clk =Fosc/x (see below)        |B4
;
;;Mode 2                      ;CKP=1,CKE=1
;     banksel   SSP1STAT       ;all SPI controls in Bank4                   |B4
;     clrf      SSP1STAT       ;CKE=1, SMP=1 (sample at middle)             |B4
;     bsf       SSP1STAT,6
;     movlw     b'00110001'    ;enable SPEN, set SPI CLK to Fosc/16
;     movwf     SSP1CON1       ;CKP=1,master clk =Fosc/x (see below)        |B4
;;Mode3                       ;CKP=1,CKE=0
;     banksel   SSP1STAT
;     clrf      SSP1STAT
;     movlw     b'00110001'
;     movwf     SSP1CON1
;NB: Modes 0,2,3 work with display.  Mode 1 does not.  Tested at Fosc/16 = 2 MHz.
;Modes defined as per Wikipedia. Reconfirmed with changes to DDRAM.
movlb     2              ;                                            |B2
bsf       CSn            ;idle high                                   |B2
bsf       A0             ;idle high
bcf       RST            ;idle low (hold in reset)
DelayCy   (10*msecs)     ;1 ms for power to stablize may be sufficient
Code:
;*******************************************************************************
;Initialize 132x64 display
;*******************************************************************************
POR
bsf       RST            ;release from Reset
movlw     26             ;delay d.26 = 9.875 usec delay
decfsz    WREG           ;delay
bra       $-1 ;delay ;Datasheet for the ST7567 suggests >5 usec delay after releasing from Reset, ;but other sources,including the Display datasheet, recomment >10 usec. Some ;sources even recommend just >1 usec. Other delays tried that work are d.13 ;(5 usec), d.3 (1.25 usec), 4x NOP (0.5 usec), and no delay. movlw b'10100010' ;0xA2, bias = 1/9 call PutCMD ; movlw 0xA0 ;seg direction = normal, 0xA1 = reversed call PutCMD ; movlw b'11001000' ;0xC0, com direction = normal, 0xC8 = reverse call PutCMD ; movlw 0xF8 ;set boost = x5, double command call PutCMD ; " movlw 0x01 ; " call PutCMD ; " movlw b'00100111' ;0x27, set Regulation Ratio = 6.5 call PutCMD ; movlw 0x81 ;double command: Set EV call PutCMD ; " movlw 0x2C ;EV = 44 dec call PutCMD ; " ;Other EV's tried: ;0x1F = EV= 31 (center) 31->blank ;0x23 = very faint ;0x2B = not bad ;0x2D = not much different from 0x2C ;set power control blocks on ; movlw b'00101100' ;0x2C,set booster on ; call PutCMD ;not essential ; movlw b'00101110' ;0x2E,set regulator on ; call PutCMD ;not essential movlw b'00101111' ;0x2F,set voltage follower on call PutCMD ;all internal blocks now on #essential movlw b'10101111' ;0xAF, turn display ON #essential call PutCMD call ClrDDRAM ; call LngDly ;############################################ bra TestScrn ;############################################ Blink ;screen commands only, do not affect DDRAM ; movlw 0xA5 ;turn all pixels on ; call PutCMD ; DelayCy (100*msecs) ;allows recognition ; movlw 0xA4 ;turn all pixels off ; call PutCMD ; DelayCy (100*msecs) ;allows recognition ; bra Blink ;### Not completely sure what these do: ### ; movlw 0xEE ;end RMW ; movlw 0xE0 ;start RMW ; call PutCMD ClrDDRAM ;Under Debug, stopwatch showed 57287 Tcy for ClrDDRAM ;or 7.160 msecs @ 32MHz fosc and SPI clk @ fosc/16. With SPI clk @ fosc/4 ;31367 Tcy required or 3.921 msecs. If called from program be sure to add a ;sufficient delay. ;The ST7567 is specified for 132x65, but the ;65th line (9th row) is only 1-bit high. Judging from the absence of a faint ;line on the screen for 9th row, it does not appear to be implemented and was ;not addressed in this code. movlw 0xB8 ;0xB7 +1 movwf temp _Erase movlw 1 subwf temp,f btfss STATUS,1 return ;DC clear when "borrow" movf temp,w call PutCMD ;set row (7..0) movlw 0x10 ;set column high byte = 0 call PutCMD ; " movlw 0x00 ;set column low byte = 0 call PutCMD ; " movlw 132 ;accounts for skip on 0 movwf count movlw 0x00 ;write all zeros _DoRow call PutDat ; " decfsz count,f bra _DoRow ;WREG should return with WREG=0 (works 02/14/19) bra _Erase Test screen: Code: ;******************************************************************************* TestScrn ;same as ClrDDRAM w/ different character written movlw 0xB8 ;0xB7 +1 movwf temp _Test movlw 1 subwf temp,f btfss STATUS,1 bra Main ;return ;DC clear when "borrow" movf temp,w call PutCMD ;set row (7..0) movlw 0x10 ;set column high byte = 0 call PutCMD ; " movlw 0x00 ;set column low byte = 0 call PutCMD ; " movlw 132 ;accounts for skip on 0 movwf count movlw 0xF0 ;write stripes, etc. ######################### _DoRows call PutDat ; " decfsz count,f bra _DoRows ;WREG should return with WREG=0 (works 02/14/19) bra _Test Main nop bra$-1
;*******************************************************************************
Called subroutines:
Code:
PutCMD
movlb     2
bcf       CSn
bcf       A0             ;CMD/DAT bit, L=CMD
movlb     4
movwf     SSP1BUF
btfss     SSP1STAT,BF
bra       $-1 bsf A0 ;new 02/05 3:32 bsf CSn movlb 0 return PutDat movlb 2 bsf A0 ;A0 should idle high bcf CSn movlb 4 movwf SSP1BUF ;put data btfss SSP1STAT,BF bra$-1
movlb     2              ;
bsf       CSn
movlb     0
return
;*******************************************************************************
LngDly
movlw    0x48
movwf    d1
movlw    0x71
movwf    d2
movlw    0x12
movwf    d3
Delay_0
decfsz    d1, f
bra      $+2 decfsz d2, f bra$+2
decfsz    d3, f
bra      Delay_0
return
And finally, a picture of the test pattern:

Edit: I forgot one little detail that might be important for those accustomed to character displays. The pages do not wrap, which might be an advantage for clearing the rest of a row of characters, since the SPI interface cannot read the screen.

Edit2: I forgot to mention that #### is used to highlight things that I would not normally include, such as LngDly in usable code. LngDly ≈ 1 second.

Last edited: