olikraus / u8g2

U8glib library for monochrome displays, version 2
Other
5.17k stars 1.05k forks source link

NHD-C12864B2Z-RN-FBW support #2498

Open FabianOlczakk opened 2 months ago

FabianOlczakk commented 2 months ago

I have a NHD-C12864B2Z-RN-FBW screen, which uses the ST7565R controller and works only using the 8080 interface. I tried using the U8G2_ST7565_NHD_C12864_1_8080 constructor but without success. After writing and uploading my own initialization code for the screen, I noticed that the screen's RAM contained data from the Hello World example that I had previously run. So I went back to the Hello World example code, added my own screen initialization, and now everything works.

Modified Hello World example:

#include <Arduino.h>
#include <U8g2lib.h>

#define D0 14
#define D1 27
#define D2 26
#define D3 25
#define D4 33
#define D5 32
#define D6 13
#define D7 5
#define WRITE 16
#define READ 17
#define A0 4
#define RESET 0
#define CS 2

U8G2_ST7565_NHD_C12864_1_8080 u8g2(U8G2_R0, D0, D1, D2, D3, D4, D5, D6, D7, WRITE, CS, A0, RESET);

void setup(void) {
  u8g2.begin();
  pinMode(READ, OUTPUT);
  digitalWrite(READ, HIGH);
  initScreen();
}

void loop(void) {
  u8g2.firstPage();
  do {
    u8g2.setFont(u8g2_font_ncenB14_tr);
    u8g2.drawStr(0,20,"Hello World!");
  } while ( u8g2.nextPage() );
  delay(1000);
}

void initScreen() {
  digitalWrite(READ, HIGH);
  digitalWrite(WRITE, HIGH);
  digitalWrite(CS, LOW);
  digitalWrite(RESET, LOW);
  delay(150);
  digitalWrite(RESET, HIGH);
  delay(150);

  sendCommand(0x0a2); // LCD bias set to 1/9
  sendCommand(0x0a0); // ADC set to reverse
  sendCommand(0x0c8); // COM set to reverse
  sendCommand(0x025); // resistor ratio set to large
  sendCommand(0x081); // electronic volume set (contrast)
  sendCommand(0x010); // electronic volume set
  sendCommand(0x02f); // operating mode - all power control circuits on
  sendCommand(0x0f8); // set booster ratio
  sendCommand(0x000); // booster ratio to 4x
  sendCommand(0x040); // start line set to 0
  sendCommand(0x0af); // display on

  delay(10);
}

void sendCommand(uint8_t command) {
  digitalWrite(CS, LOW);
  digitalWrite(A0, LOW);
  digitalWrite(WRITE, LOW);
  const int dataPins[8] = {D7, D6, D5, D4, D3, D2, D1, D0};
  for(int i = 0; i < 8; i++) {
    digitalWrite(dataPins[i], (command >> (7 - i)) & 0x01);
  }
  digitalWrite(WRITE, HIGH);
  digitalWrite(CS, HIGH);
  delay(10);
}

After this, I added my own constructor for this screen with the same initialization as in the example above, intending to add it to this repository later, but it didn't work. The screen only starts when I use the modified Hello World example.

Screen: [link] Screen documentation: [link] ST7565R documentation: [link]

Code I added to the library to add this screen (This is a copy of the code responsible for U8G2_ST7565_NHD_C12864_1_8080 with modified initialization to match the one I wrote.):

U8g2lib.h

class U8G2_ST7565R_NHD_C12864_B2Z_RN_FBW_1_8080 : public U8G2 {
  public: U8G2_ST7565R_NHD_C12864_B2Z_RN_FBW_1_8080(const u8g2_cb_t *rotation, uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7, uint8_t enable, uint8_t cs, uint8_t dc, uint8_t reset = U8X8_PIN_NONE) : U8G2() {
    u8g2_Setup_st7565R_nhd_c12864_b2z_rn_fbw_1(&u8g2, rotation, u8x8_byte_arduino_8bit_8080mode, u8x8_gpio_and_delay_arduino);
    u8x8_SetPin_8Bit_8080(getU8x8(), d0, d1, d2, d3, d4, d5, d6, d7, enable, cs, dc, reset);
  }
};

u8g2.h

void u8g2_Setup_st7565R_nhd_c12864_b2z_rn_fbw_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);

u8g2_d_setup.c

void u8g2_Setup_st7565R_nhd_c12864_b2z_rn_fbw_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)
{
  uint8_t tile_buf_height;
  uint8_t *buf;
  u8g2_SetupDisplay(u8g2, u8x8_d_st7565R_nhd_c12864_b2z_rn_fbw, u8x8_cad_001, byte_cb, gpio_and_delay_cb);
  buf = u8g2_m_16_8_1(&tile_buf_height);
  u8g2_SetupBuffer(u8g2, buf, tile_buf_height, u8g2_ll_hvline_vertical_top_lsb, rotation);
}

u8x8.h

uint8_t u8x8_d_st7565R_nhd_c12864_b2z_rn_fbw(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);

u8x8_d_st7565.c

/*================================================*/
/* NHD-C12864B2Z-RN-FBW */

static const u8x8_display_info_t u8x8_st7565R_nhd_c12864_b2z_rn_fbw_display_info =
{
  /* chip_enable_level = */ 0,
  /* chip_disable_level = */ 1,

  /* This screen only supports 8080 interface, so SPI and I2C info is not required */ 
  /* post_chip_enable_wait_ns = */ 0,
  /* pre_chip_disable_wait_ns = */ 0,
  /* reset_pulse_width_ms = */ 0, 
  /* post_reset_wait_ms = */ 0, 
  /* sda_setup_time_ns = */ 0,
  /* sck_pulse_width_ns = */ 0,
  /* sck_clock_hz = */ 0,
  /* spi_mode = */ 0,
  /* i2c_bus_clock_100kHz = */ 0,

  /* == 8 bit interface info == */
  /* data_setup_time_ns = */ 40,    /* st7565R datasheet, table 24, tds8 */
  /* write_pulse_width_ns = */ 80,  /* st7565R datasheet, table 24, tcclw */
  /* tile_width = */ 16,            /* width of 16*8=128 pixel */
  /* tile_height = */ 8,
  /* default_x_offset = */ 4,
  /* flipmode_x_offset = */ 0,
  /* pixel_width = */ 128,
  /* pixel_height = */ 64
};

static const uint8_t u8x8_d_st7565R_nhd_c12864_b2z_rn_fbw_init_seq[] = {

  U8X8_START_TRANSFER(),    /* enable chip, delay is part of the transfer start */

  /* st7565R datasheet, table 16 */
  U8X8_C(0x0a2),            /* LCD bias set to 1/9 */
  U8X8_C(0x0a0),            /* ADC set to reverse */
  U8X8_C(0x0c8),            /* COM set to reverse */
  U8X8_C(0x025),            /* resistor ratio set to large */
  U8X8_CA(0x081, 0x010),    /* electronic volume mode set (contrast, test 10) */
  U8X8_C(0x02f),            /* operating mode - all power control circuits on */
  U8X8_CA(0x0f8, 0x000),    /* set booster ratio to 4x */
  U8X8_C(0x040),            /* start line set to 0 */
  U8X8_C(0x0af),            /* display on */

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

uint8_t u8x8_d_st7565R_nhd_c12864_b2z_rn_fbw(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
  /* call common procedure first and handle messages there */
  if ( u8x8_d_st7565_common(u8x8, msg, arg_int, arg_ptr) == 0 )
  {
    /* msg not handled, then try here */
    switch(msg)
    {
      case U8X8_MSG_DISPLAY_SETUP_MEMORY:
  u8x8_d_helper_display_setup_memory(u8x8, &u8x8_st7565R_nhd_c12864_b2z_rn_fbw_display_info);
  break;
      case U8X8_MSG_DISPLAY_INIT:
  u8x8_d_helper_display_init(u8x8);
  u8x8_cad_SendSequence(u8x8, u8x8_d_st7565R_nhd_c12864_b2z_rn_fbw_init_seq);
  break;
      case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
  if ( arg_int == 0 )
  {
    u8x8_cad_SendSequence(u8x8, u8x8_d_st7565_flip0_seq);
    u8x8->x_offset = u8x8->display_info->default_x_offset;
  }
  else
  {
    u8x8_cad_SendSequence(u8x8, u8x8_d_st7565_flip1_seq);
    u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
  } 
  break;
      default:
  return 0;   /* msg unknown */
    }
  }
  return 1;
}