diff --git a/applications/debug_tools/display_test/display_test.c b/applications/debug_tools/display_test/display_test.c index 7dd4d603..1e393a8c 100644 --- a/applications/debug_tools/display_test/display_test.c +++ b/applications/debug_tools/display_test/display_test.c @@ -3,7 +3,11 @@ #include #include -#include +// Need access to u8g2 +#include +#include +#include + #include #include #include @@ -16,6 +20,10 @@ typedef struct { ViewDisplayTest* view_display_test; VariableItemList* variable_item_list; Submenu* submenu; + + bool config_bias; + uint8_t config_contrast; + uint8_t config_regulation_ratio; } DisplayTest; typedef enum { @@ -24,9 +32,38 @@ typedef enum { DisplayTestViewDisplayTest, } DisplayTestView; +const bool config_bias_value[] = { + true, + false, +}; +const char* const config_bias_text[] = { + "1/7", + "1/9", +}; + +const uint8_t config_regulation_ratio_value[] = { + 0b000, + 0b001, + 0b010, + 0b011, + 0b100, + 0b101, + 0b110, + 0b111, +}; +const char* const config_regulation_ratio_text[] = { + "3.0", + "3.5", + "4.0", + "4.5", + "5.0", + "5.5", + "6.0", + "6.5", +}; + static void display_test_submenu_callback(void* context, uint32_t index) { DisplayTest* instance = (DisplayTest*)context; - view_dispatcher_switch_to_view(instance->view_dispatcher, index); } @@ -38,6 +75,49 @@ static uint32_t display_test_exit_callback(void* context) { return VIEW_NONE; } +static void display_test_reload_config(DisplayTest* instance) { + FURI_LOG_I( + "DisplayTest", + "contrast: %d, regulation_ratio: %d, bias: %d", + instance->config_contrast, + instance->config_regulation_ratio, + instance->config_bias); + u8x8_d_st756x_erc_init( + &instance->gui->canvas->fb.u8x8, + instance->config_contrast, + instance->config_regulation_ratio, + instance->config_bias); + gui_update(instance->gui); +} + +static void display_config_set_bias(VariableItem* item) { + DisplayTest* instance = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, config_bias_text[index]); + instance->config_bias = config_bias_value[index]; + display_test_reload_config(instance); +} + +static void display_config_set_regulation_ratio(VariableItem* item) { + DisplayTest* instance = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, config_regulation_ratio_text[index]); + instance->config_regulation_ratio = config_regulation_ratio_value[index]; + display_test_reload_config(instance); +} + +static void display_config_set_contrast(VariableItem* item) { + DisplayTest* instance = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + string_t temp; + string_init(temp); + string_cat_printf(temp, "%d", index); + variable_item_set_current_value_text(item, string_get_cstr(temp)); + string_clear(temp); + instance->config_contrast = index; + display_test_reload_config(instance); +} + DisplayTest* display_test_alloc() { DisplayTest* instance = furi_alloc(sizeof(DisplayTest)); @@ -45,15 +125,52 @@ DisplayTest* display_test_alloc() { instance->gui = furi_record_open("gui"); instance->view_dispatcher = view_dispatcher_alloc(); - - instance->view_display_test = view_display_test_alloc(); view_dispatcher_enable_queue(instance->view_dispatcher); view_dispatcher_attach_to_gui( instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); + + // Test + instance->view_display_test = view_display_test_alloc(); view = view_display_test_get_view(instance->view_display_test); view_set_previous_callback(view, display_test_previous_callback); view_dispatcher_add_view(instance->view_dispatcher, DisplayTestViewDisplayTest, view); + // Configure + instance->variable_item_list = variable_item_list_alloc(); + view = variable_item_list_get_view(instance->variable_item_list); + view_set_previous_callback(view, display_test_previous_callback); + view_dispatcher_add_view(instance->view_dispatcher, DisplayTestViewConfigure, view); + + // Configurtion items + VariableItem* item; + instance->config_bias = false; + instance->config_contrast = 32; + instance->config_regulation_ratio = 0b101; + // Bias + item = variable_item_list_add( + instance->variable_item_list, + "Bias:", + COUNT_OF(config_bias_value), + display_config_set_bias, + instance); + variable_item_set_current_value_index(item, 1); + variable_item_set_current_value_text(item, config_bias_text[1]); + // Regulation Ratio + item = variable_item_list_add( + instance->variable_item_list, + "Reg Ratio:", + COUNT_OF(config_regulation_ratio_value), + display_config_set_regulation_ratio, + instance); + variable_item_set_current_value_index(item, 5); + variable_item_set_current_value_text(item, config_regulation_ratio_text[5]); + // Contrast + item = variable_item_list_add( + instance->variable_item_list, "Contrast:", 64, display_config_set_contrast, instance); + variable_item_set_current_value_index(item, 32); + variable_item_set_current_value_text(item, "32"); + + // Menu instance->submenu = submenu_alloc(); view = submenu_get_view(instance->submenu); view_set_previous_callback(view, display_test_exit_callback); @@ -64,7 +181,12 @@ DisplayTest* display_test_alloc() { DisplayTestViewDisplayTest, display_test_submenu_callback, instance); - // submenu_add_item(instance->submenu, "Configure", DisplayTestViewConfigure, display_test_submenu_callback, instance); + submenu_add_item( + instance->submenu, + "Configure", + DisplayTestViewConfigure, + display_test_submenu_callback, + instance); return instance; } @@ -73,6 +195,9 @@ void display_test_free(DisplayTest* instance) { view_dispatcher_remove_view(instance->view_dispatcher, DisplayTestViewSubmenu); submenu_free(instance->submenu); + view_dispatcher_remove_view(instance->view_dispatcher, DisplayTestViewConfigure); + variable_item_list_free(instance->variable_item_list); + view_dispatcher_remove_view(instance->view_dispatcher, DisplayTestViewDisplayTest); view_display_test_free(instance->view_display_test); @@ -97,4 +222,4 @@ int32_t display_test_app(void* p) { display_test_free(instance); return ret; -} \ No newline at end of file +} diff --git a/applications/gui/canvas.c b/applications/gui/canvas.c index 7c886430..f1b351d8 100644 --- a/applications/gui/canvas.c +++ b/applications/gui/canvas.c @@ -16,7 +16,6 @@ Canvas* canvas_init() { // send init sequence to the display, display is in sleep mode after this u8g2_InitDisplay(&canvas->fb); - u8g2_SetContrast(&canvas->fb, 36); // wake up display u8g2_ClearBuffer(&canvas->fb); u8g2_SetPowerSave(&canvas->fb, 0); @@ -41,7 +40,6 @@ void canvas_reset(Canvas* canvas) { void canvas_commit(Canvas* canvas) { furi_assert(canvas); - u8g2_SetPowerSave(&canvas->fb, 0); // wake up display u8g2_SendBuffer(&canvas->fb); } diff --git a/bootloader/targets/f6/target.c b/bootloader/targets/f6/target.c index f017a1e6..6d94e5d1 100644 --- a/bootloader/targets/f6/target.c +++ b/bootloader/targets/f6/target.c @@ -191,7 +191,6 @@ void target_display_init() { u8g2_t fb; u8g2_Setup_st756x_erc(&fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); u8g2_InitDisplay(&fb); - u8g2_SetContrast(&fb, 36); // Create payload u8g2_ClearBuffer(&fb); u8g2_SetDrawColor(&fb, 0x01); diff --git a/bootloader/targets/f7/target.c b/bootloader/targets/f7/target.c index f017a1e6..6d94e5d1 100644 --- a/bootloader/targets/f7/target.c +++ b/bootloader/targets/f7/target.c @@ -191,7 +191,6 @@ void target_display_init() { u8g2_t fb; u8g2_Setup_st756x_erc(&fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); u8g2_InitDisplay(&fb); - u8g2_SetContrast(&fb, 36); // Create payload u8g2_ClearBuffer(&fb); u8g2_SetDrawColor(&fb, 0x01); diff --git a/lib/u8g2/u8g2_glue.c b/lib/u8g2/u8g2_glue.c index c9aff818..b2549eeb 100644 --- a/lib/u8g2/u8g2_glue.c +++ b/lib/u8g2/u8g2_glue.c @@ -57,23 +57,42 @@ uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ return 1; } -static const uint8_t u8x8_d_st7565_powersave0_seq[] = { - U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */ - U8X8_C(0x0a4), /* all pixel off, issue 142 */ - U8X8_C(0x0af), /* display on */ - U8X8_END_TRANSFER(), /* disable chip */ - U8X8_END() /* end of sequence */ +#define ST756X_CMD_ON_OFF 0b10101110 /**< 0:0 Switch Display ON/OFF: last bit */ +#define ST756X_CMD_SET_LINE 0b01000000 /**< 0:0 Set Start Line: last 6 bits */ +#define ST756X_CMD_SET_PAGE 0b10110000 /**< 0:0 Set Page address: last 4 bits */ +#define ST756X_CMD_SET_COLUMN_MSB 0b00010000 /**< 0:0 Set Column MSB: last 4 bits */ +#define ST756X_CMD_SET_COLUMN_LSB 0b00000000 /**< 0:0 Set Column LSB: last 4 bits */ +#define ST756X_CMD_SEG_DIRECTION 0b10100000 /**< 0:0 Reverse scan direction of SEG: last bit */ +#define ST756X_CMD_INVERSE_DISPLAY 0b10100110 /**< 0:0 Invert display: last bit */ +#define ST756X_CMD_ALL_PIXEL_ON 0b10100100 /**< 0:0 Set all pixel on: last bit */ +#define ST756X_CMD_BIAS_SELECT 0b10100010 /**< 0:0 Select 1/9(0) or 1/7(1) bias: last bit */ +#define ST756X_CMD_R_M_W 0b11100000 /**< 0:0 Enter Read Modify Write mode: read+0, write+1 */ +#define ST756X_CMD_END 0b11101110 /**< 0:0 Exit Read Modify Write mode */ +#define ST756X_CMD_RESET 0b11100010 /**< 0:0 Software Reset */ +#define ST756X_CMD_COM_DIRECTION 0b11000000 /**< 0:0 Com direction reverse: +0b1000 */ +#define ST756X_CMD_POWER_CONTROL 0b00101000 /**< 0:0 Power control: last 3 bits VB:VR:VF */ +#define ST756X_CMD_REGULATION_RATIO 0b00100000 /**< 0:0 Regulation resistor ration: last 3bits */ +#define ST756X_CMD_SET_EV 0b10000001 /**< 0:0 Set electronic volume: 5 bits in next byte */ +#define ST756X_CMD_SET_BOOSTER 0b11111000 /**< 0:0 Set Booster level, 4X(0) or 5X(1): last bit in next byte */ +#define ST756X_CMD_NOP 0b11100011 /**< 0:0 No operation */ + +static const uint8_t u8x8_d_st756x_powersave0_seq[] = { + U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */ + U8X8_C(ST756X_CMD_ALL_PIXEL_ON | 0b0), /* all pixel off */ + U8X8_C(ST756X_CMD_ON_OFF | 0b1), /* display on */ + U8X8_END_TRANSFER(), /* disable chip */ + U8X8_END() /* end of sequence */ }; -static const uint8_t u8x8_d_st7565_powersave1_seq[] = { - U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */ - U8X8_C(0x0ae), /* display off */ - U8X8_C(0x0a5), /* enter powersafe: all pixel on, issue 142 */ - U8X8_END_TRANSFER(), /* disable chip */ - U8X8_END() /* end of sequence */ +static const uint8_t u8x8_d_st756x_powersave1_seq[] = { + U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */ + U8X8_C(ST756X_CMD_ON_OFF | 0b0), /* display off */ + U8X8_C(ST756X_CMD_ALL_PIXEL_ON | 0b1), /* all pixel on */ + U8X8_END_TRANSFER(), /* disable chip */ + U8X8_END() /* end of sequence */ }; -static const uint8_t u8x8_d_st7565_flip0_seq[] = { +static const uint8_t u8x8_d_st756x_flip0_seq[] = { U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */ U8X8_C(0x0a1), /* segment remap a0/a1*/ U8X8_C(0x0c0), /* c0: scan dir normal, c8: reverse */ @@ -81,7 +100,7 @@ static const uint8_t u8x8_d_st7565_flip0_seq[] = { U8X8_END() /* end of sequence */ }; -static const uint8_t u8x8_d_st7565_flip1_seq[] = { +static const uint8_t u8x8_d_st756x_flip1_seq[] = { U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */ U8X8_C(0x0a0), /* segment remap a0/a1*/ U8X8_C(0x0c8), /* c0: scan dir normal, c8: reverse */ @@ -111,7 +130,7 @@ static const u8x8_display_info_t u8x8_st756x_128x64_display_info = { .pixel_height = 64 }; -uint8_t u8x8_d_st7565_common(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) { +uint8_t u8x8_d_st756x_common(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) { uint8_t x, c; uint8_t *ptr; @@ -148,14 +167,14 @@ uint8_t u8x8_d_st7565_common(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *a break; case U8X8_MSG_DISPLAY_SET_POWER_SAVE: if ( arg_int == 0 ) - u8x8_cad_SendSequence(u8x8, u8x8_d_st7565_powersave0_seq); + u8x8_cad_SendSequence(u8x8, u8x8_d_st756x_powersave0_seq); else - u8x8_cad_SendSequence(u8x8, u8x8_d_st7565_powersave1_seq); + u8x8_cad_SendSequence(u8x8, u8x8_d_st756x_powersave1_seq); break; #ifdef U8X8_WITH_SET_CONTRAST case U8X8_MSG_DISPLAY_SET_CONTRAST: u8x8_cad_StartTransfer(u8x8); - u8x8_cad_SendCmd(u8x8, 0x081 ); + u8x8_cad_SendCmd(u8x8, ST756X_CMD_SET_EV); u8x8_cad_SendArg(u8x8, arg_int >> 2 ); /* st7565 has range from 0 to 63 */ u8x8_cad_EndTransfer(u8x8); break; @@ -166,27 +185,33 @@ uint8_t u8x8_d_st7565_common(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *a return 1; } -static const uint8_t u8x8_d_st756x_erc_init_seq[] = { - U8X8_START_TRANSFER(), - U8X8_C(0x0e2), // soft reset - U8X8_C(0xA3), // CMD_SET_BIAS_7 - U8X8_C(0xA0), // CMD_SET_ADC_NORMAL - U8X8_C(0xC8), // CMD_SET_COM_REVERSE - U8X8_C(0x40), // CMD_SET_DISP_START_LINE - U8X8_C(0x28 | 0x4), // CMD_SET_POWER_CONTROL | 0x4 - U8X8_DLY(50), - U8X8_C(0x28 | 0x6), // CMD_SET_POWER_CONTROL | 0x6 - U8X8_DLY(50), - U8X8_C(0x28 | 0x7), // CMD_SET_POWER_CONTROL | 0x7 - U8X8_DLY(50), - U8X8_C(0x20 | 0x6), // CMD_SET_RESISTOR_RATIO | 0x6 - U8X8_END_TRANSFER(), - U8X8_END() // end of sequence -}; +void u8x8_d_st756x_erc_init(u8x8_t *u8x8, uint8_t contrast, uint8_t regulation_ratio, bool bias) { + contrast = contrast & 0b00111111; + regulation_ratio = regulation_ratio & 0b111; + + u8x8_cad_StartTransfer(u8x8); + // Reset + u8x8_cad_SendCmd(u8x8, ST756X_CMD_RESET); + // Bias: 1/7(0b1) or 1/9(0b0) + u8x8_cad_SendCmd(u8x8, ST756X_CMD_BIAS_SELECT | bias); + // Page, Line and Segment config + u8x8_cad_SendCmd(u8x8, ST756X_CMD_SEG_DIRECTION); + u8x8_cad_SendCmd(u8x8, ST756X_CMD_COM_DIRECTION | 0b1000); + u8x8_cad_SendCmd(u8x8, ST756X_CMD_SET_LINE); + // Set Regulation Ratio + u8x8_cad_SendCmd(u8x8, ST756X_CMD_REGULATION_RATIO | regulation_ratio); + // Set EV + u8x8_cad_SendCmd(u8x8, ST756X_CMD_SET_EV); + u8x8_cad_SendArg(u8x8, contrast); + // Enable power + u8x8_cad_SendCmd(u8x8, ST756X_CMD_POWER_CONTROL | 0b111); + + u8x8_cad_EndTransfer(u8x8); +} uint8_t u8x8_d_st756x_erc(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) { + if (u8x8_d_st756x_common(u8x8, msg, arg_int, arg_ptr) == 0) { /* msg not handled, then try here */ switch(msg){ case U8X8_MSG_DISPLAY_SETUP_MEMORY: @@ -194,14 +219,20 @@ uint8_t u8x8_d_st756x_erc(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ break; case U8X8_MSG_DISPLAY_INIT: u8x8_d_helper_display_init(u8x8); - u8x8_cad_SendSequence(u8x8, u8x8_d_st756x_erc_init_seq); + /* Bias, EV and Regulation Ration + * EV = 32 + * RR = V0 / ((1 - (63 - EV) / 162) * 2.1) + * RR = 10 / ((1 - (63 - 32) / 162) * 2.1) ~= 5.88 is 5.5 (0b101) + * Bias = 1/9 (false) + */ + u8x8_d_st756x_erc_init(u8x8, 32, 0b101, false); break; case U8X8_MSG_DISPLAY_SET_FLIP_MODE: if ( arg_int == 0 ) { - u8x8_cad_SendSequence(u8x8, u8x8_d_st7565_flip1_seq); + u8x8_cad_SendSequence(u8x8, u8x8_d_st756x_flip1_seq); u8x8->x_offset = u8x8->display_info->default_x_offset; } else { - u8x8_cad_SendSequence(u8x8, u8x8_d_st7565_flip0_seq); + u8x8_cad_SendSequence(u8x8, u8x8_d_st756x_flip0_seq); u8x8->x_offset = u8x8->display_info->flipmode_x_offset; } break; diff --git a/lib/u8g2/u8g2_glue.h b/lib/u8g2/u8g2_glue.h index 4a5d8655..10236df0 100644 --- a/lib/u8g2/u8g2_glue.h +++ b/lib/u8g2/u8g2_glue.h @@ -1,9 +1,12 @@ #pragma once #include "u8g2.h" +#include uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr); uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr); void u8g2_Setup_st756x_erc(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb); + +void u8x8_d_st756x_erc_init(u8x8_t *u8x8, uint8_t contrast, uint8_t regulation_ratio, bool bias); diff --git a/lib/u8g2/u8x8.h b/lib/u8g2/u8x8.h index 75cd44b0..53509578 100644 --- a/lib/u8g2/u8x8.h +++ b/lib/u8g2/u8x8.h @@ -89,7 +89,7 @@ /* Global Defines */ /* Undefine this to remove u8x8_SetContrast function */ -#define U8X8_WITH_SET_CONTRAST +// #define U8X8_WITH_SET_CONTRAST /* Define this for an additional user pointer inside the u8x8 data struct */ //#define U8X8_WITH_USER_PTR