From 9385d04650bc6b82fc9265c587f0ff9f5f73e463 Mon Sep 17 00:00:00 2001 From: Nick Gagin Date: Sat, 8 Aug 2026 00:45:27 +0300 Subject: [PATCH] mt12864k: implement contrast control via INF8574A register (4 levels) --- csrc/u8x8_d_mt12864k.c | 44 +++++++++++++++++++++++++++---------- sys/sdl/mt12864k_i2c/main.c | 23 +++++++++++++++++-- 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/csrc/u8x8_d_mt12864k.c b/csrc/u8x8_d_mt12864k.c index 6c21762c..4678edef 100644 --- a/csrc/u8x8_d_mt12864k.c +++ b/csrc/u8x8_d_mt12864k.c @@ -102,22 +102,28 @@ static void u8x8_mt12864k_select(u8x8_t *u8x8, uint8_t adr) u8x8->i2c_address = adr; } +/* write a single byte to the INF8574A control register (0x3B, 8-bit 0x076). + The register is an 8 bit latch: every write sets all bits, so the value + must always contain the state of all other control bits (^RST, backlight, + P_ON) as well. */ +static void u8x8_mt12864k_write_register(u8x8_t *u8x8, uint8_t value) +{ + u8x8_mt12864k_select(u8x8, U8X8_MT12864K_REG_ADR); + u8x8_byte_StartTransfer(u8x8); + u8x8_byte_SendByte(u8x8, value); + u8x8_byte_EndTransfer(u8x8); +} + /* reset both LCD controllers through the INF8574A control register */ static void u8x8_mt12864k_reset(u8x8_t *u8x8) { - u8x8_mt12864k_select(u8x8, U8X8_MT12864K_REG_ADR); - /* assert ^RST (bit 0 = 0), keep the other bits at their default value */ - u8x8_byte_StartTransfer(u8x8); - u8x8_byte_SendByte(u8x8, U8X8_MT12864K_REG_RESET); - u8x8_byte_EndTransfer(u8x8); + u8x8_mt12864k_write_register(u8x8, U8X8_MT12864K_REG_RESET); u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_MILLI, 1); /* release ^RST (bit 0 = 1) */ - u8x8_byte_StartTransfer(u8x8); - u8x8_byte_SendByte(u8x8, U8X8_MT12864K_REG_DEFAULT); - u8x8_byte_EndTransfer(u8x8); + u8x8_mt12864k_write_register(u8x8, U8X8_MT12864K_REG_DEFAULT); /* datasheet: 10 ms delay after ^RST goes inactive */ u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_MILLI, 10); @@ -231,9 +237,25 @@ uint8_t u8x8_d_mt12864k_128x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void /* The MT-12864K controllers can not mirror the cols and rows, use U8g2 for rotation */ // case U8X8_MSG_DISPLAY_SET_FLIP_MODE: // break; -/* The MT-12864K has no internal contrast command, contrast is controlled by the INF8574A register */ -// case U8X8_MSG_DISPLAY_SET_CONTRAST: -// break; +/* The MT-12864K has no internal contrast command. Contrast is controlled by + the INF8574A register bits 4-6. The datasheet (table 4) defines only four + discrete levels, the CT_* bits are mutually exclusive: when one of them is + "0" the other two must be "1". Bits 0-3 (^RST, backlight, P_ON) and bit 7 + stay at their default value "1". */ + case U8X8_MSG_DISPLAY_SET_CONTRAST: + { + uint8_t ct; + if ( arg_int < 64 ) + ct = 0x060; /* CT_LOW: contrast reduced */ + else if ( arg_int < 128 ) + ct = 0x070; /* normal contrast */ + else if ( arg_int < 192 ) + ct = 0x050; /* CT_HIGH1: contrast slightly increased */ + else + ct = 0x030; /* CT_HIGH2: contrast strongly increased */ + u8x8_mt12864k_write_register(u8x8, 0x08f | ct); + } + break; case U8X8_MSG_DISPLAY_DRAW_TILE: v.ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr; diff --git a/sys/sdl/mt12864k_i2c/main.c b/sys/sdl/mt12864k_i2c/main.c index 68ca16d7..f2f9db65 100644 --- a/sys/sdl/mt12864k_i2c/main.c +++ b/sys/sdl/mt12864k_i2c/main.c @@ -186,7 +186,26 @@ int main(void) if ( !check_transfer(10, 0x078, d2, 2) ) ok = 0; if ( !check_transfer(11, 0x07a, d2, 2) ) ok = 0; - /* 4. full buffer: left half 0x55, right half 0xaa, then send */ + /* 4. contrast: single byte writes to the control register (0x076). + Only four discrete levels are available (datasheet table 4): + value 0..63 -> CT_LOW (reduced) register 0x0ef + value 64..127 -> normal register 0x0ff + value 128..191 -> CT_HIGH1 (slight incr.) register 0x0df + value 192..255 -> CT_HIGH2 (strong incr.) register 0x0bf + All boundary values are checked. */ + { + const uint8_t contrast_values[] = { 0, 63, 64, 127, 128, 191, 192, 255 }; + const uint8_t contrast_reg[] = { 0x0ef, 0x0ef, 0x0ff, 0x0ff, + 0x0df, 0x0df, 0x0bf, 0x0bf }; + int i; + for( i = 0; i < 8; i++ ) + { + u8x8_SetContrast(u8g2_GetU8x8(&u8g2), contrast_values[i]); + if ( !check_transfer(12 + i, 0x076, &contrast_reg[i], 1) ) ok = 0; + } + } + + /* 5. full buffer: left half 0x55, right half 0xaa, then send */ buf = u8g2_GetBufferPtr(&u8g2); for( page = 0; page < 8; page++ ) { @@ -210,7 +229,7 @@ int main(void) cnt_data_r = 0; data_bytes_l = 0; data_bytes_r = 0; - t = 12; /* transfers 0..11 were init + power on */ + t = 20; /* transfers 0..19 were init, power on and contrast */ for( page = 0; page < 8; page++ ) { int chip;