Skip to content

Commit 33737a6

Browse files
committed
If an I2C error occurs when sending a nibble, continue to try and send the second nibble to reduce the chance of the display getting out of sync. Refactor init() function into init() and reset(), to allow users to reset the display without reinitialising with the smbus instance or backlight.
1 parent 26d8964 commit 33737a6

File tree

2 files changed

+116
-69
lines changed

2 files changed

+116
-69
lines changed

i2c-lcd1602.c

Lines changed: 107 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -201,45 +201,35 @@ static esp_err_t _write_to_expander(const i2c_lcd1602_info_t * i2c_lcd1602_info,
201201
return smbus_send_byte(i2c_lcd1602_info->smbus_info, data | i2c_lcd1602_info->backlight_flag);
202202
}
203203

204+
// IMPORTANT - for the display to stay "in sync" it is important that errors do not interrupt the
205+
// 2 x nibble sequence.
206+
204207
// clock data from expander to LCD by causing a falling edge on Enable
205208
static esp_err_t _strobe_enable(const i2c_lcd1602_info_t * i2c_lcd1602_info, uint8_t data)
206209
{
207-
esp_err_t err = _write_to_expander(i2c_lcd1602_info, data | FLAG_ENABLE);
208-
if (err == ESP_OK)
209-
{
210-
ets_delay_us(DELAY_ENABLE_PULSE_WIDTH);
211-
err = _write_to_expander(i2c_lcd1602_info, data & ~FLAG_ENABLE);
212-
if (err == ESP_OK)
213-
{
214-
ets_delay_us(DELAY_ENABLE_PULSE_SETTLE);
215-
ESP_LOGD(TAG, "enable strobed");
216-
}
217-
}
218-
return err;
210+
esp_err_t err1 = _write_to_expander(i2c_lcd1602_info, data | FLAG_ENABLE);
211+
ets_delay_us(DELAY_ENABLE_PULSE_WIDTH);
212+
esp_err_t err2 = _write_to_expander(i2c_lcd1602_info, data & ~FLAG_ENABLE);
213+
ets_delay_us(DELAY_ENABLE_PULSE_SETTLE);
214+
return err1 ? err1 : err2;
219215
}
220216

221217
// send top nibble to the LCD controller
222218
static esp_err_t _write_top_nibble(const i2c_lcd1602_info_t * i2c_lcd1602_info, uint8_t data)
223219
{
224220
ESP_LOGD(TAG, "_write_top_nibble 0x%02x", data);
225-
esp_err_t err = _write_to_expander(i2c_lcd1602_info, data);
226-
if (err == ESP_OK)
227-
{
228-
err = _strobe_enable(i2c_lcd1602_info, data);
229-
}
230-
return err;
221+
esp_err_t err1 = _write_to_expander(i2c_lcd1602_info, data);
222+
esp_err_t err2 = _strobe_enable(i2c_lcd1602_info, data);
223+
return err1 ? err1 : err2;
231224
}
232225

233226
// send command or data to controller
234227
static esp_err_t _write(const i2c_lcd1602_info_t * i2c_lcd1602_info, uint8_t value, uint8_t register_select_flag)
235228
{
236229
ESP_LOGD(TAG, "_write 0x%02x | 0x%02x", value, register_select_flag);
237-
esp_err_t err = _write_top_nibble(i2c_lcd1602_info, (value & 0xf0) | register_select_flag);
238-
if (err == ESP_OK)
239-
{
240-
err = _write_top_nibble(i2c_lcd1602_info, ((value & 0x0f) << 4) | register_select_flag);
241-
}
242-
return err;
230+
esp_err_t err1 = _write_top_nibble(i2c_lcd1602_info, (value & 0xf0) | register_select_flag);
231+
esp_err_t err2 = _write_top_nibble(i2c_lcd1602_info, ((value & 0x0f) << 4) | register_select_flag);
232+
return err1 ? err1 : err2;
243233
}
244234

245235
// send command to controller
@@ -309,51 +299,7 @@ esp_err_t i2c_lcd1602_init(i2c_lcd1602_info_t * i2c_lcd1602_info, smbus_info_t *
309299
// Wait at least 40ms after power rises above 2.7V before sending commands.
310300
ets_delay_us(DELAY_POWER_ON);
311301

312-
// put Expander into known state - Register Select and Read/Write both low
313-
err = _write_to_expander(i2c_lcd1602_info, 0);
314-
if (err == ESP_OK)
315-
{
316-
ets_delay_us(1000);
317-
318-
// select 4-bit mode on LCD controller - see datasheet page 46, figure 24.
319-
err = _write_top_nibble(i2c_lcd1602_info, 0x03 << 4);
320-
if (err == ESP_OK)
321-
{
322-
ets_delay_us(DELAY_INIT_1);
323-
err = _write_top_nibble(i2c_lcd1602_info, 0x03 << 4); // repeat
324-
if (err == ESP_OK)
325-
{
326-
ets_delay_us(DELAY_INIT_2);
327-
err = _write_top_nibble(i2c_lcd1602_info, 0x03 << 4); // repeat
328-
if (err == ESP_OK)
329-
{
330-
ets_delay_us(DELAY_INIT_3);
331-
err = _write_top_nibble(i2c_lcd1602_info, 0x02 << 4); // select 4-bit mode
332-
if (err == ESP_OK)
333-
{
334-
// now we can use the command()/write() functions
335-
err = _write_command(i2c_lcd1602_info, COMMAND_FUNCTION_SET | FLAG_FUNCTION_SET_MODE_4BIT | FLAG_FUNCTION_SET_LINES_2 | FLAG_FUNCTION_SET_DOTS_5X8);
336-
if (err == ESP_OK)
337-
{
338-
err = _write_command(i2c_lcd1602_info, COMMAND_DISPLAY_CONTROL | i2c_lcd1602_info->display_control_flags);
339-
if (err == ESP_OK)
340-
{
341-
err = i2c_lcd1602_clear(i2c_lcd1602_info);
342-
if (err == ESP_OK)
343-
{
344-
err = _write_command(i2c_lcd1602_info, COMMAND_ENTRY_MODE_SET | i2c_lcd1602_info->entry_mode_flags);
345-
if (err == ESP_OK)
346-
{
347-
err = i2c_lcd1602_home(i2c_lcd1602_info);
348-
}
349-
}
350-
}
351-
}
352-
}
353-
}
354-
}
355-
}
356-
}
302+
err = i2c_lcd1602_reset(i2c_lcd1602_info);
357303
}
358304
else
359305
{
@@ -363,6 +309,98 @@ esp_err_t i2c_lcd1602_init(i2c_lcd1602_info_t * i2c_lcd1602_info, smbus_info_t *
363309
return err;
364310
}
365311

312+
esp_err_t i2c_lcd1602_reset(const i2c_lcd1602_info_t * i2c_lcd1602_info)
313+
{
314+
esp_err_t first_err = ESP_OK;
315+
esp_err_t last_err = ESP_FAIL;
316+
317+
// put Expander into known state - Register Select and Read/Write both low
318+
if ((last_err = _write_to_expander(i2c_lcd1602_info, 0)) != ESP_OK)
319+
{
320+
if (first_err == ESP_OK)
321+
first_err = last_err;
322+
ESP_LOGE(TAG, "reset: _write_to_expander 1 failed: %d", last_err);
323+
}
324+
325+
ets_delay_us(1000);
326+
327+
// select 4-bit mode on LCD controller - see datasheet page 46, figure 24.
328+
if ((last_err = _write_top_nibble(i2c_lcd1602_info, 0x03 << 4)) != ESP_OK)
329+
{
330+
if (first_err == ESP_OK)
331+
first_err = last_err;
332+
ESP_LOGE(TAG, "reset: _write_top_nibble 1 failed: %d", last_err);
333+
}
334+
335+
ets_delay_us(DELAY_INIT_1);
336+
337+
// repeat
338+
if ((last_err = _write_top_nibble(i2c_lcd1602_info, 0x03 << 4)) != ESP_OK)
339+
{
340+
if (first_err == ESP_OK)
341+
first_err = last_err;
342+
ESP_LOGE(TAG, "reset: _write_top_nibble 2 failed: %d", last_err);
343+
}
344+
345+
ets_delay_us(DELAY_INIT_2);
346+
347+
// repeat
348+
if ((last_err = _write_top_nibble(i2c_lcd1602_info, 0x03 << 4)) != ESP_OK)
349+
{
350+
if (first_err == ESP_OK)
351+
first_err = last_err;
352+
ESP_LOGE(TAG, "reset: _write_top_nibble 3 failed: %d", last_err);
353+
}
354+
355+
ets_delay_us(DELAY_INIT_3);
356+
357+
// select 4-bit mode
358+
if ((last_err = _write_top_nibble(i2c_lcd1602_info, 0x02 << 4)) != ESP_OK)
359+
{
360+
if (first_err == ESP_OK)
361+
first_err = last_err;
362+
ESP_LOGE(TAG, "reset: _write_top_nibble 4 failed: %d", last_err);
363+
}
364+
365+
// now we can use the command()/write() functions
366+
if ((last_err = _write_command(i2c_lcd1602_info, COMMAND_FUNCTION_SET | FLAG_FUNCTION_SET_MODE_4BIT | FLAG_FUNCTION_SET_LINES_2 | FLAG_FUNCTION_SET_DOTS_5X8)) != ESP_OK)
367+
{
368+
if (first_err == ESP_OK)
369+
first_err = last_err;
370+
ESP_LOGE(TAG, "reset: _write_command 1 failed: %d", last_err);
371+
}
372+
373+
if ((last_err = _write_command(i2c_lcd1602_info, COMMAND_DISPLAY_CONTROL | i2c_lcd1602_info->display_control_flags)) != ESP_OK)
374+
{
375+
if (first_err == ESP_OK)
376+
first_err = last_err;
377+
ESP_LOGE(TAG, "reset: _write_command 2 failed: %d", last_err);
378+
}
379+
380+
if ((last_err = i2c_lcd1602_clear(i2c_lcd1602_info)) != ESP_OK)
381+
{
382+
if (first_err == ESP_OK)
383+
first_err = last_err;
384+
ESP_LOGE(TAG, "reset: i2c_lcd1602_clear failed: %d", last_err);
385+
}
386+
387+
if ((last_err = _write_command(i2c_lcd1602_info, COMMAND_ENTRY_MODE_SET | i2c_lcd1602_info->entry_mode_flags)) != ESP_OK)
388+
{
389+
if (first_err == ESP_OK)
390+
first_err = last_err;
391+
ESP_LOGE(TAG, "reset: _write_command 3 failed: %d", last_err);
392+
}
393+
394+
if ((last_err = i2c_lcd1602_home(i2c_lcd1602_info)) != ESP_OK)
395+
{
396+
if (first_err == ESP_OK)
397+
first_err = last_err;
398+
ESP_LOGE(TAG, "reset: i2c_lcd1602_home failed: %d", last_err);
399+
}
400+
401+
return first_err;
402+
}
403+
366404
esp_err_t i2c_lcd1602_clear(const i2c_lcd1602_info_t * i2c_lcd1602_info)
367405
{
368406
esp_err_t err = ESP_FAIL;

include/i2c-lcd1602.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,18 @@ void i2c_lcd1602_free(i2c_lcd1602_info_t ** tsl2561_info);
127127
*
128128
* @param[in] i2c_lcd1602_info Pointer to I2C-LCD1602 info instance.
129129
* @param[in] smbus_info Pointer to SMBus info instance.
130+
* @return ESP_OK if successful, otherwise an error constant.
130131
*/
131132
esp_err_t i2c_lcd1602_init(i2c_lcd1602_info_t * i2c_lcd1602_info, smbus_info_t * smbus_info, bool backlight);
132133

134+
/**
135+
* @brief Reset the display. Custom characters will be cleared.
136+
*
137+
* @param[in] i2c_lcd1602_info Pointer to I2C-LCD1602 info instance.
138+
* @return ESP_OK if successful, otherwise an error constant.
139+
*/
140+
esp_err_t i2c_lcd1602_reset(const i2c_lcd1602_info_t * i2c_lcd1602_info);
141+
133142
/**
134143
* @brief Clears entire display (clears DDRAM) and returns cursor to home position.
135144
* DDRAM content is cleared, CGRAM content is not changed.

0 commit comments

Comments
 (0)