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

GU128x64-800B Support #1604

Closed
Bankst opened this issue Oct 2, 2021 · 64 comments
Closed

GU128x64-800B Support #1604

Bankst opened this issue Oct 2, 2021 · 64 comments
Milestone

Comments

@Bankst
Copy link
Contributor

Bankst commented Oct 2, 2021

Hello, there is an existing Adafruit_GFX based implementation to drive this display, but I would like to use u8g2.

I began digging through u8g2 to see if I could port it myself but unfortunately quickly got lost.
Some support on porting this display would be greatly appreciated.
Here is the datasheet.

@Bankst
Copy link
Contributor Author

Bankst commented Oct 2, 2021

What I was able to get started was the display info, based on this section of the datasheet.
image

static const u8x8_display_info_t u8x8_d_gu800_128x64_display_info =
{
  /* chip_enable_level = */ 0,      /* GU800: Not used */
  /* chip_disable_level = */ 1,     /* GU800: Not used */
  
  /* post_chip_enable_wait_ns = */ 40,
  /* pre_chip_disable_wait_ns = */ 150,
  /* reset_pulse_width_ms = */ 1,   /* GU800: Unspecified in datasheet */
  /* post_reset_wait_ms = */ 2,     /* GU800: Min 1.5ms per datasheet */
  /* sda_setup_time_ns = */ 12,     /* GU800: Not used */
  /* sck_pulse_width_ns = */ 80,    /* GU800: Min 80ns per datasheet */
  /* sck_clock_hz = */ 4000000UL,
  /* spi_mode = */ 0,               /* active high, rising edge */
  /* i2c_bus_clock_100kHz = */ 4,   /* GU800: Not used */
  /* data_setup_time_ns = */ 40,    /* GU800: Min 40ns per datasheet */
  /* write_pulse_width_ns = */ 150, /* GU800: Min 150ns per datasheet */
  /* tile_width = */ 16,            /* width of 16*8=128 pixel */
  /* tile_hight = */ 8,
  /* default_x_offset = */ 0,
  /* flipmode_x_offset = */ 0,
  /* pixel_width = */ 128,
  /* pixel_height = */ 64
};

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

Nice display, but seems to be very expensive. Indeed there is no support for such device in u8g2 (I came across such a VFD device before but it is too expensive for a open source project like u8g2), but I you are willing to do some testing we can try to implement support for your display.

After review of the datasheet: We need to implement this as a 64x128 device. The memory structure seems to imply this. This means, that we need to drive the display with U8G2_R1 (https://github.com/olikraus/u8g2/wiki/u8g2reference#setdisplayrotation) to get landscape mode.

I will go ahead with the implementation...

Edit: I am confused with the GU800 RAM structure, Not sure whether landscape will be U8G2_R0 or U8G2_R1.. we need to test this.

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

Technical question: The GU128x64 seems to consume 700mA. This is more than the Arduino can provide, right? So an external power supply is require, correct?

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

static const u8x8_display_info_t u8x8_d_gu800_128x64_display_info =
{
  /* chip_enable_level = */ 0,      /* GU800: CSS signal */
  /* chip_disable_level = */ 1,     /* GU800: CSS signal */
  
  /* post_chip_enable_wait_ns = */ 40,
  /* pre_chip_disable_wait_ns = */ 150,
  /* reset_pulse_width_ms = */ 2,   /* GU800: Unspecified in datasheet */
  /* post_reset_wait_ms = */ 2,     /* GU800: Min 1.5ms per datasheet */
  /* sda_setup_time_ns = */ 40,     /* GU800: 40ns according to the timing diagram */
  /* sck_pulse_width_ns = */ 80,    /* GU800: Min 80ns per datasheet */
  /* sck_clock_hz = */ 4000000UL,
  /* spi_mode = */ 0,               /* active high, rising edge */
  /* i2c_bus_clock_100kHz = */ 4,   /* GU800: Not used */
  /* data_setup_time_ns = */ 40,    /* GU800: Min 40ns per datasheet */
  /* write_pulse_width_ns = */ 150, /* GU800: Min 150ns per datasheet */
  /* tile_width = */ 16,            /* width of 16*8=128 pixel */
  /* tile_hight = */ 8,
  /* default_x_offset = */ 0,
  /* flipmode_x_offset = */ 0,
  /* pixel_width = */ 128,
  /* pixel_height = */ 64
};

olikraus added a commit that referenced this issue Oct 3, 2021
olikraus added a commit that referenced this issue Oct 3, 2021
olikraus added a commit that referenced this issue Oct 3, 2021
olikraus added a commit that referenced this issue Oct 3, 2021
olikraus added a commit that referenced this issue Oct 3, 2021
@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

I have created alle the constructors, for example:

U8G2_GU800_128X64_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
U8G2_GU800_128X64_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

I have created beta release 2.32.3.
Can you test the same?

You can download the latest U8g2 beta release from here: https://github.com/olikraus/U8g2_Arduino/archive/master.zip

  1. Remove the existing U8g2_Arduino library (https://stackoverflow.com/questions/16752806/how-do-i-remove-a-library-from-the-arduino-environment)
  2. Install the U8g2_Arduino Zip file via Arduino IDE, add zip library menu (https://www.arduino.cc/en/Guide/Libraries).

@Bankst
Copy link
Contributor Author

Bankst commented Oct 3, 2021

Technical question: The GU128x64 seems to consume 700mA. This is more than the Arduino can provide, right? So an external power supply is require, correct?

Yes, that is correct. I use a large 5V powerbank for my testing.

I have created beta release 2.32.3. Can you test the same?

You can download the latest U8g2 beta release from here: https://github.com/olikraus/U8g2_Arduino/archive/master.zip

1. Remove the existing U8g2_Arduino library (https://stackoverflow.com/questions/16752806/how-do-i-remove-a-library-from-the-arduino-environment)

2. Install the U8g2_Arduino Zip file via Arduino IDE, add zip library menu (https://www.arduino.cc/en/Guide/Libraries).

I'll give this a go now and report back. Thank you.

@Bankst
Copy link
Contributor Author

Bankst commented Oct 3, 2021

I've tested both the full buffer and page buffer u8g2 logo examples, and get nothing on the screen. I tested my code using the library I mentioned in the original post, and confirm it still works.

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

Which constructor did you use? Did you apply the correct pin values? Maybe you can share your test code.

@olikraus olikraus added this to the 2.32 milestone Oct 3, 2021
@Bankst
Copy link
Contributor Author

Bankst commented Oct 3, 2021

I'm using this constructor.

U8G2_GU800_128X64_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);

Here is my code repo that I have driven the display with successfully. It uses the exact same pins for CS, DC, and Reset.
https://github.com/Bankst/GU800_VFD_GL/blob/master/src/GU800/GU800_GFX.cpp

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

Are you able to see any kind of activity on CS or DC line? The reset should be driven high by u8g2.
Can you see any other kind of activity on the screen?

@Bankst
Copy link
Contributor Author

Bankst commented Oct 3, 2021

There is no screen activity. I will connect my logic analyzer and see what it shows.

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

I will connect my logic analyzer and see what it shows.

logic analyzer, nice.

If you see activity, we probably need to check the init sequence for the display. It is here:

u8g2/csrc/u8x8_d_gu800.c

Lines 143 to 172 in 438906e

static const uint8_t u8x8_d_gu800_128x64_init_seq[] = {
U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
U8X8_C(0x05f), /* clear all RAM, clear address counters */
U8X8_DLY(1), /* delay for 1 ms (see datasheet) */
/* configure all area as graphics RAM */
U8X8_CA(0x62,0), U8X8_D1(0xff),
U8X8_CA(0x62,1), U8X8_D1(0xff),
U8X8_CA(0x62,2), U8X8_D1(0xff),
U8X8_CA(0x62,3), U8X8_D1(0xff),
U8X8_CA(0x62,4), U8X8_D1(0xff),
U8X8_CA(0x62,5), U8X8_D1(0xff),
U8X8_CA(0x62,6), U8X8_D1(0xff),
U8X8_CA(0x62,7), U8X8_D1(0xff),
U8X8_CA(0x70, 0), /* horizontal shift */
U8X8_C(0xb0), /* vertical shift */
U8X8_C(0x4f), /* max brightness */
U8X8_C(0x84), /* x increment */
// U8X8_CA(0x024, 0x040) /* display on */
U8X8_END_TRANSFER(), /* disable chip */
U8X8_END() /* end of sequence */
};

@Bankst
Copy link
Contributor Author

Bankst commented Oct 3, 2021

Here is a capture with the u8g2 logo example ino, in the loop().
image

Here is a capture from my code, looping printing text to the screen.
image

Of note I probably have the SPI mode configured incorrectly in the analyzer, but all the signals are labelled correctly.

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

Hmm.. but should the reset signal be high? I mean it is low in both cases, but according to the datasheet, the reset signal must be high.
Another point is the sample frequency: U8g2 is configured to 4 MHz SPI. Not sure what 4096 samples at 8kHz means, but if the sampling frequency of your analyzer is 8KB, then the individual SPI bytes can not be detected.

@Bankst
Copy link
Contributor Author

Bankst commented Oct 3, 2021

for quick reference here are the writeSPI methods from the adafruit-gfx based library.

size_t GU800::writeSPI(uint8_t data, bool isCommand) {
    *csport &= ~cspinmask;              // Assert /CS
    
    if (isCommand) {
        *dcport |= dcpinmask;           // Write command: DC high
    } else {
        *dcport &= ~dcpinmask;          // Write data: DC low
    }

    delayMicroseconds(1);               // Minimum 40nS between asserting /CS and starting transaction

    SPI.beginTransaction(this->spi);
    SPI.transfer(data);
    SPI.endTransaction();

    delayMicroseconds(2);               // Minimum 1.5uS between last clock and deasserting /CS
    *csport |= cspinmask;
    delayMicroseconds(1);               // Minimum 80nS between deasserting /CS and next transaction

    return 1;
}

size_t GU800::writeSPI(uint8_t * buf, size_t count, bool isCommand) {
    // GU800 requires that we deassert and reassert /CS after every byte, so no
    // gain in doing batch transfers :(

    for (int i = 0; i < count; i++) {
        this->writeSPI(buf[i], isCommand);
    }

    return count;
}

@Bankst
Copy link
Contributor Author

Bankst commented Oct 3, 2021

Hmm.. but should the reset signal be high? I mean it is low in both cases, but according to the datasheet, the reset signal must be high. Another point is the sample frequency: U8g2 is configured to 4 MHz SPI. Not sure what 4096 samples at 8kHz means, but if the sampling frequency of your analyzer is 8KB, then the individual SPI bytes can not be detected.

The reset line was labelled incorrectly, my mistake. I'll relabel that now. I also increased the sample rate to 5MHz and things look more sensible. I think.
image
I really am not that familiar with SPI at this level. Or logic analyzers for that matter.

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

It might look like some signals are swapped. However there is still a sampling issue:
With 4MHz SPI you need at least 8MHz sampling frequency (twice frequency for sampling: https://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem). So you should either sample with 8MHz or reduce the SPI speed with u8g2 by using setBusClock(2000000) to assign 2MHz SPI clock.

@Bankst
Copy link
Contributor Author

Bankst commented Oct 3, 2021

Ok, with a 12.5MHz sample rate this makes more sense. Only thing I'm unsure of is the SPI mode.
image
image

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

U8g2 is configured for spi mode 0 (https://www.arduino.cc/en/reference/SPI)
But I think this doesn't matter much. How does the capture of the first view bytes look like with 12.5MHz?

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

I am not sure which SPI frequency is used by the Adafruit lib, however maybe the 4MHz suggested by your code is too high.
It might be worth to try setBusClock(1000000).

@Bankst
Copy link
Contributor Author

Bankst commented Oct 3, 2021

I tried 1MHz and got no display from u8g2 again. Let me capture the initial bytes again on 12.5MHz

@Bankst
Copy link
Contributor Author

Bankst commented Oct 3, 2021

Ah. The display is expecting CS to be asserted on every byte, but u8g2 is only asserting it at the end of a transaction.
image
also of note, u8g2 sends the first 0x62 very early. it is off to the far left of the screenshot.

Here is my code.
image

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

The pin assinment seems to be correct. In fact DC and select (ccs) seem to be ok (u8g2 does not unselect between each byte, but this should be ok).
I see two differences:

  • Adafruit code seems to be slower, maybe only 1MHz instead of 4MHz
  • The data line behaves differently, which seems to indicate a different SPI mode.

also of note, u8g2 sends the first 0x62 very early. it is off to the far left of the screenshot.

Please review the code from above: I first sent 0x5f, then wait for 1ms (as described in the datasheet) and then send the 0x62. It should be the same as for your code.

Let's try different SPI modes.

Please locate the following line 187 in your local u8g2 code (file u8x8_d_gu800.c):

u8g2/csrc/u8x8_d_gu800.c

Lines 186 to 187 in 61feaec

/* sck_clock_hz = */ 4000000UL,
/* spi_mode = */ 0, /* active high, rising edge */

There are four modes, from 0 to 3
Maybe also reduce SPI clock to 1000000 in line 186

@Bankst
Copy link
Contributor Author

Bankst commented Oct 3, 2021

The screen is somewhat dim, I'm not sure the brightness is being set to max. I'll see if I can figure it out.

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

wow, very nice.
So the updated cad_110 is required, right?
Could you test the following:
Currently the cad code includes this:

    case U8X8_MSG_CAD_SEND_DATA:
      u8x8_byte_SetDC(u8x8, 0);
      data = (uint8_t *)arg_ptr;
      while( arg_int > 0 )
      {
        u8x8_byte_StartTransfer(u8x8);
        u8x8_byte_SendByte(u8x8, *data);
        u8x8_byte_EndTransfer(u8x8);
        data++;
        arg_int--;
      }
      break;

Will this also work? It would be a great performance improvement...

    case U8X8_MSG_CAD_SEND_DATA:
      u8x8_byte_SetDC(u8x8, 0);
      data = (uint8_t *)arg_ptr;
      u8x8_byte_StartTransfer(u8x8);
      while( arg_int > 0 )
      {
        u8x8_byte_SendByte(u8x8, *data);
        data++;
        arg_int--;
      }
      u8x8_byte_EndTransfer(u8x8);
      break;

@Bankst
Copy link
Contributor Author

Bankst commented Oct 3, 2021

Unfortunately that does not work. :( Is there a good test I could run to evaluate performance?

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

The screen is somewhat dim, I'm not sure the brightness is being set to max. I'll see if I can figure it out.

You can use the set contrast command of u8g2, however remember to use the value 255 for max brightness. You display has brightness levels from 0 to 15, however u8g2 uses 0..255: The value in u8g2 will be divided by 16 to get the GU800 value.

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

Unfortunately that does not work. :(

too bad

Is there a good test I could run to evaluate performance?

There is the FPS.ino example, which also includes some reference values of other displays.

@Bankst
Copy link
Contributor Author

Bankst commented Oct 3, 2021

My device is an Arduino Mega 2560
Page mode results:

  • draw clip test, 12.3
  • clear screen, 16.0
  • draw @, 3.7
  • draw pixel, 5.7

Full buffer results:

  • draw clip test, 14.8
  • clear screen, 16.5
  • draw @, 6.1
  • draw pixel, 7.9

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

well... better than expected :-)

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

I have created a new cad_110 procedure. Also reverted some of the recent changes.

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

Created beta 2.32.6
Does this still work?

You can download the latest U8g2 beta release from here: https://github.com/olikraus/U8g2_Arduino/archive/master.zip

  1. Remove the existing U8g2_Arduino library (https://stackoverflow.com/questions/16752806/how-do-i-remove-a-library-from-the-arduino-environment)
  2. Install the U8g2_Arduino Zip file via Arduino IDE, add zip library menu (https://www.arduino.cc/en/Guide/Libraries).

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

Did you solve the "dim" brightness issue?

@olikraus
Copy link
Owner

olikraus commented Oct 3, 2021

Thanks for testing and working with me on this topic. I am happy to have VFD support inside u8g2 :-)

@Bankst
Copy link
Contributor Author

Bankst commented Oct 3, 2021

Did you solve the "dim" brightness issue?

I'll be looking in to that soon. I'll give the 2.32.6 beta a test now.

@Bankst
Copy link
Contributor Author

Bankst commented Oct 3, 2021

2.32.6 results in all pixels being On. I cannot make out whether there is anything actually happening on the screen.

@Bankst
Copy link
Contributor Author

Bankst commented Oct 3, 2021

Ah, simple fix. the SPI mode must be 2, not 0.

/* spi_mode = */ 0, /* active high, rising edge */

After changing this to 2, all is well again.
Thanks so much for working with me on this. I'm also happy to have VFD support in u8g2!

@Bankst
Copy link
Contributor Author

Bankst commented Oct 3, 2021

I just PR'd the SPI mode fix and some other cleanups. A bunch of unnecessary start/end transfers were still there. I have confirmed that the display works fine with these changes. All that is left is brightness control.

@olikraus
Copy link
Owner

olikraus commented Oct 4, 2021

After changing this to 2, all is well again.

puh, guess it was too late for me to remember all the changes :-)
Thanks for the PR

@olikraus
Copy link
Owner

olikraus commented Jan 7, 2022

ok, i assme this can be closed...

@WuSiYu
Copy link

WuSiYu commented Oct 25, 2024

@olikraus
This lib works fine on a Arduino UNO with this display. But when I switched to a esp32s3 (with a 3.3v to 5v I/O converter chip), it's not work anymore (no display), until I changed the SPI mode from 2 to 3, it works again.

(FYI: On esp32s3 I'm using U8G2_GU800_128X64_F_4W_HW_SPI with u8x8_SetPin(u8g2.getU8x8(), U8X8_PIN_SPI_XXX, xx); to set a custom SPI pin)

@WuSiYu
Copy link

WuSiYu commented Oct 26, 2024

I checked the screen's datasheet, according to the fig I think spi mode 3 is the correct one:

图片

Later I will test spi mode 3 on an Arduino UNO as well.

@olikraus
Copy link
Owner

olikraus commented Oct 29, 2024

Hmm.. there had been similar issues in history, where the SPI modes had not been compatible. See for example here: #53
Maybe ESP32 has a similar problem.

My bug report to ESP8266: esp8266/Arduino#2416

@WuSiYu
Copy link

WuSiYu commented Nov 12, 2024

@olikraus sorry for late response, I missed the notifacation
I found that spi mode = 3 also works on Arduino UNO, and according to the datasheet, I think mode 3 is correct. And mode 2 is wrong, which just works on UNO coincidentally.
Shall I open a PR to fix this?

@olikraus
Copy link
Owner

If mode 3 works with Arduino Uno, then mode 3 is correct and ESP is wrong because I assume, that Arduino Framework is the reference.

Shall I open a PR to fix this?

It would be better to address this to ESP framework...

@WuSiYu
Copy link

WuSiYu commented Nov 12, 2024

@olikraus
Sorry, I may not express it clearly. The current situation is:

  • According to the datasheet of the screen, I think it should be: spi mode3
  • While the configuration in u8g2: spi mode2
  • On Arduino UNO: spi mode2 works, spi mode3 works
  • On esp32: spi mode2 does not work, spi mode3 works
  • The thing I want to PR: change the config in u8g2 from spi mode2 to spi mode3, then the screen should works fine on both platform

(this line:)

/* spi_mode = */ 2, /* active high, rising edge */

Also I found #1970, I think this is similar to that.

@olikraus
Copy link
Owner

Ok, fine, then I would accept the PR

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

3 participants