olikraus / u8g2

U8glib library for monochrome displays, version 2
Other
5k stars 1.04k forks source link

UC1698 #1120

Closed mcarosh closed 4 years ago

mcarosh commented 4 years ago

Hi Mr olikraus Would it be possible to add the UC1698 driver? I´ve tried already some some different driver, most success was the "U8G2_UC1611_CG160160_1_8080" driver but more isn´t possible :( (see picture) DSC_20200301_002755_331 I´ve also found a Data sheet for the uc1698 UC1698.pdf So if it makes not to much circumstances I would be very happy Meanwhile stay brave ;) regards mcarosh

olikraus commented 4 years ago

I already tried to add support for the UC1698 long time back, but I actually failed. I do not know whether my hardware setup was wrong or whether the had been a software error.

The UC1698 differs a lot from any other know LCD controllers and without having a known good device in my lab, it will be almost impossible to add support for this controller.

Where did you buy your display? It looks like it came with a breakout board?

Hmm... it could be this display: https://www.aliexpress.com/i/32914228404.html

Problem is, that shipping time is unpredictable at the moment from China to Germany.

mcarosh commented 4 years ago

Hi First of all thx a lot for answering :) To be honest I couldn´t tell where I´ve bought this display. It´s a long time ago but I guess it was on ebay. Made some progress with the lcd. Now it flipped 180 deg and the contrast is a little better I changed the "LCD Mapping", "column and page address" according to the datasheet. I guess this causes the 180 deg flip. The contrast gets better by changing the "bias ratio" uc1698_lcd But to be honest again, this is like landing on mars to me :/ I just use the "try and error" method and I´m just waiting for my LCD-RIP That was the reason I asked for a little help I´m already proud of myself that there are coming up some pixels on it :) PS I used the "Hello world sketch" and I think where the blanket space is should normally placed the text Grüße mcarosh

mcarosh commented 4 years ago

I´ve forgotten to mention that in your UC1611 settings are two addresses for the "LCD-Mapping" but in the datasheet and any other codes I always find only one address. I´m confused

olikraus commented 4 years ago

I´ve forgotten to mention that in your UC1611 settings are two addresses for the "LCD-Mapping" but in the datasheet and any other codes I always find only one address. I´m confused

You can not compare UC1611 and UC1698. There are a lot of differences. What exactly do you mean by LCD-Mapping? Do you refer to the UC1611 0xc0 2-byte command? The same command is a one byte commend on the UC1698. It is totally different. In fact it is a real wonder, that you see something on the screen with the UC1611 driver.

mcarosh commented 4 years ago

Yep After reading a lot I have understand the command thing by LCD-Mapping. I thought it could not be so difficult to port a similar library into Arduino. Because I found some sketches for PIC-MCUs. But if you say I am wasting my time, I think I will need to dispose this LCD. But so far I say big thx

olikraus commented 4 years ago

For sure you can build on top of an existing library like the UC1611, but still there is a lot of effort.

If you just want to complete your project, then probably get a display with a different controller (like the ST75256 for example): If you do a google image search for the ST75256 you will find a lot of other displays. In fact you could compare your LCD with the list of supported displays by this project before buying.

mcarosh commented 4 years ago

okay My point was just not to throw away this LCD, because it´s working despite the correct order of the 1s and 0s :) I would like to use it in a soldering station but there is no time limit. I own this LCD for a long time there it doesn´t matter if it will lay around for another few years. It´s just another reason to learn more about displays. So again thx a lot and if I´ll succeed I´ll let you know

olikraus commented 4 years ago

ok then, maybe I buy one of these displays and port it to u8g2. But indeed it may take time...

mcarosh commented 4 years ago

Oh thanks, but no need to buy an extra LCD, really. Maybe I came back for some question if you don´t mind. I think you have enough other problems ;) And this is my quest, despite I´m really happy for any help. Again really thanks for all your help so far

mcarosh commented 4 years ago

Even more progress was made :) lcd_uc1698

mcarosh commented 4 years ago

Hi again So for now I was only able to print "Hello World" but in no perfect way :( Maybe you can give me a little hint?! As picture shown, normal mode, 90 degree mode, 180 degree mode and mirror mode show up. But 270 degree mode shows nothing. When I set tile hight to 160 Text stands still but if I set up as normal to 20 text is scrolling in (I guess) column-direction. And pixel width or height does nothing change. My guess is that the column address is not correct OR it is really important to convert B/W data to RGB data ( I tried but absolutely without success) So if you have any idea what´s wrong maybe you can help. Here are the pictures: Normal mode: normal_mode_uc1698

90_degree_mode: 90_degree_mode_uc1698

180_degree_mode: 180_degree_mode_uc1698

MIRROR_mode: mirror_mode_uc1698

And here is the code. I build it up on your uc1610.c file (only 8080 mode):


include "u8x8.h"

static const uint8_t u8x8_d_uc1610_dogxl160_init_seq[] = {

U8X8_START_TRANSFER(), / enable chip, delay is part of the transfer start / U8X8_C(0x02b), / set power control as internal / U8X8_C(0x0eb), / set bias 1/2 /
U8X8_CA(0x081, 0x090), / set contrast / U8X8_C(0x024), /* set Temp. Compensation

/ AC0: 0: stop at boundary, 1: increment by one AC1: 0: first column then page, 1: first page, then column increment AC2: 0: increment page adr, 1: decrement page adr. / U8X8_C(0x08b), / set RAM address control, low bits AC2 AC1 AC0 /

U8X8_C(0x0ad), / set display on, UC1698 /

U8X8_END_TRANSFER(), / disable chip / U8X8_END() / end of sequence / };

static const uint8_t u8x8_d_uc1610_dogxl160_powersave0_seq[] = {

U8X8_START_TRANSFER(),
U8X8_C(0x0ad), / display on, UC1698 / U8X8_END_TRANSFER(), / disable chip / U8X8_END() / end of sequence / };

static const uint8_t u8x8_d_uc1610_dogxl160_powersave1_seq[] = { U8X8_START_TRANSFER(),
U8X8_C(0x0ae), / display off, UC1698 / U8X8_END_TRANSFER(), / disable chip / U8X8_END() / end of sequence / };

static const uint8_t u8x8_d_uc1610_dogxl160_flip0_seq[] = { U8X8_START_TRANSFER(), / enable chip, delay is part of the transfer start/

/ LC0: 0 MX: Mirror X MY: Mirror Y /
U8X8_CA(0x0c0, 0x0c6), / low bits are MY, MX, LC0 / U8X8_END_TRANSFER(), / disable chip / U8X8_END() / end of sequence / };

static const uint8_t u8x8_d_uc1610_dogxl160_flip1_seq[] = { U8X8_START_TRANSFER(), / enable chip, delay is part of the transfer start/

/ LC0: 0 MX: Mirror X MY: Mirror Y /
U8X8_CA(0x0c0, 0x0c3), / low bits are MY, MX, LC0 / U8X8_END_TRANSFER(), / disable chip / U8X8_END() / end of sequence / };

/ UC1698 has two chip select inputs (CS0 and CS1). CS0 is low active, CS1 is high active. It will depend on the display module whether the display has a is low or high active chip select.(not in my case, only CS0) /

static const u8x8_display_info_t u8x8_uc1610_display_info = { / chip_enable_level = / 0, / chip_disable_level = / 1, / post_chip_enable_wait_ns = / 15, / pre_chip_disable_wait_ns = / 15, / reset_pulse_width_ms = / 1, / post_reset_wait_ms = / 6, / sda_setup_time_ns = / 30, / sck_pulse_width_ns = / 63,
/ sck_clock_hz = / 8000000UL,
/ spi_mode = / 0, / active high, rising edge / / i2c_bus_clock_100kHz = / 4, / data_setup_time_ns = / 30, / write_pulse_width_ns = / 40, / tile_width = / 20,
/ tile_hight = / 160, / height of 138=104 pixel / / default_x_offset = / 0, / flipmode_x_offset = / 0, / pixel_width = / 160, / pixel_height = */ 160 };

static uint8_t u8x8_convert_tile_for_uc1610(uint8_t t) { uint8_t i; uint16_t r; static uint8_t buf[16]; uint8_t *pbuf = buf;

for( i = 0; i < 8; i++ ) { r = u8x8_upscale_byte(t++); pbuf++ = r & 255; r >>= 8; *pbuf++ = r; } return buf; }

uint8_t u8x8_d_uc1610_ea_dogxl160(u8x8_t u8x8, uint8_t msg, uint8_t arg_int, void arg_ptr) { uint8_t x, c, page; uint8_t *ptr; switch(msg) { case U8X8_MSG_DISPLAY_SETUP_MEMORY: u8x8_d_helper_display_setup_memory(u8x8, &u8x8_uc1610_display_info); break; case U8X8_MSG_DISPLAY_INIT: u8x8_d_helper_display_init(u8x8); u8x8_cad_SendSequence(u8x8, u8x8_d_uc1610_dogxl160_init_seq); break; case U8X8_MSG_DISPLAY_SET_POWER_SAVE: if ( arg_int == 0 ) u8x8_cad_SendSequence(u8x8, u8x8_d_uc1610_dogxl160_powersave0_seq); else u8x8_cad_SendSequence(u8x8, u8x8_d_uc1610_dogxl160_powersave1_seq); break; case U8X8_MSG_DISPLAY_SET_FLIP_MODE: if ( arg_int == 0 ) { u8x8_cad_SendSequence(u8x8, u8x8_d_uc1610_dogxl160_flip0_seq); u8x8->x_offset = u8x8->display_info->default_x_offset; } else { u8x8_cad_SendSequence(u8x8, u8x8_d_uc1610_dogxl160_flip1_seq); u8x8->x_offset = u8x8->display_info->flipmode_x_offset; } break;

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  );    /*uc1698 has range from 0 to 255 maybe*/
  u8x8_cad_EndTransfer(u8x8);
  break;

endif

case U8X8_MSG_DISPLAY_DRAW_TILE:
  u8x8_cad_StartTransfer(u8x8);

  x = ((u8x8_tile_t *)arg_ptr)->x_pos;
  x *= 8;
  x += u8x8->x_offset;

  page = (((u8x8_tile_t *)arg_ptr)->y_pos);
  page *= 2;

  u8x8_cad_SendCmd(u8x8, 0x0f4 );       /* window start column */
  u8x8_cad_SendArg(u8x8, x);
  u8x8_cad_SendCmd(u8x8, 0x0f5 );       /* window start page */
  u8x8_cad_SendArg(u8x8, page);
  u8x8_cad_SendCmd(u8x8, 0x0f6 );           /* window end column */
  u8x8_cad_SendArg(u8x8, 159);          /* end of display */
  u8x8_cad_SendCmd(u8x8, 0x0f7 );       /* window end page */
  u8x8_cad_SendArg(u8x8, page+1);
  u8x8_cad_SendCmd(u8x8, 0x0f9 );       /* Set Window Program Enable / outside Mode */

  do
  {
c = ((u8x8_tile_t *)arg_ptr)->cnt;
ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;

do
{     
  u8x8_cad_SendData(u8x8, 16, u8x8_convert_tile_for_uc1610(ptr));

  ptr += 8;
  x += 8;
  c--;
} while( c > 0 );

arg_int--;
  } while( arg_int > 0 );

  u8x8_cad_EndTransfer(u8x8);

  break;
default:
  return 0;

} return 1; }


Hope this is okay for you that I also put in the code here???

So far regards mcarosh

olikraus commented 4 years ago

I am happy if you put the code and progress here.

To increase readability, you could use proper code tags: https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code

I think the biggest remaining problem is the u8x8_convert_tile_for_uc1610(ptr) procedure. You need to convert the internal u8g2 monochrome pixel spec go the format of the UC1698.

The u8g2 buffer format is described here: https://github.com/olikraus/u8g2/wiki/u8g2reference#direct-access-buffer-api

The description of the buffer format for the UC1698 in page 46-48 is very incomplete. I assume a lot of testing is required to understand how the data needs to be reformated to fit to the target buffer.

mcarosh commented 4 years ago

Ok I think it´s really important to convert Buffer Data when read out because according to Datasheet UC1698u convert input RAM data to 16-bit of RGB data. And each 16-bit of RGB data takes 2 RAM read cycles for 8–bit bus mode. But now I really don´t know how to convert it.


static uint8_t u8x8_convert_tile_for_uc1610(uint8_t t) { uint8_t i; uint16_t r; static uint8_t buf[16]; uint8_t *pbuf = buf;

for( i = 0; i < 8; i++ ) { r = u8x8_upscale_byte(t++); pbuf++ = r & 255; r >>= 8; *pbuf++ = r; } return buf; }


Is this the correct part of code to convert? respectively the "buf" variable? And sorry for annoying you Regards

olikraus commented 4 years ago

Yes, the target display will require 16 bit for one pixel. You have to take one bit of the u8g2 buffer and then 2x 255 for a 1-bit and 2x 0 for a zero bit.

There is no predefined procedure to do this.

Is this the correct part of code to convert? respectively the "buf" variable?

This procedure is for the UC1610 (which has a complete different display architecture compared to the UC1698). I just wanted to say, you need a similar conversion procedure.And even more: You need to modify the calling procedure a lot. And: We do not know how the target memory structure should be.

I really have to say, I am impressed by your power and tenacity to solve this problem. As I said before, it personally put me to my limits...

Anyhow, having support for UC1698 based limits would be great. To my knowledge there is no open source graphics lib, which supports this controller.

mcarosh commented 4 years ago

Ha, it´s me again I´ve still did a little research and have some news. ;) First we need only 4Bit per pixel (in 4K-color mode) In the data sheet the 16 bit are only between LCD-controller and LCD-display. This affects not the MCU. Data-sheet documentation is a little confusing. I´ve also found code for converting 1 byte to Diplayformat but it´s written in C. Therefore I really don´t know which variable to tweak Maybe "static uint8_t u8x8_convert_tile_for_uc1610(uint8_t t)"???

Here the code for converting (in C)


// turns 1byte B/W data to Displayformat // procedure DispBW2RGB( temp : byte); var temp1,temp2,temp3,temp4,temp5,temp6,temp7,temp8 : byte; h11,h12,h13,h14,h15,h16,h17,h18,d1,d2,d3,d4 : byte;

begin temp1:=temp AND $80; temp2:=( temp AND $40) SHR 3; // >>3; temp3:=( temp AND $20) SHL 2; // <<2; temp4:=( temp AND $10) SHR 1; // >>1; temp5:=( temp AND $08) SHL 4; // <<4; temp6:=( temp AND $04) SHL 1; // <<1; temp7:=( temp AND $02) SHL 6; // <<6; temp8:=( temp AND $01) SHL 3; // <<3;

h11:=temp1 OR (temp1 SHR 1) OR (temp1 SHR 2) OR (temp1 SHR 3);
h12:=temp2 OR (temp2 SHR 1) OR (temp2 SHR 2) OR (temp2 SHR 3);
h13:=temp3 OR (temp3 SHR 1) OR (temp3 SHR 2) OR (temp3 SHR 3);
h14:=temp4 OR (temp4 SHR 1) OR (temp4 SHR 2) OR (temp4 SHR 3);
h15:=temp5 OR (temp5 SHR 1) OR (temp5 SHR 2) OR (temp5 SHR 3);
h16:=temp6 OR (temp6 SHR 1) OR (temp6 SHR 2) OR (temp6 SHR 3);
h17:=temp7 OR (temp7 SHR 1) OR (temp7 SHR 2) OR (temp7 SHR 3);
h18:=temp8 OR (temp8 SHR 1) OR (temp8 SHR 2) OR (temp8 SHR 3);

d1:= h11 OR h12; d2:= h13 OR h14;
d3:= h15 OR h16; d4:= h17 OR h18;
          // Schreibe aufbereitete Daten an Display
WriteLCD(d1,true); WriteLCD(d2,true);
WriteLCD(d3,true); WriteLCD(d4,true);

end DispBW2RGB;


What do you say about my tenacity ;) Do you think it´ll pay off Best wishes

olikraus commented 4 years ago

Impressive

First we need only 4Bit per pixel (in 4K-color mode)

What is the UC1698 command for this?

mcarosh commented 4 years ago

Do you mean the 4K color mode? 0x0d5 The conversion is needed because of RRRR-GGGG-BBBB

olikraus commented 4 years ago

First we need only 4Bit per pixel (in 4K-color mode)

hmm... but this means actually 4 bit per color, which is 15 bit per black/white pixel, correct?

mcarosh commented 4 years ago

Oh sorry This was also misleading on my side If we are in 4K color mode we can directly send a 4bpp command to the controller. The controller only convert, or better stores, the data as 444RGB-data in its own RAM. If you can give me a hint which part I need to convert to get a 4Bit command I´ll try. But so far there are too much variables to me :/

mcarosh commented 4 years ago

This was the file which made me hope UC1698U-appnote.pdf

mcarosh commented 4 years ago

And again my fault :/ Of course the 4bpp needed to be converted to the display format but this part of code we have now, right?

olikraus commented 4 years ago

Of course the 4bpp needed to be converted to the display format but this part of code we have now, right?

I am still confused. No, there is no such code.

On u8g2 side, we have either a set or not-set pixel: 1 Bit. On UC1698 we have a kind of an unknown format. I personally do not have a working UC1698 display here and I also do not really understand the datasheet, so I can not figure out the target data format. So the first step for you is to figure out the data format. Second step is to write a conversion procedure.

Lets assume the UC1698 requires 16 bit per pixel: So 0x0000 is black and 0xffff is white. Then we can do this if ( u8g2-pixel-is-not-set ) sent 2x 0 else sent 2x 255

If so, the conversion would be simple. However, as I mentioned, I do not know the target format and as a result, I do not know who the conversion procedure will look like.

With all this discussions: You should be aware, that your display will be super slow, because you need to transfer 16x more data than required (unless you find a more quicker mode). For example a display with the ST75256 whould be much faster (ok, I mentioned this before)

mcarosh commented 4 years ago

Hi again And I am sorry for confusing you If we are in 4K-color mode the target format is in fact just 4bpp. So one byte with 1bpp (1byte then 8pixels) needs to be converted to 4 bytes a 4bpp

Just for example to keep it clear:

If I have one byte 0xEA / 234 / binär 11101010

I then need to convert it to 4 bytes a

1111 1111
1111 0000
1111 0000
1111 0000

This was the reason I wrote we have already the conversion-code I don´t know if there is a more easy solution to send one bit four times because we only need 1 or 0 for B/W. I had some little help to find out these information. He uses the display with an XMEGA and in SPI-mode and in his code he uses the conversion. He says the display works absolutely fluently. I hope this now was more a clarifying than a confusion :) Maybe you can give me a hint where to put conversion code in your library and I´ll try. for now best wishes and a nice weekend ;)

olikraus commented 4 years ago

Ah ok... Unfortunately I do not have time to work on this...

mcarosh commented 4 years ago

As I said already I will try it myself but maybe you can give me a little hint where to put the conversion code in your code??? My guess, as I am on modifying the uc1610 code, is the "u8x8_convert_tile_for_uc1610" part?! But I´m not sure because this is only the tile and not the "send Byte" So if it makes not too much circumstances I would be happy about a little starting point :) So far best wishes

olikraus commented 4 years ago

hmm... I guess I somehow missed to answer this :-( Is further help from my side required?

nicgon commented 4 years ago

I currently have a JHDLCD 240X128 Driver uc1698u display. I'm working in it. I have found code files to make it work but I am not an expert programmer. I have always used armed libraries for arduino. Can I share these files with you? I have direct contact with JHDLCD Factory.