Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

U8G2 with STM32 and 12864B LCD over SPI Displaying Random Pixels #840

Closed
berndoJ opened this issue Mar 17, 2019 · 28 comments
Closed

U8G2 with STM32 and 12864B LCD over SPI Displaying Random Pixels #840

berndoJ opened this issue Mar 17, 2019 · 28 comments

Comments

@berndoJ
Copy link

berndoJ commented Mar 17, 2019

Hello,

so I've followed the porting guide (https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform) on how to port u8g2 to a custom MCU platform. In my case I use an STM32F072RBT7 (ARM Cortex-M0 Core) STM32-MCU.
It seems that my port of the hardware dependant functions at least kinda works, as data is pushed out over spi. (I checked it with an oscilloscope)
The problem is that after the init of the display random pixels are displayed on screen, with 32 pixel wide white / inverted areas. (see image).

I use an 12864B 128x64 graphical LCD (I think its even the same one as in the SPI example of the setup tutorial), driven over SPI (SCK, MOSI, CS, RST), which uses the ST7920 LCD-Controller. As I've succeeded in driving this exact LCD with an Arduino before, this LCD is known good.

As firmware I use FreeRTOS and STM32CubeMX, which generates the HAL libs for my STM32 device.

I don't know if it is the issue of my hw port or if something different is going on...

Image of the LCD after init:
lcd

display.c : Here the u8g2 is initialised.
display.c.txt

u8g2_stm32_hw_port.c : here are the functions used to port u8g2 to my device.
u8g2_stm32_hw_port.c.txt

Thanks in advance,
berndoJ

@olikraus
Copy link
Owner

looks like no data is transfered.
In the C code: Also the other delay messages need to be handled.

@berndoJ
Copy link
Author

berndoJ commented Mar 18, 2019

Hello,

thanks for the quick response olikraus.

So I've added the remainding delay messages (from the porting guide) to my C-code. (Attached)
Then I've checked the data agin with an oscilloscope and sure enough, here's whats being sent on init (blue MOSI yellow SCK):
pic_17_1

After all this the display shows the same random pixels.

But then, after checking the datasheet of the LCD to decode some of the messages sent on start, I noticed that the bytes should not be sent in 8 bit packets, but rather in 24 bit ones. I don't know if this may be the cause of my error, as I am always sending packets in 8 bits, not 24.

Regards,
berndoJ

New u8g_stm32_port.c
u8g2_stm32_hw_port.c.txt

@olikraus
Copy link
Owner

looks like no data is transfered.

Can you check the CS signal line also?

It should change after some bytes of data and also there must be a delay between the last bit of the last byte and the level change of CS

Looking at your picture: It looks like high level is 3 Volt only. This is too less for the ST7920 which is a very old 5V IC.

@berndoJ
Copy link
Author

berndoJ commented Mar 18, 2019

Actually, the oscilloscope was set to 2V / Division, so the signal is 5V (there is a 74LVC4245APW voltage level translator between the STM32 and LCD).
Here's a whole shot of the startup sequence, blue is CS and yellow is the clock (note that it is zoomed out very far to capture whole sequence, so the clock seems to only be a pulse, but actually its more short pulses.)
pic_18_1

Here's the CS at the start of the sequence:
pic_17_2

@olikraus
Copy link
Owner

ok, at least one thing what is missing are the post cs and pre cs wait times:
https://github.com/olikraus/u8g2/blob/master/csrc/u8x8_byte.c#L150

@olikraus
Copy link
Owner

Additionally I suggest to set the CS level to a proper default: https://github.com/olikraus/u8g2/blob/master/csrc/u8x8_byte.c#L141

@olikraus
Copy link
Owner

the other question also is: Did you apply the correct SPI mode? The ST7920 is a little bit sensitive for this.

@berndoJ
Copy link
Author

berndoJ commented Mar 18, 2019

So I've corrected the CS pre and post timing, added the defauklt state of the CS and corrected the SPI mode. Apparently the SPI mode of the ST7920 is 3, so I had to tweak my SPI settings a bit.

Now I am at a point where after calling my draw routine in display.c (unedited since last attachment) where usually a string should be drawn, the display is completely blank. (no random pixels, I can see it update to a blank screen after init).

I know that the display routine is run because of the output in the serial debug console.

@olikraus
Copy link
Owner

Which setup did you use? How does your code look like?

@berndoJ
Copy link
Author

berndoJ commented Mar 19, 2019

This is my hardware setup:

LCD (12864B) connected:
VCC to 5V0, backight to 3V3, VSS to GND;
E to SPI SCLK
R/W to SPI MOSI
RS to SPI CS
PSB to GND (Parallel / serial select)

SCLK, MOSI and CS are connected to the STM32 via a voltage translator (3V3 to 5V0, 74LVC4245APW) which has been tested and considered in working condition.

The contrast of the display is controlled with an onboard (on the LCD module PCB) potentiometer, and is tuned correctly. (See image in original post, the pixels can be seen)

The STM32 is set up using CubeMX software, which generates the code and configures the HAL library of the STM32.

As a debugger, a STLINKV2 is used.

The version of u8g2 was pulled from this GitHub repo on 17th of March 2019.

Here's the code:

  • display.c / display.h
    Here all the display drawing code is run. display_init function is called in init, display_run_thread is called after init, when FreeRTOS started the "thread" where I want the display code to be run.
    display.c.txt
    display.h.txt

  • u8g_arm.c / u8g_arm.h
    u8g_arm.c is the file containing all the necessary code for the hw port of the U8G2 lib to the STM32.
    u8g_arm.c.txt
    u8g_arm.h.txt

All display relevant code and / or code interfacing with the u8g2 library is contained within these two files and the assertion can be made, that display_init is called in init and display_run_thread after init from a thread from main.c.

Regards,
berndoJ

@berndoJ berndoJ closed this as completed Mar 19, 2019
@berndoJ berndoJ reopened this Mar 19, 2019
@olikraus
Copy link
Owner

ok, display.c looks good. What about the reset input of the display? The reset u8x8 reset message U8X8_MSG_GPIO_RESET is not handled (did I miss this?). Then: What about the v0 input of the display. It should be connected to the wiper of a var pot to control the contrast.

@berndoJ
Copy link
Author

berndoJ commented Mar 19, 2019

So the V0 input is controlled via an onboard potentiometer (its directly on the lcd, measured it and it is connected to V0)

U8X8_MSG_GPIO_RESET: I've added it to my code now. Nothing changed.

@olikraus
Copy link
Owner

Hmm I am running out of ideas.

@berndoJ
Copy link
Author

berndoJ commented Mar 19, 2019

Yes, weird I know...

@berndoJ
Copy link
Author

berndoJ commented Mar 19, 2019

So I think I will check out if it makes a difference, if you send 24 bit blocks or 3 8 bit blocks to the ST7920 controller.
Also, by reading various comments / blogs about the ST7920 a lot of people say that it is quite sensitive and tricky... Well, hope I'll fix it.

@berndoJ
Copy link
Author

berndoJ commented Mar 19, 2019

Just for info: This is a export of the data being sent. Basically, every time U8X8_MSG_BYTE_SEND is called, it prints S-arg_int and then for each data byte D-data_byte_value. I know its long, but is it intentional to send individual 8 bit packets for example in init? (e.g. f8-30-80 is interpreted by the display as f83080 but is sent f8-30-80)

output_2019-03-19_23-02-59.txt

@olikraus
Copy link
Owner

olikraus commented Mar 20, 2019

f8-30-80 is interpreted by the display as f83080 but is sent f8-30-80

not sure what you mean about this. What should be the difference?

if you send 24 bit blocks or 3 8 bit blocks to the ST7920 controller.

There is no other option. Arduino IDE only has a 8 Bit SPI interface, so it has to be 3x 8Bit. But this works quite well for my personal boards and displays.

Let me check your log:

[Kernel] Started serial port thread.
S-1
D-f8
[Kernel] Started util thread.
S-1
D-30
S-1
D-80
[Init] GPIO initialisation status OK.

Indeed the first init command for the display is 0x38: https://github.com/olikraus/u8g2/blob/master/csrc/u8x8_d_st7920.c#L50
This command must be sent as a 24 bit sequence (very inefficient, by the way): 0xf8 0x30 0x80

The conversion from 0x38 to the three byte sequence 0xf8 0x30 0x80 happens here:
https://github.com/olikraus/u8g2/blob/master/csrc/u8x8_cad.c#L361

Except for the interrupting "Kernel" messages, the output sequence seems to be correct.

@olikraus
Copy link
Owner

Also, by reading various comments / blogs about the ST7920 a lot of people say that it is quite sensitive and tricky... Well, hope I'll fix it.

I agree. Many requests here and on arduino.cc are problems related to ST7920 displays. It seems to be very sensitive regarding timing and wiring.

@berndoJ
Copy link
Author

berndoJ commented Mar 20, 2019

So I am curious:

I just checked the log again and I assume that every time 16 bytes are being transfered (so when S-10 (hex) is proceeding the data) pixel data is sent. But there is not single occurence of a non-zero byte in these 16 bytes after S-10. If my understanding is correct, doesn't this mean that the LCD displays a blank screen, because only null-bytes are sent to it? Or am I wrong?

@olikraus
Copy link
Owner

If my understanding is correct, doesn't this mean that the LCD displays a blank screen, because only null-bytes are sent to it? Or am I wrong?

Yes, thats why I asked for the rest of your code. But this looks already ok:

	u8g2_FirstPage(&u8g2);
	do
	{
		u8g2_SetFont(&u8g2, u8g2_font_fur11_t_symbol);
		u8g2_DrawStr(&u8g2, 0, 20, "Hello World!");
	} while (u8g2_NextPage(&u8g2));

Maybe you could draw a box (drawBox) or a line (drawLine), just to ensure, that there are no other issues.

@berndoJ
Copy link
Author

berndoJ commented Mar 21, 2019

I've tried it with pixel sets and some rectangle graphics, but still nothing...
Also, I've tried to set the draw color, but no effect.

This is the whole code:

code_u8g2_example_roc_controller.zip

@olikraus
Copy link
Owner

So you say: The display becomes blank and all the data is zero in the log file.
This means: The display works but some HAL procedure makes every to zero. Strange.

Oh, there is a "break" statement missing before "case U8X8_MSG_BYTE_END_TRANSFER:"
Maybe this is your problem.

@berndoJ
Copy link
Author

berndoJ commented Mar 21, 2019

Ok, so here's whats happened:

So I've missed this one break statement, and sure enough, that fixed it. But the text wasn't showing, only a rectangle... So I've looked into it and i realised that I used a symbol font, not a normal font, so one small change and now the text also works. I also found out, that the display also runs with an SPI clock of 750kHz as well as default SPI-mode. (So default and 3)

I would say that the missing break statement was "ein absoluter Klassiker", if you know what I mean :)

Here's the working display:
helloworld2

Thank you for the extensive help olikraus, It is very appreciated from my side.

This issue is hereby closed.

Regards,
berndoJ

@berndoJ berndoJ closed this as completed Mar 21, 2019
@olikraus
Copy link
Owner

"ein absoluter Klassiker"

tja...

I am happy that everything works :-)

@klen25
Copy link

klen25 commented Jun 30, 2021

I get same problem
So, where is the "break" statement that youre fix it and where you change the "symbol font" to "normal font"?

@Donatussss
Copy link

Hello @olikraus, @berndoJ, please, which break statement were you guys referring to if your remember?

@berndoJ
Copy link
Author

berndoJ commented May 22, 2024

The missing break statement was in the µC port code in u8g_arm.c (my code!!!) before case U8X8_MSG_BYTE_END_TRANSFER: in the u8g_hw_port_byte_cb function.

The file was linked in this comment:

This is my hardware setup:

LCD (12864B) connected: VCC to 5V0, backight to 3V3, VSS to GND; E to SPI SCLK R/W to SPI MOSI RS to SPI CS PSB to GND (Parallel / serial select)

SCLK, MOSI and CS are connected to the STM32 via a voltage translator (3V3 to 5V0, 74LVC4245APW) which has been tested and considered in working condition.

The contrast of the display is controlled with an onboard (on the LCD module PCB) potentiometer, and is tuned correctly. (See image in original post, the pixels can be seen)

The STM32 is set up using CubeMX software, which generates the code and configures the HAL library of the STM32.

As a debugger, a STLINKV2 is used.

The version of u8g2 was pulled from this GitHub repo on 17th of March 2019.

Here's the code:

* display.c / display.h
  Here all the display drawing code is run. display_init function is called in init, display_run_thread is called after init, when FreeRTOS started the "thread" where I want the display code to be run.
  [display.c.txt](https://github.com/olikraus/u8g2/files/2983943/display.c.txt)
  [display.h.txt](https://github.com/olikraus/u8g2/files/2983944/display.h.txt)

* u8g_arm.c / u8g_arm.h
  u8g_arm.c is the file containing all the necessary code for the hw port of the U8G2 lib to the STM32.
  [u8g_arm.c.txt](https://github.com/olikraus/u8g2/files/2983966/u8g_arm.c.txt)
  [u8g_arm.h.txt](https://github.com/olikraus/u8g2/files/2983967/u8g_arm.h.txt)

All display relevant code and / or code interfacing with the u8g2 library is contained within these two files and the assertion can be made, that display_init is called in init and display_run_thread after init from a thread from main.c.

Regards, berndoJ

I see this issue linked in topics that frankly do not have anything to do with the issue at hand. The port of the u8g hw-interface was done according to the wiki docs, the issue was that I had that one break statement missing in my code, thus a unwanted switch/case fallthrough to the U8X8_MSG_BYTE_END_TRANSFER section from U8X8_MSG_BYTE_SEND.

Also, iirc, the symbol font thing was just a RTFM for me regarding on how to properly set up & use u8g2 in the code itself. I even attached the (working) code I've used in the previous answers:

void display_run_task(void)
{
	debug_cons_println("[Display] Initialising display...");
	u8g2_Setup_st7920_s_128x64_2(&u8g2, U8G2_R0, u8g_hw_port_byte_cb,
			u8g_hw_port_gpio_delay_cb);
	debug_cons_println(
			"[Display] Initialised display communication over SPI.\n[Display] Initialising U8G2.");
	u8g2_InitDisplay(&u8g2);
	u8g2_SetPowerSave(&u8g2, 0);
	debug_cons_println("[Display] Initialisation done.");

	display_draw();

	for (;;)
	{
		osDelay(500);
	}
}

void display_draw(void)
{
	debug_cons_println("[Display] Display draw routine init.");
	u8g2_FirstPage(&u8g2);
	do
	{
		u8g2_SetDrawColor(&u8g2, 1);
		u8g2_SetFont(&u8g2, u8g2_font_fur11_t_symbol);
		u8g2_DrawStr(&u8g2, 0, 20, "Hello World!");
		u8g2_DrawPixel(&u8g2, 3, 3);
		u8g2_DrawRFrame(&u8g2, 20, 15, 30, 22, 7);
	} while (u8g2_NextPage(&u8g2));
	debug_cons_println("[Display] Display draw routine done.");
}

Regarding other details I would really suggest you taking a look at the libraries docs in the GitHub wiki, this issue is already 5 years old and things may have changed during this time.

Cheers,
berndoJ

@olikraus
Copy link
Owner

@berndoJ thanks for your answer. I have access via cellphone only at the moment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants