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

Using the 12864-06D display, and how does flipmode work? (startup code and flipmode 0 code do not match) #1792

Closed
olikraus opened this issue Feb 22, 2022 Discussed in #1791 · 11 comments
Labels
Milestone

Comments

@olikraus
Copy link
Owner

Discussed in #1791

Originally posted by RvanDeelen February 22, 2022
So a while ago i bought some displays of aliexpress. As one does. They were explicitly specified as being "right to left written".
It took me ages to get t the right constructor but in the end i found out that "U8G2_ST7565_NHD_C12864_1_4W_SW_SPI" will work. Because before this i used U8G2_ST7565_KS0713_1_4W_SW_SPI constructor, but altered the ADC reversal line manually in the library.
So now everything is oriented correctly (writing left to right and no mirrored letters), For my use case i did have to use rotation R2 but that's besides the point.

Something i don't understand tho is how the flipmode works in the constructor code. how can i know if the flipmode instruction actually works looking at the library?

@olikraus olikraus added the bug label Feb 22, 2022
@olikraus olikraus added this to the 2.32 milestone Feb 22, 2022
@olikraus
Copy link
Owner Author

The code for flipmode is only sent to the display if the flipmode command (https://github.com/olikraus/u8g2/wiki/u8g2reference#setflipmode) is used. Ideally setFlipMode(0) should be executed automatically by the constructor. Unfortunately this isn't done (I missed this very early in the development now I am too lazy to fix this).
As a result, the commands for flip mode 0 must be implemented in the constructor startup code and in the flipmode 0 sequence itself.

In your case:

uint8_t u8x8_d_st7565_ks0713(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)

The flip mode sequence is sent here:

u8g2/csrc/u8x8_d_st7565.c

Lines 819 to 830 in d9402d5

case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
if ( arg_int == 0 )
{
u8x8_cad_SendSequence(u8x8, u8x8_d_st7565_flip1_seq);
u8x8->x_offset = u8x8->display_info->default_x_offset;
}
else
{
u8x8_cad_SendSequence(u8x8, u8x8_d_st7565_flip0_seq);
u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
}
break;

And the commands are repeated in the normal startup sequence of that display:

u8g2/csrc/u8x8_d_st7565.c

Lines 787 to 802 in d9402d5

static const uint8_t u8x8_d_st7565_ks0713_init_seq[] = {
U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
U8X8_C(0x0ae), /* display off */
U8X8_C(0x0e2), /* soft reset */
U8X8_C(0x0a3), /* LCD bias 1/9 */
U8X8_C(0x0a0), /* ADC set to reverse */
U8X8_C(0x0c0), /* common output mode */
U8X8_C(0x02f), /* all power control circuits on (regulator, booster and follower) */
U8X8_C(0x026), /* set V0 voltage resistor ratio to max */
U8X8_C(0x0a6), /* display normal, bit val 0: LCD pixel off. */
U8X8_CA(0x081, 0x010), /* set contrast, contrast value, EA default: 0x016 */
U8X8_C(0x0af), /* display on */
U8X8_END_TRANSFER(), /* disable chip */
U8X8_END() /* end of sequence */
};

Which is actually defined here:

static const uint8_t u8x8_d_st7565_flip0_seq[] = {
U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
U8X8_C(0x0a1), /* segment remap a0/a1*/
U8X8_C(0x0c0), /* c0: scan dir normal, c8: reverse */
U8X8_END_TRANSFER(), /* disable chip */
U8X8_END() /* end of sequence */
};
static const uint8_t u8x8_d_st7565_flip1_seq[] = {
U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
U8X8_C(0x0a0), /* segment remap a0/a1*/
U8X8_C(0x0c8), /* c0: scan dir normal, c8: reverse */
U8X8_END_TRANSFER(), /* disable chip */
U8X8_END() /* end of sequence */
};

But it seems, that the flip mode sequences are wrong. and the code for flip mode 0 and startup do not match.
In startup we have the commands 0xa0 and 0xc0, however flipmode 0 will send the wrong code 0xa1 0xc0.
This means, the display will be ok as long as you do not use the flipmode command, but will destroy the content after first use of flipmode.

Is this the problem you observed?

To fix this, I need to change

u8x8_cad_SendSequence(u8x8, u8x8_d_st7565_flip1_seq);

to zflip1 and
u8x8_cad_SendSequence(u8x8, u8x8_d_st7565_flip0_seq);

to zflip0

hmm looks like a bug in u8g2...

@olikraus olikraus changed the title Using the 12864-06D display, and how does flipmode work? Using the 12864-06D display, and how does flipmode work? (startup code and flipmode 0 code do not match) Feb 22, 2022
@RvanDeelen
Copy link

I didn't perceive it as a bug at first as it just wasn't documented which constructor would would with my specific display, If i use the U8G2_ST7565_KS0713_1_4W_SW_SPI one (without any edits or .setfontdirection or anything) it looks like the image below. If i use the other it looks normal.
IMG_20220222_103146 1
The working constructor doesn't need the flipmode to work. but i still like to understand it.

@RvanDeelen
Copy link

Incidentally, the U8G2_ST7565_NHD_C12864_1_4W_SW_SPI constructor also stops the very first (current last) column of pixels being cut off. One line up from the bottom, the right most character is supposed to be a capital V . The clear border arround all the text is just how the display is made. there are no pixels there. I think the little black vertical line on the left is either left over in the buffer, or it's that cut off bit of the V that got put over there.

@olikraus
Copy link
Owner Author

olikraus commented Feb 22, 2022

I didn't perceive it as a bug at first as it just wasn't documented which constructor would would with my specific display

Indeed you need to test which constructor fits best to your needs.
The ST7565 is actually a controller for up to 132 x 65 pixel.
However if a display has 128x64 pixel, then there are 4x2 = 8 possibilities for the location of the 128x64 window within the 132x65 frame buffer. If the 128x64 is shifted in such a way, so that, for example, the two leftmost columns of the display controller are not connected to the LCD, then it appears, that some text is missing like in your image. U8g2 basically does not know how the LCD is connected to the controller.
Moreover each display vendor can swap the assignment between pixel columns/rows and pins of the display controller. This are 4 more possibilites, so wie have 8x4 = 32 different possibilites how a 128x64 display can be connected to the ST7565. Then there are different technologies which require different driving voltage so on one display it might be to dark on others too light, Which gives even more possibilites in total.

So instead of just numbering the constructors from 1 to 32 i just took the first display name with a specific architecture and named it according to that display name (like NHD_C12864). So it indicates that this was once implemented for the New Haven https://www.newhavendisplay.com/nhdc12864a1zfsrgbfbwht1-p-3896.html display. But of course it might also fit to any other display with the same architecture.

So my suggest is this: Please check all of the current constructors for a 128x64 display:

ST7565 EA_DOGM128
ST7565 LM6063
ST7565 64128N
ST7565 ZOLEN_128X64
ST7565 LM6059
ST7565 KS0713
ST7565 LX12864
ST7565 ERC12864
ST7565 ERC12864_ALT
ST7565 NHD_C12864
ST7565 JLX12864
ST7565 NHD_C12832

Ignore the contrast, just observe whether the text is correct or not.
Contast can be adjusted always later with the setContrast command.

@RvanDeelen
Copy link

RvanDeelen commented Feb 23, 2022

So do you want me to try all constructers for each display type? or just the ones that would work protocol wise, ie 4W SW spi.

in any case, i tried all the 4W software SPI versions and this is what i got with these settings:
u8g2.setFont(u8g2_font_5x7_tr);
u8g2.setContrast(0);
u8g2.setColorIndex(1);
and U8G2_R2 given to the constructor as a rotation.
I don't have the reset line attached.

ST7565 EA_DOGM128
The screen rotation is correct, but the text is 4 pixels to far to the right. largest contrast possible.
Also the first column of characters is duplicated in that 4 pixel wide space.

ST7565 LM6063
Same thing, but low contrast. Doesn't respond to changing it via the instruction

ST7565 64128N
No display at all, everything from the previous display is erased.

ST7565 ZOLEN_128X64
The text is flipped horizontally and very low contrast. Does not respond to changing it.
The first column of characters is also duplicated

ST7565 LM6059
Text on each horizontal half is rotated 180 degrees, So the top 32 pixels are rotated and the bottom 32 are. Also the contrast is messed up and almost fully black on black. No response to the contrast function.

ST7565 KS0713
Strongest contrast possible. Text written from right to left and vertically mirrored. Right most column of pixels is cut off and put on the left most column of the display.

ST7565 LX12864
same issue as with ST7565 LM6059. But not it is very low contrast and faint. No response to changing it
Also the top 4 lines of pixels are cut off of the display, and displayed at the bottom 4 pixels.

ST7565 ERC12864
bad contrast with almost black on black. All text is rotated 180 degrees as a whole. No response to the contrast command.

ST7565 ERC12864_ALT
Very faint text, Also rotated 180 degrees. no response to contrast change.

ST7565 NHD_C12864
The one i used before. looks good. nothing cut off.

ST7565 JLX12864
Works correctly, nothing cut off or rotated. strong contrast between fully on and off pixels. Also no contrast reponse

ST7565 NHD_C12832
That's a 32 pixel display constructor,

All in all i'm 99% sure my particular display just flat out doesn't have contrast control or it has some weird register for it that non on the constructors use.
All i know is that it's ST7565 based
image

@olikraus
Copy link
Owner Author

wow, nice summary.

The jlx is indeed identical to the nhd constructor:

u8g2/csrc/u8x8_d_st7565.c

Lines 686 to 689 in d9402d5

uint8_t u8x8_d_st7565_jlx12864(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
return u8x8_d_st7565_nhd_c12864(u8x8, msg, arg_int, arg_ptr);
}

The contranst should work also for your display, unless you have undefinde the macro here:

u8g2/csrc/u8x8_d_st7565.c

Lines 167 to 173 in d9402d5

#ifdef U8X8_WITH_SET_CONTRAST
case U8X8_MSG_DISPLAY_SET_CONTRAST:
u8x8_cad_StartTransfer(u8x8);
u8x8_cad_SendCmd(u8x8, 0x081 );
u8x8_cad_SendArg(u8x8, arg_int >> 2 ); /* st7565 has range from 0 to 63 */
u8x8_cad_EndTransfer(u8x8);
break;

To test the contranst you could also use the set contranst example, which loops over the contrast.

Another way would be to manually send the contrast value with SendF("ca", 0x81, contranst_value).
Note that contranst_value in SendF command is from 0 to 63, but u8g2 expects 0 to 255.

You said you selected the correct constructor, but in your picture it seems to be shiftet by some pixel. I am confused. Is there an issue or: Which constructor / commands had been used to generate the shift in the picture?

@RvanDeelen
Copy link

RvanDeelen commented Feb 23, 2022

You said you selected the correct constructor, but in your picture it seems to be shiftet by some pixel. I am confused. Is there an issue or: Which constructor / commands had been used to generate the shift in the picture?

What i mean by that is that when i used a particular wrong one, (in this case U8G2_ST7565_KS0713_1_4W_SW_SPI one) that was one of the results i got.
Right now, when using U8G2_ST7565_NHD_C12864_1_4W_SW_SPI u8g2 (U8G2_R2, 13, 11, 10, 9); as a constructor it looks like this.
image
Nothing is shifted and the contrast seems to be fully black on white text.
Now i might be not knowledgeble enough about SPI. But does software SPI also use that specific start and end transfer behind the scenes like the contrast function does.? As if it doesn't, that might be why it's not responding. I can see U8X8_START_TRANSFER(), and U8X8_END_TRANSFER(), used in 20 other places. But the contrast function has it's own specific version it seems.

@olikraus
Copy link
Owner Author

olikraus commented Feb 23, 2022

Nothing is shifted and the contrast seems to be fully black on white text.

ok looks good

But does software SPI also use that specific start and end transfer behind the scenes

There should be no difference between SW SPI and HW SPI.
Infact only the communication part is exchanged. The data transfer should be the same. Maybe I should test whether the sw spi still allows changing the contrast.

So as a summary for this issue:

  • U8G2_ST7565_KS0713 flip mode sequence is wrong
  • I should test why set contrast doesn't work for any (?) of the constructors

@RvanDeelen
Copy link

If you want to test contrast, i only have one kind of display. So for all we know there is no contrast instruction in this one and the changing contrast is just a result of something else funky.

@olikraus
Copy link
Owner Author

olikraus commented Feb 23, 2022

hmmm... I never came across a display, which does not allow contrast setup.
Technically there are two options: The controller generates the LCD voltage or the LCD voltage is provided by an external circuit. Indeed if there is an external circuit then the LCD contrast adjustment is not possible via software commands. However the internal voltage generation includes an amplifier with controllable gain (64 steps). I have never seen this controller with an external circuit, in other words for all known displays with this controler the contrast can be adjusted via software commands.

The contrast itself is also changed by some other parameters like refresh rate. So it might indeed differ between LCDs.

olikraus added a commit that referenced this issue Mar 4, 2022
@olikraus
Copy link
Owner Author

olikraus commented Mar 4, 2022

fixed flip sequence

@olikraus olikraus closed this as completed Mar 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants