Added new i2c driver

This commit is contained in:
nopnop2002 2024-03-24 08:14:25 +09:00
parent 78f3f5611a
commit 22097a5ec3
8 changed files with 354 additions and 88 deletions

View File

@ -14,6 +14,10 @@ ESP-IDF V5.1 is required when using i2c of ESP32C2.
__Note for ESP32C6.__
ESP-IDF V5.1 is required when using ESP32C6.
__Note for ESP-IDF V5.2.__
A new i2c driver is now available in ESP-IDF V5.2.
Under ESP-IDF V5.2 this project uses a new i2c driver.
# Installation
```

View File

@ -1,5 +1,12 @@
set(component_srcs "ssd1306.c" "ssd1306_i2c.c" "ssd1306_spi.c")
set(component_srcs "ssd1306.c" "ssd1306_spi.c")
idf_component_register(SRCS "${component_srcs}"
PRIV_REQUIRES driver
INCLUDE_DIRS ".")
# get IDF version for comparison
set(idf_version "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}")
if(idf_version VERSION_GREATER_EQUAL "5.2")
list(APPEND component_srcs "ssd1306_i2c_new.c")
else()
list(APPEND component_srcs "ssd1306_i2c_legacy.c")
endif()
idf_component_register(SRCS "${component_srcs}" PRIV_REQUIRES driver INCLUDE_DIRS ".")

View File

@ -57,8 +57,7 @@ menu "SSD1306 Configuration"
int "SCL GPIO number"
range 0 GPIO_RANGE_MAX
default 22 if IDF_TARGET_ESP32
default 12 if IDF_TARGET_ESP32S2
default 12 if IDF_TARGET_ESP32S3
default 12 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 6 # C3 and others
help
GPIO number (IOxx) to I2C SCL.
@ -70,8 +69,7 @@ menu "SSD1306 Configuration"
int "SDA GPIO number"
range 0 GPIO_RANGE_MAX
default 21 if IDF_TARGET_ESP32
default 11 if IDF_TARGET_ESP32S2
default 11 if IDF_TARGET_ESP32S3
default 11 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 5 # C3 and others
help
GPIO number (IOxx) to I2C SDA.
@ -83,8 +81,7 @@ menu "SSD1306 Configuration"
int "MOSI GPIO number"
range 0 GPIO_RANGE_MAX
default 23 if IDF_TARGET_ESP32
default 35 if IDF_TARGET_ESP32S2
default 35 if IDF_TARGET_ESP32S3
default 35 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 1 # C3 and others
help
GPIO number (IOxx) to SPI MOSI.
@ -97,8 +94,7 @@ menu "SSD1306 Configuration"
int "SCLK GPIO number"
range 0 GPIO_RANGE_MAX
default 18 if IDF_TARGET_ESP32
default 36 if IDF_TARGET_ESP32S2
default 36 if IDF_TARGET_ESP32S3
default 36 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 2 # C3 and others
help
GPIO number (IOxx) to SPI SCLK.
@ -111,8 +107,7 @@ menu "SSD1306 Configuration"
int "CS GPIO number"
range 0 GPIO_RANGE_MAX
default 5 if IDF_TARGET_ESP32
default 34 if IDF_TARGET_ESP32S2
default 34 if IDF_TARGET_ESP32S3
default 34 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 10 # C3 and others
help
GPIO number (IOxx) to SPI CS.
@ -124,8 +119,7 @@ menu "SSD1306 Configuration"
int "DC GPIO number"
range 0 GPIO_RANGE_MAX
default 4 if IDF_TARGET_ESP32
default 37 if IDF_TARGET_ESP32S2
default 37 if IDF_TARGET_ESP32S3
default 37 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 3 # C3 and others
help
GPIO number (IOxx) to SPI DC.
@ -136,8 +130,7 @@ menu "SSD1306 Configuration"
int "RESET GPIO number"
range -1 GPIO_RANGE_MAX
default 15 if IDF_TARGET_ESP32
default 38 if IDF_TARGET_ESP32S2
default 38 if IDF_TARGET_ESP32S3
default 38 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 4 # C3 and others
help
GPIO number (IOxx) to RESET.
@ -156,7 +149,7 @@ menu "SSD1306 Configuration"
help
Use I2C_PORT_0.
config I2C_PORT_1
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
depends on IDF_TARGET_ARCH_XTENSA
bool "I2C_PORT_1"
help
Use I2C_PORT_1.
@ -173,7 +166,7 @@ menu "SSD1306 Configuration"
help
Use SPI2_HOST. This is also called HSPI_HOST.
config SPI3_HOST
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
depends on IDF_TARGET_ARCH_XTENSA
bool "SPI3_HOST"
help
USE SPI3_HOST. This is also called VSPI_HOST

View File

@ -19,7 +19,7 @@ typedef union out_column_t {
void ssd1306_init(SSD1306_t * dev, int width, int height)
{
if (dev->_address == SPIAddress) {
if (dev->_address == SPI_ADDRESS) {
spi_init(dev, width, height);
} else {
i2c_init(dev, width, height);
@ -47,7 +47,7 @@ int ssd1306_get_pages(SSD1306_t * dev)
void ssd1306_show_buffer(SSD1306_t * dev)
{
if (dev->_address == SPIAddress) {
if (dev->_address == SPI_ADDRESS) {
for (int page=0; page<dev->_pages;page++) {
spi_display_image(dev, page, 0, dev->_page[page]._segs, dev->_width);
}
@ -78,7 +78,7 @@ void ssd1306_get_buffer(SSD1306_t * dev, uint8_t * buffer)
void ssd1306_display_image(SSD1306_t * dev, int page, int seg, uint8_t * images, int width)
{
if (dev->_address == SPIAddress) {
if (dev->_address == SPI_ADDRESS) {
spi_display_image(dev, page, seg, images, width);
} else {
i2c_display_image(dev, page, seg, images, width);
@ -101,7 +101,7 @@ void ssd1306_display_text(SSD1306_t * dev, int page, char * text, int text_len,
if (dev->_flip) ssd1306_flip(image, 8);
ssd1306_display_image(dev, page, seg, image, 8);
#if 0
if (dev->_address == SPIAddress) {
if (dev->_address == SPI_ADDRESS) {
spi_display_image(dev, page, seg, image, 8);
} else {
i2c_display_image(dev, page, seg, image, 8);
@ -154,7 +154,7 @@ ssd1306_display_text_x3(SSD1306_t * dev, int page, char * text, int text_len, bo
}
if (invert) ssd1306_invert(image, 24);
if (dev->_flip) ssd1306_flip(image, 24);
if (dev->_address == SPIAddress) {
if (dev->_address == SPI_ADDRESS) {
spi_display_image(dev, page+yy, seg, image, 24);
} else {
i2c_display_image(dev, page+yy, seg, image, 24);
@ -183,7 +183,7 @@ void ssd1306_clear_line(SSD1306_t * dev, int page, bool invert)
void ssd1306_contrast(SSD1306_t * dev, int contrast)
{
if (dev->_address == SPIAddress) {
if (dev->_address == SPI_ADDRESS) {
spi_contrast(dev, contrast);
} else {
i2c_contrast(dev, contrast);
@ -213,7 +213,7 @@ void ssd1306_scroll_text(SSD1306_t * dev, char * text, int text_len, bool invert
if (dev->_scEnable == false) return;
void (*func)(SSD1306_t * dev, int page, int seg, uint8_t * images, int width);
if (dev->_address == SPIAddress) {
if (dev->_address == SPI_ADDRESS) {
func = spi_display_image;
} else {
func = i2c_display_image;
@ -255,7 +255,7 @@ void ssd1306_scroll_clear(SSD1306_t * dev)
void ssd1306_hardware_scroll(SSD1306_t * dev, ssd1306_scroll_type_t scroll)
{
if (dev->_address == SPIAddress) {
if (dev->_address == SPI_ADDRESS) {
spi_hardware_scroll(dev, scroll);
} else {
i2c_hardware_scroll(dev, scroll);
@ -399,7 +399,7 @@ void ssd1306_wrap_arround(SSD1306_t * dev, ssd1306_scroll_type_t scroll, int sta
if (delay >= 0) {
for (int page=0;page<dev->_pages;page++) {
if (dev->_address == SPIAddress) {
if (dev->_address == SPI_ADDRESS) {
spi_display_image(dev, page, 0, dev->_page[page]._segs, 128);
} else {
i2c_display_image(dev, page, 0, dev->_page[page]._segs, 128);
@ -581,7 +581,7 @@ uint8_t ssd1306_rotate_byte(uint8_t ch1) {
void ssd1306_fadeout(SSD1306_t * dev)
{
void (*func)(SSD1306_t * dev, int page, int seg, uint8_t * images, int width);
if (dev->_address == SPIAddress) {
if (dev->_address == SPI_ADDRESS) {
func = spi_display_image;
} else {
func = i2c_display_image;

View File

@ -68,8 +68,8 @@ Usage:
#define OLED_CMD_ACTIVE_SCROLL 0x2F
#define OLED_CMD_VERTICAL 0xA3
#define I2CAddress 0x3C
#define SPIAddress 0xFF
#define I2C_ADDRESS 0x3C
#define SPI_ADDRESS 0xFF
typedef enum {
SCROLL_RIGHT = 1,

View File

@ -2,13 +2,13 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "esp_log.h"
#include "ssd1306.h"
#define tag "SSD1306"
#define TAG "SSD1306"
#if CONFIG_I2C_PORT_0
#define I2C_NUM I2C_NUM_0
@ -18,10 +18,12 @@
#define I2C_NUM I2C_NUM_0 // if spi is selected
#endif
#define I2C_MASTER_FREQ_HZ 400000 /*!< I2C clock of SSD1306 can run at 400 kHz max. */
#define I2C_MASTER_FREQ_HZ 400000 // I2C clock of SSD1306 can run at 400 kHz max.
#define I2C_TICKS_TO_WAIT 100 // Maximum ticks to wait before issuing a timeout.
void i2c_master_init(SSD1306_t * dev, int16_t sda, int16_t scl, int16_t reset)
{
ESP_LOGI(TAG, "Legacy i2c driver is used");
i2c_config_t i2c_config = {
.mode = I2C_MODE_MASTER,
.sda_io_num = sda,
@ -41,7 +43,7 @@ void i2c_master_init(SSD1306_t * dev, int16_t sda, int16_t scl, int16_t reset)
vTaskDelay(50 / portTICK_PERIOD_MS);
gpio_set_level(reset, 1);
}
dev->_address = I2CAddress;
dev->_address = I2C_ADDRESS;
dev->_flip = false;
}
@ -56,19 +58,19 @@ void i2c_init(SSD1306_t * dev, int width, int height) {
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (dev->_address << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);
i2c_master_write_byte(cmd, OLED_CMD_DISPLAY_OFF, true); // AE
i2c_master_write_byte(cmd, OLED_CMD_SET_MUX_RATIO, true); // A8
i2c_master_write_byte(cmd, OLED_CMD_DISPLAY_OFF, true); // AE
i2c_master_write_byte(cmd, OLED_CMD_SET_MUX_RATIO, true); // A8
if (dev->_height == 64) i2c_master_write_byte(cmd, 0x3F, true);
if (dev->_height == 32) i2c_master_write_byte(cmd, 0x1F, true);
i2c_master_write_byte(cmd, OLED_CMD_SET_DISPLAY_OFFSET, true); // D3
i2c_master_write_byte(cmd, OLED_CMD_SET_DISPLAY_OFFSET, true); // D3
i2c_master_write_byte(cmd, 0x00, true);
//i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_DATA_STREAM, true); // 40
i2c_master_write_byte(cmd, OLED_CMD_SET_DISPLAY_START_LINE, true); // 40
//i2c_master_write_byte(cmd, OLED_CMD_SET_SEGMENT_REMAP, true); // A1
if (dev->_flip) {
i2c_master_write_byte(cmd, OLED_CMD_SET_SEGMENT_REMAP_0, true); // A0
i2c_master_write_byte(cmd, OLED_CMD_SET_SEGMENT_REMAP_0, true); // A0
} else {
i2c_master_write_byte(cmd, OLED_CMD_SET_SEGMENT_REMAP_1, true); // A1
i2c_master_write_byte(cmd, OLED_CMD_SET_SEGMENT_REMAP_1, true); // A1
}
i2c_master_write_byte(cmd, OLED_CMD_SET_COM_SCAN_MODE, true); // C8
i2c_master_write_byte(cmd, OLED_CMD_SET_DISPLAY_CLK_DIV, true); // D5
@ -96,19 +98,17 @@ void i2c_init(SSD1306_t * dev, int width, int height) {
i2c_master_stop(cmd);
esp_err_t espRc = i2c_master_cmd_begin(I2C_NUM, cmd, 10/portTICK_PERIOD_MS);
if (espRc == ESP_OK) {
ESP_LOGI(tag, "OLED configured successfully");
esp_err_t res = i2c_master_cmd_begin(I2C_NUM, cmd, I2C_TICKS_TO_WAIT);
if (res == ESP_OK) {
ESP_LOGI(TAG, "OLED configured successfully");
} else {
ESP_LOGE(tag, "OLED configuration failed. code: 0x%.2X", espRc);
ESP_LOGE(TAG, "OLED configuration failed. code: 0x%.2X", res);
}
i2c_cmd_link_delete(cmd);
}
void i2c_display_image(SSD1306_t * dev, int page, int seg, uint8_t * images, int width) {
i2c_cmd_handle_t cmd;
if (page >= dev->_pages) return;
if (seg >= dev->_width) return;
@ -121,7 +121,7 @@ void i2c_display_image(SSD1306_t * dev, int page, int seg, uint8_t * images, int
_page = (dev->_pages - page) - 1;
}
cmd = i2c_cmd_link_create();
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (dev->_address << 1) | I2C_MASTER_WRITE, true);
@ -134,72 +134,78 @@ void i2c_display_image(SSD1306_t * dev, int page, int seg, uint8_t * images, int
i2c_master_write_byte(cmd, 0xB0 | _page, true);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM, cmd, 10/portTICK_PERIOD_MS);
esp_err_t res = i2c_master_cmd_begin(I2C_NUM, cmd, I2C_TICKS_TO_WAIT);
if (res != ESP_OK) {
ESP_LOGE(TAG, "Scroll command failed. code: 0x%.2X", res);
}
i2c_cmd_link_delete(cmd);
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (dev->_address << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_DATA_STREAM, true);
i2c_master_write(cmd, images, width, true);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM, cmd, 10/portTICK_PERIOD_MS);
res = i2c_master_cmd_begin(I2C_NUM, cmd, I2C_TICKS_TO_WAIT);
if (res != ESP_OK) {
ESP_LOGE(TAG, "Scroll command failed. code: 0x%.2X", res);
}
i2c_cmd_link_delete(cmd);
}
void i2c_contrast(SSD1306_t * dev, int contrast) {
i2c_cmd_handle_t cmd;
int _contrast = contrast;
if (contrast < 0x0) _contrast = 0;
if (contrast > 0xFF) _contrast = 0xFF;
cmd = i2c_cmd_link_create();
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (dev->_address << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);
i2c_master_write_byte(cmd, OLED_CMD_SET_CONTRAST, true); // 81
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true); // 00
i2c_master_write_byte(cmd, OLED_CMD_SET_CONTRAST, true); // 81
i2c_master_write_byte(cmd, _contrast, true);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM, cmd, 10/portTICK_PERIOD_MS);
esp_err_t res = i2c_master_cmd_begin(I2C_NUM, cmd, I2C_TICKS_TO_WAIT);
if (res != ESP_OK) {
ESP_LOGE(TAG, "Scroll command failed. code: 0x%.2X", res);
}
i2c_cmd_link_delete(cmd);
}
void i2c_hardware_scroll(SSD1306_t * dev, ssd1306_scroll_type_t scroll) {
esp_err_t espRc;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (dev->_address << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true); // 00
if (scroll == SCROLL_RIGHT) {
i2c_master_write_byte(cmd, OLED_CMD_HORIZONTAL_RIGHT, true); // 26
i2c_master_write_byte(cmd, OLED_CMD_HORIZONTAL_RIGHT, true); // 26
i2c_master_write_byte(cmd, 0x00, true); // Dummy byte
i2c_master_write_byte(cmd, 0x00, true); // Define start page address
i2c_master_write_byte(cmd, 0x07, true); // Frame frequency
i2c_master_write_byte(cmd, 0x07, true); // Define end page address
i2c_master_write_byte(cmd, 0x00, true); //
i2c_master_write_byte(cmd, 0xFF, true); //
i2c_master_write_byte(cmd, OLED_CMD_ACTIVE_SCROLL, true); // 2F
i2c_master_write_byte(cmd, OLED_CMD_ACTIVE_SCROLL, true); // 2F
}
if (scroll == SCROLL_LEFT) {
i2c_master_write_byte(cmd, OLED_CMD_HORIZONTAL_LEFT, true); // 27
i2c_master_write_byte(cmd, OLED_CMD_HORIZONTAL_LEFT, true); // 27
i2c_master_write_byte(cmd, 0x00, true); // Dummy byte
i2c_master_write_byte(cmd, 0x00, true); // Define start page address
i2c_master_write_byte(cmd, 0x07, true); // Frame frequency
i2c_master_write_byte(cmd, 0x07, true); // Define end page address
i2c_master_write_byte(cmd, 0x00, true); //
i2c_master_write_byte(cmd, 0xFF, true); //
i2c_master_write_byte(cmd, OLED_CMD_ACTIVE_SCROLL, true); // 2F
i2c_master_write_byte(cmd, OLED_CMD_ACTIVE_SCROLL, true); // 2F
}
if (scroll == SCROLL_DOWN) {
i2c_master_write_byte(cmd, OLED_CMD_CONTINUOUS_SCROLL, true); // 29
i2c_master_write_byte(cmd, OLED_CMD_CONTINUOUS_SCROLL, true); // 29
i2c_master_write_byte(cmd, 0x00, true); // Dummy byte
i2c_master_write_byte(cmd, 0x00, true); // Define start page address
i2c_master_write_byte(cmd, 0x07, true); // Frame frequency
@ -207,18 +213,18 @@ void i2c_hardware_scroll(SSD1306_t * dev, ssd1306_scroll_type_t scroll) {
i2c_master_write_byte(cmd, 0x00, true); // Define end page address
i2c_master_write_byte(cmd, 0x3F, true); // Vertical scrolling offset
i2c_master_write_byte(cmd, OLED_CMD_VERTICAL, true); // A3
i2c_master_write_byte(cmd, OLED_CMD_VERTICAL, true); // A3
i2c_master_write_byte(cmd, 0x00, true);
if (dev->_height == 64)
//i2c_master_write_byte(cmd, 0x7F, true);
i2c_master_write_byte(cmd, 0x40, true);
if (dev->_height == 32)
i2c_master_write_byte(cmd, 0x20, true);
i2c_master_write_byte(cmd, OLED_CMD_ACTIVE_SCROLL, true); // 2F
i2c_master_write_byte(cmd, OLED_CMD_ACTIVE_SCROLL, true); // 2F
}
if (scroll == SCROLL_UP) {
i2c_master_write_byte(cmd, OLED_CMD_CONTINUOUS_SCROLL, true); // 29
i2c_master_write_byte(cmd, OLED_CMD_CONTINUOUS_SCROLL, true); // 29
i2c_master_write_byte(cmd, 0x00, true); // Dummy byte
i2c_master_write_byte(cmd, 0x00, true); // Define start page address
i2c_master_write_byte(cmd, 0x07, true); // Frame frequency
@ -226,28 +232,26 @@ void i2c_hardware_scroll(SSD1306_t * dev, ssd1306_scroll_type_t scroll) {
i2c_master_write_byte(cmd, 0x00, true); // Define end page address
i2c_master_write_byte(cmd, 0x01, true); // Vertical scrolling offset
i2c_master_write_byte(cmd, OLED_CMD_VERTICAL, true); // A3
i2c_master_write_byte(cmd, OLED_CMD_VERTICAL, true); // A3
i2c_master_write_byte(cmd, 0x00, true);
if (dev->_height == 64)
//i2c_master_write_byte(cmd, 0x7F, true);
i2c_master_write_byte(cmd, 0x40, true);
if (dev->_height == 32)
i2c_master_write_byte(cmd, 0x20, true);
i2c_master_write_byte(cmd, OLED_CMD_ACTIVE_SCROLL, true); // 2F
i2c_master_write_byte(cmd, OLED_CMD_ACTIVE_SCROLL, true); // 2F
}
if (scroll == SCROLL_STOP) {
i2c_master_write_byte(cmd, OLED_CMD_DEACTIVE_SCROLL, true); // 2E
i2c_master_write_byte(cmd, OLED_CMD_DEACTIVE_SCROLL, true); // 2E
}
i2c_master_stop(cmd);
espRc = i2c_master_cmd_begin(I2C_NUM, cmd, 10/portTICK_PERIOD_MS);
if (espRc == ESP_OK) {
ESP_LOGD(tag, "Scroll command succeeded");
} else {
ESP_LOGE(tag, "Scroll command failed. code: 0x%.2X", espRc);
}
esp_err_t res = i2c_master_cmd_begin(I2C_NUM, cmd, I2C_TICKS_TO_WAIT);
if (res != ESP_OK) {
ESP_LOGE(TAG, "Scroll command failed. code: 0x%.2X", res);
}
i2c_cmd_link_delete(cmd);
}

View File

@ -0,0 +1,262 @@
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/i2c_master.h"
#include "esp_log.h"
#include "ssd1306.h"
#define TAG "SSD1306"
#if CONFIG_I2C_PORT_0
#define I2C_NUM I2C_NUM_0
#elif CONFIG_I2C_PORT_1
#define I2C_NUM I2C_NUM_1
#else
#define I2C_NUM I2C_NUM_0 // if spi is selected
#endif
#define I2C_MASTER_FREQ_HZ 400000 // I2C clock of SSD1306 can run at 400 kHz max.
#define I2C_TICKS_TO_WAIT 100 // Maximum ticks to wait before issuing a timeout.
i2c_master_dev_handle_t dev_handle;
void i2c_master_init(SSD1306_t * dev, int16_t sda, int16_t scl, int16_t reset)
{
ESP_LOGI(TAG, "New i2c driver is used");
i2c_master_bus_config_t i2c_mst_config = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.glitch_ignore_cnt = 7,
.i2c_port = I2C_NUM,
.scl_io_num = scl,
.sda_io_num = sda,
.flags.enable_internal_pullup = true,
};
i2c_master_bus_handle_t bus_handle;
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
i2c_device_config_t dev_cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = I2C_ADDRESS,
.scl_speed_hz = I2C_MASTER_FREQ_HZ,
};
//i2c_master_dev_handle_t dev_handle;
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
#if 0
i2c_config_t i2c_config = {
.mode = I2C_MODE_MASTER,
.sda_io_num = sda,
.scl_io_num = scl,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ
};
ESP_ERROR_CHECK(i2c_param_config(I2C_NUM, &i2c_config));
ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM, I2C_MODE_MASTER, 0, 0, 0));
#endif
if (reset >= 0) {
//gpio_pad_select_gpio(reset);
gpio_reset_pin(reset);
gpio_set_direction(reset, GPIO_MODE_OUTPUT);
gpio_set_level(reset, 0);
vTaskDelay(50 / portTICK_PERIOD_MS);
gpio_set_level(reset, 1);
}
dev->_address = I2C_ADDRESS;
dev->_flip = false;
}
void i2c_init(SSD1306_t * dev, int width, int height) {
dev->_width = width;
dev->_height = height;
dev->_pages = 8;
if (dev->_height == 32) dev->_pages = 4;
uint8_t out_buf[27];
int out_index = 0;
out_buf[out_index++] = OLED_CONTROL_BYTE_CMD_STREAM;
out_buf[out_index++] = OLED_CMD_DISPLAY_OFF; // AE
out_buf[out_index++] = OLED_CMD_SET_MUX_RATIO; // A8
if (dev->_height == 64) out_buf[out_index++] = 0x3F;
if (dev->_height == 32) out_buf[out_index++] = 0x1F;
out_buf[out_index++] = OLED_CMD_SET_DISPLAY_OFFSET; // D3
out_buf[out_index++] = 0x00;
//out_buf[out_index++] = OLED_CONTROL_BYTE_DATA_STREAM; // 40
out_buf[out_index++] = OLED_CMD_SET_DISPLAY_START_LINE; // 40
//out_buf[out_index++] = OLED_CMD_SET_SEGMENT_REMAP; // A1
if (dev->_flip) {
out_buf[out_index++] = OLED_CMD_SET_SEGMENT_REMAP_0; // A0
} else {
out_buf[out_index++] = OLED_CMD_SET_SEGMENT_REMAP_1; // A1
}
out_buf[out_index++] = OLED_CMD_SET_COM_SCAN_MODE; // C8
out_buf[out_index++] = OLED_CMD_SET_DISPLAY_CLK_DIV; // D5
out_buf[out_index++] = 0x80;
out_buf[out_index++] = OLED_CMD_SET_COM_PIN_MAP; // DA
if (dev->_height == 64) out_buf[out_index++] = 0x12;
if (dev->_height == 32) out_buf[out_index++] = 0x02;
out_buf[out_index++] = OLED_CMD_SET_CONTRAST; // 81
out_buf[out_index++] = 0xFF;
out_buf[out_index++] = OLED_CMD_DISPLAY_RAM; // A4
out_buf[out_index++] = OLED_CMD_SET_VCOMH_DESELCT; // DB
out_buf[out_index++] = 0x40;
out_buf[out_index++] = OLED_CMD_SET_MEMORY_ADDR_MODE; // 20
//out_buf[out_index++] = OLED_CMD_SET_HORI_ADDR_MODE; // 00
out_buf[out_index++] = OLED_CMD_SET_PAGE_ADDR_MODE; // 02
// Set Lower Column Start Address for Page Addressing Mode
out_buf[out_index++] = 0x00;
// Set Higher Column Start Address for Page Addressing Mode
out_buf[out_index++] = 0x10;
out_buf[out_index++] = OLED_CMD_SET_CHARGE_PUMP; // 8D
out_buf[out_index++] = 0x14;
out_buf[out_index++] = OLED_CMD_DEACTIVE_SCROLL; // 2E
out_buf[out_index++] = OLED_CMD_DISPLAY_NORMAL; // A6
out_buf[out_index++] = OLED_CMD_DISPLAY_ON; // AF
esp_err_t res;
res = i2c_master_transmit(dev_handle, out_buf, out_index, I2C_TICKS_TO_WAIT);
if (res == ESP_OK) {
ESP_LOGI(TAG, "OLED configured successfully");
} else {
ESP_LOGE(TAG, "Could not write to device [0x%02x at %d]: %d (%s)", dev->_address, I2C_NUM, res, esp_err_to_name(res));
}
}
void i2c_display_image(SSD1306_t * dev, int page, int seg, uint8_t * images, int width) {
if (page >= dev->_pages) return;
if (seg >= dev->_width) return;
int _seg = seg + CONFIG_OFFSETX;
uint8_t columLow = _seg & 0x0F;
uint8_t columHigh = (_seg >> 4) & 0x0F;
int _page = page;
if (dev->_flip) {
_page = (dev->_pages - page) - 1;
}
uint8_t *out_buf;
out_buf = malloc(width + 1);
if (out_buf == NULL) {
ESP_LOGE(TAG, "malloc fail");
return;
}
int out_index = 0;
out_buf[out_index++] = OLED_CONTROL_BYTE_CMD_STREAM;
// Set Lower Column Start Address for Page Addressing Mode
out_buf[out_index++] = (0x00 + columLow);
// Set Higher Column Start Address for Page Addressing Mode
out_buf[out_index++] = (0x10 + columHigh);
// Set Page Start Address for Page Addressing Mode
out_buf[out_index++] = 0xB0 | _page;
esp_err_t res;
res = i2c_master_transmit(dev_handle, out_buf, out_index, I2C_TICKS_TO_WAIT);
if (res != ESP_OK)
ESP_LOGE(TAG, "Could not write to device [0x%02x at %d]: %d (%s)", dev->_address, I2C_NUM, res, esp_err_to_name(res));
out_buf[0] = OLED_CONTROL_BYTE_DATA_STREAM;
memcpy(&out_buf[1], images, width);
res = i2c_master_transmit(dev_handle, out_buf, width + 1, I2C_TICKS_TO_WAIT);
if (res != ESP_OK)
ESP_LOGE(TAG, "Could not write to device [0x%02x at %d]: %d (%s)", dev->_address, I2C_NUM, res, esp_err_to_name(res));
free(out_buf);
}
void i2c_contrast(SSD1306_t * dev, int contrast) {
uint8_t _contrast = contrast;
if (contrast < 0x0) _contrast = 0;
if (contrast > 0xFF) _contrast = 0xFF;
uint8_t out_buf[3];
int out_index = 0;
out_buf[out_index++] = OLED_CONTROL_BYTE_CMD_STREAM; // 00
out_buf[out_index++] = OLED_CMD_SET_CONTRAST; // 81
out_buf[out_index++] = _contrast;
esp_err_t res = i2c_master_transmit(dev_handle, out_buf, 3, I2C_TICKS_TO_WAIT);
if (res != ESP_OK)
ESP_LOGE(TAG, "Could not write to device [0x%02x at %d]: %d (%s)", dev->_address, I2C_NUM, res, esp_err_to_name(res));
}
void i2c_hardware_scroll(SSD1306_t * dev, ssd1306_scroll_type_t scroll) {
uint8_t out_buf[11];
int out_index = 0;
out_buf[out_index++] = OLED_CONTROL_BYTE_CMD_STREAM; // 00
if (scroll == SCROLL_RIGHT) {
out_buf[out_index++] = OLED_CMD_HORIZONTAL_RIGHT; // 26
out_buf[out_index++] = 0x00; // Dummy byte
out_buf[out_index++] = 0x00; // Define start page address
out_buf[out_index++] = 0x07; // Frame frequency
out_buf[out_index++] = 0x07; // Define end page address
out_buf[out_index++] = 0x00; //
out_buf[out_index++] = 0xFF; //
out_buf[out_index++] = OLED_CMD_ACTIVE_SCROLL; // 2F
}
if (scroll == SCROLL_LEFT) {
out_buf[out_index++] = OLED_CMD_HORIZONTAL_LEFT; // 27
out_buf[out_index++] = 0x00; // Dummy byte
out_buf[out_index++] = 0x00; // Define start page address
out_buf[out_index++] = 0x07; // Frame frequency
out_buf[out_index++] = 0x07; // Define end page address
out_buf[out_index++] = 0x00; //
out_buf[out_index++] = 0xFF; //
out_buf[out_index++] = OLED_CMD_ACTIVE_SCROLL; // 2F
}
if (scroll == SCROLL_DOWN) {
out_buf[out_index++] = OLED_CMD_CONTINUOUS_SCROLL; // 29
out_buf[out_index++] = 0x00; // Dummy byte
out_buf[out_index++] = 0x00; // Define start page address
out_buf[out_index++] = 0x07; // Frame frequency
//out_buf[out_index++] = 0x01; // Define end page address
out_buf[out_index++] = 0x00; // Define end page address
out_buf[out_index++] = 0x3F; // Vertical scrolling offset
out_buf[out_index++] = OLED_CMD_VERTICAL; // A3
out_buf[out_index++] = 0x00;
if (dev->_height == 64)
//out_buf[out_index++] = 0x7F;
out_buf[out_index++] = 0x40;
if (dev->_height == 32)
out_buf[out_index++] = 0x20;
out_buf[out_index++] = OLED_CMD_ACTIVE_SCROLL; // 2F
}
if (scroll == SCROLL_UP) {
out_buf[out_index++] = OLED_CMD_CONTINUOUS_SCROLL; // 29
out_buf[out_index++] = 0x00; // Dummy byte
out_buf[out_index++] = 0x00; // Define start page address
out_buf[out_index++] = 0x07; // Frame frequency
//out_buf[out_index++] = 0x01; // Define end page address
out_buf[out_index++] = 0x00; // Define end page address
out_buf[out_index++] = 0x01; // Vertical scrolling offset
out_buf[out_index++] = OLED_CMD_VERTICAL; // A3
out_buf[out_index++] = 0x00;
if (dev->_height == 64)
//out_buf[out_index++] = 0x7F;
out_buf[out_index++] = 0x40;
if (dev->_height == 32)
out_buf[out_index++] = 0x20;
out_buf[out_index++] = OLED_CMD_ACTIVE_SCROLL; // 2F
}
if (scroll == SCROLL_STOP) {
out_buf[out_index++] = OLED_CMD_DEACTIVE_SCROLL; // 2E
}
esp_err_t res = i2c_master_transmit(dev_handle, out_buf, 3, I2C_TICKS_TO_WAIT);
if (res != ESP_OK)
ESP_LOGE(TAG, "Could not write to device [0x%02x at %d]: %d (%s)", dev->_address, I2C_NUM, res, esp_err_to_name(res));
}

View File

@ -2,7 +2,6 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "esp_log.h"
@ -19,26 +18,23 @@
#define HOST_ID SPI2_HOST // If i2c is selected
#endif
static const int SPI_Command_Mode = 0;
static const int SPI_Data_Mode = 1;
static const int SPI_Frequency = 1000000; // 1MHz
#define SPI_COMMAND_MODE 0
#define SPI_DATA_MODE 1
#define SPI_FREQUENCY 1000000; // 1MHz
void spi_master_init(SSD1306_t * dev, int16_t GPIO_MOSI, int16_t GPIO_SCLK, int16_t GPIO_CS, int16_t GPIO_DC, int16_t GPIO_RESET)
{
esp_err_t ret;
//gpio_pad_select_gpio( GPIO_CS );
gpio_reset_pin( GPIO_CS );
gpio_set_direction( GPIO_CS, GPIO_MODE_OUTPUT );
gpio_set_level( GPIO_CS, 0 );
//gpio_pad_select_gpio( GPIO_DC );
gpio_reset_pin( GPIO_DC );
gpio_set_direction( GPIO_DC, GPIO_MODE_OUTPUT );
gpio_set_level( GPIO_DC, 0 );
if ( GPIO_RESET >= 0 ) {
//gpio_pad_select_gpio( GPIO_RESET );
gpio_reset_pin( GPIO_RESET );
gpio_set_direction( GPIO_RESET, GPIO_MODE_OUTPUT );
gpio_set_level( GPIO_RESET, 0 );
@ -63,7 +59,7 @@ void spi_master_init(SSD1306_t * dev, int16_t GPIO_MOSI, int16_t GPIO_SCLK, int1
spi_device_interface_config_t devcfg;
memset( &devcfg, 0, sizeof( spi_device_interface_config_t ) );
devcfg.clock_speed_hz = SPI_Frequency;
devcfg.clock_speed_hz = SPI_FREQUENCY;
devcfg.spics_io_num = GPIO_CS;
devcfg.queue_size = 1;
@ -73,7 +69,7 @@ void spi_master_init(SSD1306_t * dev, int16_t GPIO_MOSI, int16_t GPIO_SCLK, int1
assert(ret==ESP_OK);
dev->_dc = GPIO_DC;
dev->_SPIHandle = handle;
dev->_address = SPIAddress;
dev->_address = SPI_ADDRESS;
dev->_flip = false;
}
@ -96,13 +92,13 @@ bool spi_master_write_command(SSD1306_t * dev, uint8_t Command )
{
static uint8_t CommandByte = 0;
CommandByte = Command;
gpio_set_level( dev->_dc, SPI_Command_Mode );
gpio_set_level( dev->_dc, SPI_COMMAND_MODE );
return spi_master_write_byte( dev->_SPIHandle, &CommandByte, 1 );
}
bool spi_master_write_data(SSD1306_t * dev, const uint8_t* Data, size_t DataLength )
{
gpio_set_level( dev->_dc, SPI_Data_Mode );
gpio_set_level( dev->_dc, SPI_DATA_MODE );
return spi_master_write_byte( dev->_SPIHandle, Data, DataLength );
}