esp-idf-ssd1306/components/ssd1306/ssd1306_i2c_new.c
2024-09-12 08:00:14 +09:00

291 lines
9.7 KiB
C

#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.
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 i2c_dev_handle;
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &i2c_dev_handle));
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;
dev->_i2c_num = I2C_NUM;
dev->_i2c_dev_handle = i2c_dev_handle;
}
void i2c_bus_add(SSD1306_t * dev, i2c_master_bus_handle_t bus_handle, i2c_port_t i2c_num, int16_t reset)
{
ESP_LOGI(TAG, "New i2c driver is used");
ESP_LOGW(TAG, "Will not install i2c master driver");
#if 0
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));
#endif
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 i2c_dev_handle;
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &i2c_dev_handle));
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;
dev->_i2c_num = i2c_num;
dev->_i2c_dev_handle = i2c_dev_handle;
}
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->_i2c_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, dev->_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->_i2c_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, dev->_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->_i2c_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, dev->_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->_i2c_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, dev->_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->_i2c_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, dev->_i2c_num, res, esp_err_to_name(res));
}