#include <stdio.h>
#include "esp_log.h"
#include "driver/i2c.h"
#include "ani.c"
#include <string.h>
//https://triwahyu45.github.io/ESP32-OLED-Video-Converter/
#define u32 unsigned int
#define OLED_CLK_FREQ 1000000
#define OLED_SDA GPIO_NUM_21
#define OLED_SCL GPIO_NUM_22
#define OLED_I2C_ADDR 0x3C
#define OLED_WR_ADDR ((OLED_I2C_ADDR << 1) | I2C_MASTER_WRITE)
#define OLED_RD_ADDR ((OLED_I2C_ADDR << 1) | I2C_MASTER_READ)
#define HEIGHT 64
#define WIDTH 128
#define FRAME_COUNT (sizeof(frames) / sizeof(frames[0]))
uint8_t buffer[1024];
static const char *TAG = "OLED";
extern const unsigned char frames[][1024];
i2c_cmd_handle_t oledhandle = NULL;
void resetCursor(void);
void f_inti_i2c(void)
{
i2c_config_t i2c_conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = OLED_SDA,
.scl_io_num = OLED_SCL,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = OLED_CLK_FREQ
};
i2c_param_config(0, &i2c_conf);
i2c_driver_install(0, i2c_conf.mode, 0, 0, 0);
}
void f_init_oled(void) {
oledhandle = i2c_cmd_link_create();
if (oledhandle == NULL)
{
ESP_LOGI(TAG, "Not enough memory");
while (true)
{
ESP_LOGI(TAG, ".");
}
}
ESP_ERROR_CHECK(i2c_master_start(oledhandle));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, OLED_WR_ADDR, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x00, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0xAE, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0xD5, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x80, true));//F0
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0xA8, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x3F, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0xD3, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x00, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x40, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x8D, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x14, true));
//Set memory addressing Mode
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x20, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x00, true));
//Set pade start address: selects page 0
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0xB0, true));
//Set COM output scan direction: 0xC8 (vertically flipped): Most OLED modules are mounted upside down internally
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0xC8, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0xA1, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x22, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x00, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x07, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x22, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x00, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x07, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0xDA, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x12, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x81, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x7F, true));//FF
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0xD9, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0xF1, true));//22
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0xDB, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x20, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0xA4, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0xA6, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x2E, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0xAF, true));
//set addressing mode
//Configure display timings & panel size
//Map segment & COM directions
//Configure power & contrast
//Turn the display ON
ESP_ERROR_CHECK(i2c_master_stop(oledhandle));
ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM_0, oledhandle, 50 / portTICK_PERIOD_MS));
i2c_cmd_link_delete(oledhandle);
}
void clearBuffer(void)
{
for (int i = 0; i < 1024; i++)
{
buffer[i] = 0x00;
}
}
void bufToScreen(void)
{
oledhandle = i2c_cmd_link_create();
if (oledhandle == NULL)
{
ESP_LOGI(TAG, "Not enough memory");
while (true)
{
ESP_LOGI(TAG, ".");
}
}
ESP_ERROR_CHECK(i2c_master_start(oledhandle));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, OLED_WR_ADDR, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x40, true)); // control byte
ESP_ERROR_CHECK(i2c_master_write(oledhandle, buffer, 1024, true));
ESP_ERROR_CHECK(i2c_master_stop(oledhandle));
ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM_0, oledhandle, 50 / portTICK_PERIOD_MS));
i2c_cmd_link_delete(oledhandle);
}
void convertBitmapToSSD1306(const uint8_t *src, uint8_t *dst)
{
memset(dst, 0, 1024);
for (int y = 0; y < 64; y++) {
for (int x = 0; x < 128; x++) {
int byteIndex = y * (128 / 8) + (x / 8);
int bitIndex = 7 - (x % 8);
int pixel = (src[byteIndex] >> bitIndex) & 0x01;
if (pixel) {
int page = y / 8;
int shift = y % 8;
dst[page * 128 + x] |= (1 << shift);
}
}
}
}
void directToScreenAnimation(const unsigned char myAnimationBuf[][1024], int frames)
{
for (int i = 0; i < frames; i++) // change with the number of frames
{
resetCursor();
convertBitmapToSSD1306(myAnimationBuf[i], buffer);
oledhandle = i2c_cmd_link_create();
if (oledhandle == NULL)
{
ESP_LOGI(TAG, "Not enough memory");
while (true)
{
ESP_LOGI(TAG, ".");
}
}
ESP_ERROR_CHECK(i2c_master_start(oledhandle));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, OLED_WR_ADDR, true));
ESP_ERROR_CHECK(i2c_master_write_byte(oledhandle, 0x40, true)); // control byte
ESP_ERROR_CHECK(i2c_master_write(oledhandle, buffer, 1024, true));
ESP_ERROR_CHECK(i2c_master_stop(oledhandle));
ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM_0, oledhandle, 50 / portTICK_PERIOD_MS));
i2c_cmd_link_delete(oledhandle);
//vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
void resetCursor(void) {
oledhandle = i2c_cmd_link_create();
i2c_master_start(oledhandle);
i2c_master_write_byte(oledhandle, OLED_WR_ADDR, true);
i2c_master_write_byte(oledhandle, 0x00, true); // command mode
// Set column address: 0 to 127
i2c_master_write_byte(oledhandle, 0x21, true);
i2c_master_write_byte(oledhandle, 0x00, true); // start column
i2c_master_write_byte(oledhandle, 0x7F, true); // end column
// Set page address: 0 to 7
i2c_master_write_byte(oledhandle, 0x22, true);
i2c_master_write_byte(oledhandle, 0x00, true); // start page
i2c_master_write_byte(oledhandle, 0x07, true); // end page
i2c_master_stop(oledhandle);
i2c_master_cmd_begin(I2C_NUM_0, oledhandle, 50 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(oledhandle);
}
void app_main() {
f_inti_i2c();
f_init_oled();
vTaskDelay(1000 / portTICK_PERIOD_MS);
clearBuffer();
bufToScreen();
while (true) {
directToScreenAnimation(frames, FRAME_COUNT);
//vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}