olikraus / u8g2

U8glib library for monochrome displays, version 2
Other
4.93k stars 1.03k forks source link

Is there any way to boost u8g2 speed even more ? #1121

Closed ramenia closed 4 years ago

ramenia commented 4 years ago

Hi,

I am using STM32L152 and have enough ram to does not care memory usage. I couldn't dig the code enough yet but it is like the library sends buffer divided. I am using u8g2_Setup_ssd1327_i2c_midas_128x128_f

Thank you.

olikraus commented 4 years ago

It looks like you use the high level u8g2 procedures with custom procedures for your hardware. However, speed will be influenced mostly on these hardware related procedures. Without knowing these hardware procedures I can not say whether speed improvements are possible.

Which gpio / byte level callback do you use?

ramenia commented 4 years ago

I am not sure if i understand you correctly but this is my data transmit functions.

`void i2cScrWrite(uint8_t *writeBuff, uint16_t writeBuffSize)
{
    HAL_I2C_Master_Transmit(&I2c.I2c, I2C_ADDRESS << 1, writeBuff, writeBuffSize, 2000);
}

uint8_t u8x8_byte_stm32l151_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
  static uint8_t buffer[32];        /* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */
  static uint8_t buf_idx;
  uint8_t *data;

  switch(msg)
  {
    case U8X8_MSG_BYTE_SEND:
      data = (uint8_t *)arg_ptr;
      while( arg_int > 0 )
      {
          buffer[buf_idx++] = *data;
          data++;
          arg_int--;
      }
      break;
    case U8X8_MSG_BYTE_INIT:
      /* add your custom code to init i2c subsystem */
      break;
    case U8X8_MSG_BYTE_SET_DC:
      /* ignored for i2c */
      break;
    case U8X8_MSG_BYTE_START_TRANSFER:
      buf_idx = 0;
      break;
    case U8X8_MSG_BYTE_END_TRANSFER:
        i2cScrWrite(buffer, buf_idx);
      break;
    default:
      return 0;
  }
  return 1;
}

uint8_t stm32l1_gpio_and_delay_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
      switch (msg)
      {
      case U8X8_MSG_GPIO_AND_DELAY_INIT:
        break;
      case U8X8_MSG_DELAY_MILLI:
        break;
      case U8X8_MSG_DELAY_I2C:
        break;
      case U8X8_MSG_GPIO_DC:
        break;
      case U8X8_MSG_GPIO_RESET:
        break;
      }
      return 1;
}`
olikraus commented 4 years ago

Looks good. You do use HW I2C. Maybe you can increase speed for your HW I2C until the display stops working.

If you still feel, that your code is slow, maybe there is some issue in using U8g2. Can you share some u8g2 code which you feel is slow?

ramenia commented 4 years ago

Hmm, maybe this is the limit of ssd1327 because when i run this code, words begin to appear from top to bottom. I am trying to make them all appear at the same time. For example this code:

   u8g2_SetFont(&u8g2, u8g2_font_ncenB14_tr);
   u8g2_DrawStr(&u8g2, 0, 20, "Hello World!");
   u8g2_DrawStr(&u8g2, 0, 60, "Hello World!");
   u8g2_DrawStr(&u8g2, 0, 100, "Hello World!");
   u8g2_SendBuffer(&u8g2);
ramenia commented 4 years ago

https://youtu.be/6Bi6LpvQG4w

olikraus commented 4 years ago

Hm... but to me it looks like "HAL_I2C_Master_Transmit" might be too slow. But in general the SSD1327 is also very slow. It actually is 4-bit graylevel controller. U8g2 only supports black and white, but still has to transmit either 0b0000 or 0b1111, which means, that there amount of data is 4 times higher compared to a true monochrome display.

For example the new grove display V2 includes a different controller than the SSD1327, which is much faster: https://www.seeedstudio.com/Grove-OLED-Display-1-12-V2.html

So one main reason for the poor speed is the display itself.

ramenia commented 4 years ago

Thank you very much for your quick responses. I just want to ask one more question. Why words begin to appear from top to bottom is it because of the u8g2 or screen ?

olikraus commented 4 years ago

Well, the transfer has to start somewhere, which is the upper left corner in case of U8g2. The screen is organized in pages, where each page has the height of 8 pixel ( see the SSD1327 datasheet). So u8g2 indeed starts with the first page. That means, the top 8 rows get transfered first. Within one page the data is transfered from left to right (like a progress bar with 8 pixel height).

ramenia commented 4 years ago

Hi again, sorry to bother you again :) i have made a basic calculation which is my i2c speed is 400kHz. My screen is 128x128 also 4bit so 1281284 = 65536 / 400.000 = 0.163 second should be the time i need to send full screen buffer but i have made all the suggested changes for speed boost but still 0.435 second the best i got.

And there is a line in the code as / u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER / I can send much more bytes at the same time, why limit ?

olikraus commented 4 years ago

And there is a line in the code as / u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER / I can send much more bytes at the same time, why limit ?

bigger data is internally split into smaller pieces.

my i2c speed is 400kHz.

Are you sure? Similar display with this controller did not support 400kHz.

but still 0.435 second the best i got.

Three points:

  1. The picture has to be rendered and then transfered. Rendering the picture obviously takes time. I mean there is no continues data stream. Or did you measure the SendBuffer command only?
  2. There are a several extra data required per row. I mean, there is an overhead required to tell where exactly which data should appear on the display.
  3. During the transmission, the data has to be converted from one bit/pixel to 4 bit per pixel. This also takes a lot of time.
ramenia commented 4 years ago
olikraus commented 4 years ago

Is there a way to convert data from one bit/pixel to 4 bit per pixel before sendbuffer ?

Maybe, but will it help? U8g2 is a monochrome graphics lib, so somewhere you have to convert the data. Code is here: https://github.com/olikraus/u8g2/blob/21f5a74dff0d658a49d407fc5cd46ebdeea464f8/csrc/u8x8_d_ssd1327.c#L97-L125

ramenia commented 4 years ago

Actually i want to make all preparations before "sendBuffer" and with sendBuffer i want to send everything those i want to see on the display with one and only buffer for once if ssd1327 can work like this. Can it ? or at least use bigger buffers not 32 byte maximum.

olikraus commented 4 years ago

Actually i want to make all preparations before "sendBuffer"

Then you need to write your own graphics lib (or extend u8g2 a lot).

The focus of u8g2 is to make monochrome displays work. I mean focus is on functionality, goal is to support as many displays as possible. It is not like this, that I didn't care about speed (the opposite is true: I spent a lot on speed optimization), but I never sacrificed the u8g2 software architection for speed optimization of a special display with a very special internal memory architecture.

The point is this: Each display might have a different internal memory architecture to represent the graphics buffer.

On the other side, I have to decide for one specific memory architecture to do the u8g2 graphics functions. It is like this:

Graphics Functions --> U8g2 Graphics Memory --> Display Specific Transformation --> Display Graphics Memory.

In order to have a universal library which fits to (hopefully) all displays, there must be a transformation function to simplify the complexity of the tool. What you request is this:

Graphics Functions --> display specific drawing procedures --> display specific graphics memory --> Display Graphics Memory.

But this request is a complete different library.