mirror of
https://github.com/BotChain-Robots/firmware.git
synced 2026-07-08 17:47:21 +02:00
160 lines
4.8 KiB
C++
160 lines
4.8 KiB
C++
|
|
#include <string>
|
|
|
|
#include "driver/gpio.h"
|
|
#include "driver/i2c.h"
|
|
#include "esp_err.h"
|
|
#include "esp_log.h"
|
|
#include "Oled.h"
|
|
#include "font8x8_basic.h"
|
|
#include "ssd1306.h"
|
|
|
|
#define TAG "OLED"
|
|
|
|
// 128x64 pixels
|
|
// 8 pixels per byte
|
|
// 128 bytes per page -> ((128*64)/8)/128 = 8 pages.
|
|
#define DISPLAY_WIDTH 128
|
|
#define DISPLAY_HEIGHT 64
|
|
#define PAGE_SIZE 128
|
|
#define PAGE_COUNT 8
|
|
#define I2C_PORT I2C_NUM_0
|
|
|
|
void Oled::init(uint8_t sda_pin, uint8_t scl_pin) {
|
|
i2c_config_t i2c_config = {
|
|
.mode = I2C_MODE_MASTER,
|
|
.sda_io_num = sda_pin,
|
|
.scl_io_num = scl_pin,
|
|
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
|
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
|
.master = {
|
|
.clk_speed = 1000000
|
|
},
|
|
.clk_flags = 0,
|
|
};
|
|
i2c_param_config(I2C_PORT, &i2c_config);
|
|
|
|
i2c_driver_install(I2C_PORT, I2C_MODE_MASTER, 0, 0, 0);
|
|
|
|
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
|
i2c_master_start(cmd);
|
|
i2c_master_write_byte(cmd, (OLED_I2C_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_CHARGE_PUMP, true);
|
|
i2c_master_write_byte(cmd, 0x14, true);
|
|
i2c_master_write_byte(cmd, OLED_CMD_SET_SEGMENT_REMAP, true);
|
|
i2c_master_write_byte(cmd, OLED_CMD_SET_COM_SCAN_MODE, true);
|
|
i2c_master_write_byte(cmd, OLED_CMD_DISPLAY_ON, true);
|
|
i2c_master_stop(cmd);
|
|
|
|
if (ESP_OK != i2c_master_cmd_begin(I2C_PORT, cmd, 10 / portTICK_PERIOD_MS)) {
|
|
ESP_LOGE(TAG, "configuration failed");
|
|
}
|
|
|
|
i2c_cmd_link_delete(cmd);
|
|
|
|
clear_display();
|
|
}
|
|
|
|
void Oled::clear_display() {
|
|
ESP_LOGI(TAG, "clear_display");
|
|
i2c_cmd_handle_t cmd;
|
|
|
|
uint8_t page[PAGE_SIZE] = {0};
|
|
for (uint8_t i = 0; i < PAGE_COUNT; i++) {
|
|
cmd = i2c_cmd_link_create();
|
|
i2c_master_start(cmd);
|
|
i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);
|
|
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_SINGLE, true);
|
|
i2c_master_write_byte(cmd, 0xB0 | i, true);
|
|
|
|
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_DATA_STREAM, true);
|
|
i2c_master_write(cmd, page, PAGE_SIZE, true);
|
|
i2c_master_stop(cmd);
|
|
i2c_master_cmd_begin(I2C_PORT, cmd, 10 / portTICK_PERIOD_MS);
|
|
i2c_cmd_link_delete(cmd);
|
|
}
|
|
}
|
|
|
|
void Oled::set_contrast(uint8_t contrast) {
|
|
i2c_cmd_handle_t cmd;
|
|
cmd = i2c_cmd_link_create();
|
|
i2c_master_start(cmd);
|
|
i2c_master_write_byte(cmd, (OLED_I2C_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);
|
|
i2c_master_write_byte(cmd, contrast, true);
|
|
i2c_master_stop(cmd);
|
|
i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS);
|
|
i2c_cmd_link_delete(cmd);
|
|
}
|
|
|
|
void Oled::display_text(const std::string& text) {
|
|
ESP_LOGI(TAG, "display_text %s", text.c_str());
|
|
i2c_cmd_handle_t cmd;
|
|
|
|
uint8_t cur_page = 0;
|
|
uint8_t col = 0;
|
|
auto col_width = DISPLAY_WIDTH / 8; // using an 8x8 font
|
|
auto num_rows = DISPLAY_HEIGHT / 8; // using an 8x8 font
|
|
auto max_size = col_width * num_rows;
|
|
|
|
cmd = i2c_cmd_link_create();
|
|
i2c_master_start(cmd);
|
|
i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);
|
|
|
|
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);
|
|
i2c_master_write_byte(cmd, 0x00, true); // reset column
|
|
i2c_master_write_byte(cmd, 0x10, true);
|
|
i2c_master_write_byte(cmd, 0xB0 | cur_page, true); // reset page
|
|
|
|
i2c_master_stop(cmd);
|
|
i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS);
|
|
i2c_cmd_link_delete(cmd);
|
|
|
|
for (uint8_t i = 0; i < text.size() && i < max_size; i++) {
|
|
ESP_LOGI(TAG, "%d: %c", i, text[i]);
|
|
if (text[i] == '\n' || col >= col_width) {
|
|
ESP_LOGI(TAG, "new line");
|
|
cmd = i2c_cmd_link_create();
|
|
i2c_master_start(cmd);
|
|
i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);
|
|
|
|
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);
|
|
i2c_master_write_byte(cmd, 0x00, true); // reset column
|
|
i2c_master_write_byte(cmd, 0x10, true);
|
|
i2c_master_write_byte(cmd, 0xB0 | ++cur_page, true); // increment page
|
|
|
|
i2c_master_stop(cmd);
|
|
i2c_master_cmd_begin(I2C_NUM_0, cmd, 10/portTICK_PERIOD_MS);
|
|
i2c_cmd_link_delete(cmd);
|
|
col = 0;
|
|
} else {
|
|
cmd = i2c_cmd_link_create();
|
|
i2c_master_start(cmd);
|
|
i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);
|
|
|
|
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_DATA_STREAM, true);
|
|
uint8_t rotated[8];
|
|
rotate8x8((uint8_t*)font8x8_basic[(uint8_t)text[i]], rotated);
|
|
i2c_master_write(cmd, rotated, 8, true);
|
|
|
|
i2c_master_stop(cmd);
|
|
i2c_master_cmd_begin(I2C_NUM_0, cmd, 10/portTICK_PERIOD_MS);
|
|
i2c_cmd_link_delete(cmd);
|
|
col++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Oled::rotate8x8(uint8_t in[8], uint8_t out[8]) {
|
|
for (int x = 0; x < 8; x++) {
|
|
out[x] = 0;
|
|
for (int y = 0; y < 8; y++) {
|
|
if (in[y] & (1 << x)) {
|
|
out[x] |= (1 << (7 - y));
|
|
}
|
|
}
|
|
}
|
|
}
|