diff --git a/CMakeLists.txt b/CMakeLists.txt index 41d6fff..e4832b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ set(COMPONENT_ADD_INCLUDEDIRS include) set(COMPONENT_SRCDIRS ".") -set(COMPONENT_PRIV_REQUIRES "esp32-smbus") +set(COMPONENT_PRIV_REQUIRES "esp_driver_i2c") register_component() diff --git a/README.md b/README.md index 953d572..d352a7a 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,11 @@ This component provides useful access functions for the I2C-LCD1602 device, which is compatible with the HD44780 LCD controller. It uses a PCF8574A Remote 8-bit I/O Expander over the I2C bus, allowing the controller to be programmed via I2C using 4-bit mode. -It is written and tested for the [ESP-IDF](https://github.com/espressif/esp-idf) environment, version 2.1, using the xtensa-esp32-elf toolchain (gcc version 5.2.0). +It is written and tested for the [ESP-IDF](https://github.com/espressif/esp-idf) environment, version 5.5, using the xtensa-esp32-elf toolchain (gcc version 14.2.0). ## Dependencies -Requires [esp32-smbus](https://github.com/DavidAntliff/esp32-smbus). +Requires [esp_driver_i2c] (provided with esp-idf) ## Example @@ -49,7 +49,6 @@ The code in this project is licensed under the MIT license - see LICENSE for det ## Acknowledgements * Inspired by the Arduino [DFRobot sample code](http://www.dfrobot.com/image/data/DFR0154/LiquidCrystal_I2Cv1-1.rar). - * "SMBus" is a trademark of Intel Corporation. * "I2C" is a registered trademark of Phillips Corporation. ## Roadmap diff --git a/i2c-lcd1602.c b/i2c-lcd1602.c index 122f8c8..979003f 100644 --- a/i2c-lcd1602.c +++ b/i2c-lcd1602.c @@ -198,7 +198,8 @@ static esp_err_t _write_to_expander(const i2c_lcd1602_info_t * i2c_lcd1602_info, { // backlight flag must be included with every write to maintain backlight state ESP_LOGD(TAG, "_write_to_expander 0x%02x", data | i2c_lcd1602_info->backlight_flag); - return smbus_send_byte(i2c_lcd1602_info->smbus_info, data | i2c_lcd1602_info->backlight_flag); + data |= i2c_lcd1602_info->backlight_flag; + return i2c_master_transmit(*i2c_lcd1602_info->i2c_info->dev_handle, &data, 1, i2c_lcd1602_info->i2c_info->i2c_transfer_timeout_ms / portTICK_PERIOD_MS); } // IMPORTANT - for the display to stay "in sync" it is important that errors do not interrupt the @@ -208,9 +209,9 @@ static esp_err_t _write_to_expander(const i2c_lcd1602_info_t * i2c_lcd1602_info, static esp_err_t _strobe_enable(const i2c_lcd1602_info_t * i2c_lcd1602_info, uint8_t data) { esp_err_t err1 = _write_to_expander(i2c_lcd1602_info, data | FLAG_ENABLE); - ets_delay_us(DELAY_ENABLE_PULSE_WIDTH); + esp_rom_delay_us(DELAY_ENABLE_PULSE_WIDTH); esp_err_t err2 = _write_to_expander(i2c_lcd1602_info, data & ~FLAG_ENABLE); - ets_delay_us(DELAY_ENABLE_PULSE_SETTLE); + esp_rom_delay_us(DELAY_ENABLE_PULSE_SETTLE); return err1 ? err1 : err2; } @@ -278,13 +279,14 @@ void i2c_lcd1602_free(i2c_lcd1602_info_t ** i2c_lcd1602_info) } } -esp_err_t i2c_lcd1602_init(i2c_lcd1602_info_t * i2c_lcd1602_info, smbus_info_t * smbus_info, +esp_err_t i2c_lcd1602_init(i2c_lcd1602_info_t * i2c_lcd1602_info, struct i2c_info_t * i2c_info, bool backlight, uint8_t num_rows, uint8_t num_columns, uint8_t num_visible_columns) { esp_err_t err = ESP_FAIL; if (i2c_lcd1602_info != NULL) { - i2c_lcd1602_info->smbus_info = smbus_info; + i2c_lcd1602_info->i2c_info = i2c_info; + i2c_lcd1602_info->backlight_flag = backlight ? FLAG_BACKLIGHT_ON : FLAG_BACKLIGHT_OFF; i2c_lcd1602_info->num_rows = num_rows; i2c_lcd1602_info->num_columns = num_columns; @@ -301,7 +303,7 @@ esp_err_t i2c_lcd1602_init(i2c_lcd1602_info_t * i2c_lcd1602_info, smbus_info_t * // See page 45/46 of HD44780 data sheet for the initialisation procedure. // Wait at least 40ms after power rises above 2.7V before sending commands. - ets_delay_us(DELAY_POWER_ON); + esp_rom_delay_us(DELAY_POWER_ON); err = i2c_lcd1602_reset(i2c_lcd1602_info); } @@ -326,7 +328,7 @@ esp_err_t i2c_lcd1602_reset(const i2c_lcd1602_info_t * i2c_lcd1602_info) ESP_LOGE(TAG, "reset: _write_to_expander 1 failed: %d", last_err); } - ets_delay_us(1000); + esp_rom_delay_us(1000); // select 4-bit mode on LCD controller - see datasheet page 46, figure 24. if ((last_err = _write_top_nibble(i2c_lcd1602_info, 0x03 << 4)) != ESP_OK) @@ -336,7 +338,7 @@ esp_err_t i2c_lcd1602_reset(const i2c_lcd1602_info_t * i2c_lcd1602_info) ESP_LOGE(TAG, "reset: _write_top_nibble 1 failed: %d", last_err); } - ets_delay_us(DELAY_INIT_1); + esp_rom_delay_us(DELAY_INIT_1); // repeat if ((last_err = _write_top_nibble(i2c_lcd1602_info, 0x03 << 4)) != ESP_OK) @@ -346,7 +348,7 @@ esp_err_t i2c_lcd1602_reset(const i2c_lcd1602_info_t * i2c_lcd1602_info) ESP_LOGE(TAG, "reset: _write_top_nibble 2 failed: %d", last_err); } - ets_delay_us(DELAY_INIT_2); + esp_rom_delay_us(DELAY_INIT_2); // repeat if ((last_err = _write_top_nibble(i2c_lcd1602_info, 0x03 << 4)) != ESP_OK) @@ -356,7 +358,7 @@ esp_err_t i2c_lcd1602_reset(const i2c_lcd1602_info_t * i2c_lcd1602_info) ESP_LOGE(TAG, "reset: _write_top_nibble 3 failed: %d", last_err); } - ets_delay_us(DELAY_INIT_3); + esp_rom_delay_us(DELAY_INIT_3); // select 4-bit mode if ((last_err = _write_top_nibble(i2c_lcd1602_info, 0x02 << 4)) != ESP_OK) @@ -413,7 +415,7 @@ esp_err_t i2c_lcd1602_clear(const i2c_lcd1602_info_t * i2c_lcd1602_info) err = _write_command(i2c_lcd1602_info, COMMAND_CLEAR_DISPLAY); if (err == ESP_OK) { - ets_delay_us(DELAY_CLEAR_DISPLAY); + esp_rom_delay_us(DELAY_CLEAR_DISPLAY); } } return err; @@ -427,7 +429,7 @@ esp_err_t i2c_lcd1602_home(const i2c_lcd1602_info_t * i2c_lcd1602_info) err = _write_command(i2c_lcd1602_info, COMMAND_RETURN_HOME); if (err == ESP_OK) { - ets_delay_us(DELAY_RETURN_HOME); + esp_rom_delay_us(DELAY_RETURN_HOME); } } return err; diff --git a/include/i2c-lcd1602.h b/include/i2c-lcd1602.h index 3999458..9ea0567 100644 --- a/include/i2c-lcd1602.h +++ b/include/i2c-lcd1602.h @@ -27,28 +27,36 @@ * @brief Interface definitions for the ESP32-compatible I2C LCD1602 component. * * This component provides structures and functions that are useful for communicating with the device. - * - * Technically, the LCD1602 device is an I2C not SMBus device, however some SMBus protocols can be used - * to communicate with the device, so it makes sense to use an SMBus interface to manage communication. */ #ifndef I2C_LCD1602_H #define I2C_LCD1602_H #include -#include "smbus.h" +#include "driver/i2c_master.h" #ifdef __cplusplus extern "C" { #endif +/** + * @brief Structure containing information related to the I2C master device. + */ + +struct i2c_info_t { + i2c_master_bus_handle_t *bus_handle; + i2c_master_dev_handle_t *dev_handle; + int i2c_transfer_timeout_ms; +}; + + /** * @brief Structure containing information related to the I2C-LCD1602 device. */ typedef struct { bool init; ///< True if struct has been initialised, otherwise false - smbus_info_t * smbus_info; ///< Pointer to associated SMBus info + struct i2c_info_t *i2c_info; ///< Pointer to associated I2C master info uint8_t backlight_flag; ///< Non-zero if backlight is to be enabled, otherwise zero uint8_t num_rows; ///< Number of configured columns uint8_t num_columns; ///< Number of configured columns, including offscreen columns @@ -126,14 +134,14 @@ void i2c_lcd1602_free(i2c_lcd1602_info_t ** tsl2561_info); * @brief Initialise a I2C-LCD1602 info instance with the specified SMBus information. * * @param[in] i2c_lcd1602_info Pointer to I2C-LCD1602 info instance. - * @param[in] smbus_info Pointer to SMBus info instance. + * @param[in] i2c_info Pointer to i2c master info instance. * @param[in] backlight Initial backlight state. * @param[in] num_rows Maximum number of supported rows for this device. Typical values include 2 (1602) or 4 (2004). * @param[in] num_columns Maximum number of supported columns for this device. Typical values include 40 (1602, 2004). * @param[in] num_visible_columns Number of columns visible at any one time. Typical values include 16 (1602) or 20 (2004). * @return ESP_OK if successful, otherwise an error constant. */ -esp_err_t i2c_lcd1602_init(i2c_lcd1602_info_t * i2c_lcd1602_info, smbus_info_t * smbus_info, +esp_err_t i2c_lcd1602_init(i2c_lcd1602_info_t * i2c_lcd1602_info, struct i2c_info_t * i2c_info, bool backlight, uint8_t num_rows, uint8_t num_columns, uint8_t num_visible_columns); /**