Compare commits

...

10 Commits

Author SHA1 Message Date
Elias Ahokas
c2aabfd227 Cleanup 2025-10-18 20:24:36 +03:00
Elias Ahokas
224a354394 add README 2025-10-18 20:03:52 +03:00
Elias Ahokas
f005fcf1c7 modify gitignore 2025-10-18 19:46:40 +03:00
Elias Ahokas
936b27116e bigger font 2025-10-17 23:56:10 +03:00
Elias Ahokas
de8b0d663b SPEEEED 2025-10-17 23:46:35 +03:00
Elias Ahokas
77d2aa09ec fix byte offset 2025-10-17 23:25:26 +03:00
Elias Ahokas
e1aa89982d WORKING ::o 2025-10-17 21:48:12 +03:00
Elias Ahokas
75ca356f1c counter workings 2025-10-17 21:38:35 +03:00
Elias Ahokas
b93cf777a5 works :O with glitches 2025-10-17 20:20:07 +03:00
Elias Ahokas
4e1502357c kinda working 2025-10-17 20:08:58 +03:00
9 changed files with 102 additions and 285 deletions

View File

@@ -1,13 +0,0 @@
ARG DOCKER_TAG=latest
FROM espressif/idf:${DOCKER_TAG}
ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8
RUN apt-get update -y && apt-get install udev -y
RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc
ENTRYPOINT [ "/opt/esp/entrypoint.sh" ]
CMD ["/bin/bash", "-c"]

View File

@@ -1,21 +0,0 @@
{
"name": "ESP-IDF QEMU",
"build": {
"dockerfile": "Dockerfile"
},
"customizations": {
"vscode": {
"settings": {
"terminal.integrated.defaultProfile.linux": "bash",
"idf.espIdfPath": "/opt/esp/idf",
"idf.toolsPath": "/opt/esp",
"idf.gitPath": "/usr/bin/git"
},
"extensions": [
"espressif.esp-idf-extension",
"espressif.esp-idf-web"
]
}
},
"runArgs": ["--privileged"]
}

12
.gitignore vendored
View File

@@ -1,3 +1,9 @@
build/ *
sdkconfig !*/
sdkconfig.old !components/**
!main/**
!.gitignore
!.gitmodules
!CMakeLists.txt
!dependencies.lock
!README.md

View File

@@ -1,23 +0,0 @@
{
"configurations": [
{
"name": "ESP-IDF",
"compilerPath": "${config:idf.toolsPath}/tools/xtensa-esp-elf/esp-14.2.0_20241119/xtensa-esp-elf/bin/xtensa-esp32-elf-gcc",
"compileCommands": "${config:idf.buildPath}/compile_commands.json",
"includePath": [
"${config:idf.espIdfPath}/components/**",
"${config:idf.espIdfPathWin}/components/**",
"${workspaceFolder}/**"
],
"browse": {
"path": [
"${config:idf.espIdfPath}/components",
"${config:idf.espIdfPathWin}/components",
"${workspaceFolder}"
],
"limitSymbolsToIncludedHeaders": true
}
}
],
"version": 4
}

15
.vscode/launch.json vendored
View File

@@ -1,15 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "gdbtarget",
"request": "attach",
"name": "Eclipse CDT GDB Adapter"
},
{
"type": "espidf",
"name": "Launch",
"request": "launch"
}
]
}

14
.vscode/settings.json vendored
View File

@@ -1,14 +0,0 @@
{
"C_Cpp.intelliSenseEngine": "default",
"idf.espIdfPath": "/home/sirian/esp/esp-idf",
"idf.pythonInstallPath": "/usr/bin/python3",
"idf.openOcdConfigs": [
"board/esp32-wrover-kit-3.3v.cfg"
],
"idf.port": "/dev/ttyS1",
"idf.toolsPath": "/home/sirian/.espressif",
"idf.customExtraVars": {
"IDF_TARGET": "esp32"
},
"idf.flashType": "UART"
}

View File

@@ -1,32 +1,11 @@
# _Sample project_ # OLED display counter
(See the README.md file in the upper level 'examples' directory for more information about examples.) A simple counter on an oled display.
This is the simplest buildable example. The example is used by command `idf.py create-project` ## References
that copies the project to user specified path and set it's name. For more information follow the [docs page](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#start-a-new-project)
- [Esp32 programming guide](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/get-started/index.html)
- [Esp32 datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-wroom-32d_esp32-wroom-32u_datasheet_en.pdf)
- [SSD1306 datasheet](https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf)
- [lvgl programming guide](https://docs.lvgl.io/master/intro/introduction/index.html)
## How to use example
We encourage the users to use the example as a template for the new projects.
A recommended way is to follow the instructions on a [docs page](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#start-a-new-project).
## Example folder contents
The project **sample_project** contains one source file in C language [main.c](main/main.c). The file is located in folder [main](main).
ESP-IDF projects are built using CMake. The project build configuration is contained in `CMakeLists.txt`
files that provide set of directives and instructions describing the project's source files and targets
(executable, library, or both).
Below is short explanation of remaining files in the project folder.
```
├── CMakeLists.txt
├── main
│   ├── CMakeLists.txt
│   └── main.c
└── README.md This is the file you are currently reading
```
Additionally, the sample project contains Makefile and component.mk files, used for the legacy Make based build system.
They are not used or needed when building with CMake and idf.py.

View File

@@ -28,8 +28,6 @@
/** Color depth: 1 (I1), 8 (L8), 16 (RGB565), 24 (RGB888), 32 (XRGB8888) */ /** Color depth: 1 (I1), 8 (L8), 16 (RGB565), 24 (RGB888), 32 (XRGB8888) */
#define LV_COLOR_DEPTH 1 #define LV_COLOR_DEPTH 1
#define LV_COLOR_1_BYTE 1
#define LV_USE_THEME_MONO 1
/*========================= /*=========================
STDLIB WRAPPER SETTINGS STDLIB WRAPPER SETTINGS
@@ -45,7 +43,7 @@
#define LV_USE_STDLIB_MALLOC LV_STDLIB_BUILTIN #define LV_USE_STDLIB_MALLOC LV_STDLIB_BUILTIN
/** Possible values /** Possible values
* - LV_STDLIB_BUILTIN: LVGL's built in implementation * - LV_STDLIB_BUlILTIN: LVGL's built in implementation
* - LV_STDLIB_CLIB: Standard C functions, like malloc, strlen, etc * - LV_STDLIB_CLIB: Standard C functions, like malloc, strlen, etc
* - LV_STDLIB_MICROPYTHON: MicroPython implementation * - LV_STDLIB_MICROPYTHON: MicroPython implementation
* - LV_STDLIB_RTTHREAD: RT-Thread implementation * - LV_STDLIB_RTTHREAD: RT-Thread implementation
@@ -611,7 +609,7 @@
#define LV_FONT_MONTSERRAT_18 0 #define LV_FONT_MONTSERRAT_18 0
#define LV_FONT_MONTSERRAT_20 0 #define LV_FONT_MONTSERRAT_20 0
#define LV_FONT_MONTSERRAT_22 0 #define LV_FONT_MONTSERRAT_22 0
#define LV_FONT_MONTSERRAT_24 0 #define LV_FONT_MONTSERRAT_24 1
#define LV_FONT_MONTSERRAT_26 0 #define LV_FONT_MONTSERRAT_26 0
#define LV_FONT_MONTSERRAT_28 0 #define LV_FONT_MONTSERRAT_28 0
#define LV_FONT_MONTSERRAT_30 0 #define LV_FONT_MONTSERRAT_30 0
@@ -621,7 +619,7 @@
#define LV_FONT_MONTSERRAT_38 0 #define LV_FONT_MONTSERRAT_38 0
#define LV_FONT_MONTSERRAT_40 0 #define LV_FONT_MONTSERRAT_40 0
#define LV_FONT_MONTSERRAT_42 0 #define LV_FONT_MONTSERRAT_42 0
#define LV_FONT_MONTSERRAT_44 0 #define LV_FONT_MONTSERRAT_44 1
#define LV_FONT_MONTSERRAT_46 0 #define LV_FONT_MONTSERRAT_46 0
#define LV_FONT_MONTSERRAT_48 0 #define LV_FONT_MONTSERRAT_48 0

View File

@@ -5,25 +5,20 @@
#include "freertos/task.h" #include "freertos/task.h"
#define LV_CONF_INCLUDE_SIMPLE 1 #define LV_CONF_INCLUDE_SIMPLE 1
#include "lv_conf.h" #include "lv_conf.h"
#include "lvgl.h" #include "lvgl.h"
#define I2C_SCL 19 #define I2C_SCL 19
#define I2C_SDA 21 #define I2C_SDA 21
/* Docs: https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf */
#define DISP_ADDRESS 0X3c #define DISP_ADDRESS 0X3c
#define I2C_FREQ 100000 #define I2C_FREQ 400000
static i2c_master_dev_handle_t disp_handle; static i2c_master_dev_handle_t disp_handle;
static lv_obj_t *counter_label; static lv_obj_t *counter_label;
static SemaphoreHandle_t flush_sem = NULL; static SemaphoreHandle_t flush_sem = NULL;
static uint8_t lv_buf[(128 * 64/8)+8];
static lv_color_t lv_buf[128 * 64];
void init_i2c(void){ void init_i2c(void){
i2c_master_bus_config_t i2c_mst_config = { i2c_master_bus_config_t i2c_mst_config = {
@@ -44,7 +39,7 @@ void init_i2c(void){
.scl_speed_hz = I2C_FREQ, .scl_speed_hz = I2C_FREQ,
}; };
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &disp_handle)); i2c_master_bus_add_device(bus_handle, &dev_cfg, &disp_handle);
} }
@@ -54,28 +49,16 @@ void i2c_disp_send_cmd(uint8_t cmd){
i2c_master_transmit(disp_handle, data, sizeof(data), pdMS_TO_TICKS(1000)); i2c_master_transmit(disp_handle, data, sizeof(data), pdMS_TO_TICKS(1000));
vTaskDelay(pdMS_TO_TICKS(1));
} }
/*void i2c_disp_send_data(uint8_t *data, size_t len){
uint8_t *buf = malloc(len + 1);
buf[0] = 0x40; data mode
memcpy(&buf[1], data, len);
ESP_ERROR_CHECK(
i2c_master_transmit(disp_handle, buf, len + 1, pdMS_TO_TICKS(100)));
free(buf);
}*/
void i2c_disp_send_data(uint8_t *data, size_t len){ void i2c_disp_send_data(uint8_t *data, size_t len){
uint8_t *buf = malloc(len+1); uint8_t *buf = malloc(len+1);
buf[0] = 0x40; buf[0] = 0x40; /*data mode*/
memcpy(&buf[1], data, len); memcpy(&buf[1], data, len);
esp_err_t ret = i2c_master_transmit(disp_handle, buf, len+1, pdMS_TO_TICKS(2000));
free(buf);
return;
i2c_master_transmit(disp_handle, buf, len+1, pdMS_TO_TICKS(2000));
free(buf);
} }
void init_display(void){ void init_display(void){
@@ -99,8 +82,8 @@ void init_display(void){
i2c_disp_send_cmd(0x20); // Set Memory Addressing Mode i2c_disp_send_cmd(0x20); // Set Memory Addressing Mode
i2c_disp_send_cmd(0x00); // Horizontal addressing mode i2c_disp_send_cmd(0x00); // Horizontal addressing mode
i2c_disp_send_cmd(0xA0); // Set segment re-map (A0h/A1h) i2c_disp_send_cmd(0xA1); // Set segment re-map (A0h/A1h)
i2c_disp_send_cmd(0xC0); // Set COM output scan direction i2c_disp_send_cmd(0xC8); // Set COM output scan direction
i2c_disp_send_cmd(0xDA); // Set COM pins hardware configuration i2c_disp_send_cmd(0xDA); // Set COM pins hardware configuration
i2c_disp_send_cmd(0x12); // Alternative COM pin config i2c_disp_send_cmd(0x12); // Alternative COM pin config
@@ -122,56 +105,60 @@ void init_display(void){
i2c_disp_send_cmd(0xAF); // Display ON i2c_disp_send_cmd(0xAF); // Display ON
} }
void lvgl_flush_callback(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map) void lvgl_flush_callback(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map){
{
printf("FLUSH CALLED! area: (%ld,%ld)-(%ld,%ld)\n", (long)area->x1, (long)area->y1, (long)area->x2, (long)area->y2);
if (flush_sem == NULL) if (flush_sem == NULL){
{
lv_display_flush_ready(disp); lv_display_flush_ready(disp);
return; return;
} }
xSemaphoreTake(flush_sem, portMAX_DELAY); xSemaphoreTake(flush_sem, portMAX_DELAY);
uint16_t width = 128; uint16_t width = 128;
uint16_t height = 64; uint16_t height = 64;
uint16_t pages = height/8;
static uint8_t buf[128*8]; uint8_t buf[128];
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
uint8_t *pixels = px_map; uint16_t bytes = (width * height + 7) / 8;
uint16_t bytes_per_row = width / 8;
uint16_t bytes_per_page = bytes_per_row*8;
uint8_t page = 0;
uint8_t page_x = 0;
uint8_t page_y = 0;
uint8_t byte;
printf("Center pixels (64,32): %d %d %d %d\n", px_map += 8;
pixels[32 * 128 + 62], pixels[32 * 128 + 63],
pixels[32 * 128 + 64], pixels[32 * 128 + 65]);
for(uint8_t page = 0; page < pages; page++){ /*converted pixels to page format*/
for(uint16_t x = 0; x < width; x++){ for (uint16_t i = 0; i <= bytes; i++){
byte = px_map[i];
uint8_t byte = 0; for (int bit = 7; bit >= 0; bit--){
for(uint8_t bit = 0; bit < 8; bit++){ if (byte & (1 << bit)){
uint16_t y = page*8 + bit; buf[page_x] |= (1 << page_y);
if(pixels[y*width+x] != 0){
byte |= (1<<bit);
} }
++page_x;
} }
buf[page*width+x] = byte; if ((i+1) % bytes_per_row == 0 && i+1 != 0){
page_y++;
page_x = 0;
} }
} if((i+1)% bytes_per_page == 0 && i+1 != 0){
/*page finished => send to display*/
i2c_disp_send_cmd(0x21); i2c_disp_send_cmd(0x21);
i2c_disp_send_cmd(0); i2c_disp_send_cmd(0);
i2c_disp_send_cmd(width-1); i2c_disp_send_cmd(127);
i2c_disp_send_cmd(0x22); i2c_disp_send_cmd(0x22);
i2c_disp_send_cmd(0); i2c_disp_send_cmd(page);
i2c_disp_send_cmd(pages-1); i2c_disp_send_cmd(page);
i2c_disp_send_data(buf, sizeof(buf)); i2c_disp_send_data(buf, sizeof(buf));
memset(buf, 0, sizeof(buf));
page++;
page_y = 0;
}
}
lv_display_flush_ready(disp); lv_display_flush_ready(disp);
xSemaphoreGive(flush_sem); xSemaphoreGive(flush_sem);
@@ -183,17 +170,21 @@ void init_graphics(void){
xSemaphoreGive(flush_sem); xSemaphoreGive(flush_sem);
} }
lv_init(); memset(lv_buf, 0, sizeof(lv_buf));
printf("LVGL initialized\n");
printf("LV_COLOR_DEPTH = %d\n", LV_COLOR_DEPTH); lv_init();
lv_display_t *display = lv_display_create(128, 64); lv_display_t *display = lv_display_create(128, 64);
printf("Display created\n"); lv_display_set_color_format(display, LV_COLOR_FORMAT_I1);
lv_display_set_flush_cb(display, lvgl_flush_callback); lv_display_set_flush_cb(display, lvgl_flush_callback);
printf("Flush callback set\n");
lv_display_set_buffers(display, lv_buf, NULL, sizeof(lv_buf), LV_DISPLAY_RENDER_MODE_FULL); lv_display_set_buffers(display, lv_buf, NULL, sizeof(lv_buf), LV_DISPLAY_RENDER_MODE_FULL);
printf("lvgl buffers set");
lv_obj_t *scr = lv_screen_active();
lv_obj_set_style_bg_color(scr, lv_color_black(), 0);
lv_obj_set_style_bg_opa(scr, LV_OPA_COVER, 0);
} }
@@ -207,7 +198,7 @@ void lv_tick_task(void *arg){
void lv_task(void *arg){ void lv_task(void *arg){
while(1){ while(1){
lv_task_handler(); lv_task_handler();
vTaskDelay(pdMS_TO_TICKS(10)); vTaskDelay(pdMS_TO_TICKS(50));
} }
} }
@@ -226,115 +217,44 @@ void counter_task(void *arg){
counter++; counter++;
} }
vTaskDelay(pdMS_TO_TICKS(1000)); vTaskDelay(pdMS_TO_TICKS(100));
} }
} }
void create_counter(void){ void create_counter(void){
lv_obj_t *scr = lv_scr_act(); lv_obj_t *scr = lv_scr_act();
lv_obj_set_style_bg_color(scr, lv_color_black(), 0);
lv_obj_set_style_bg_opa(scr, LV_OPA_COVER, 0);
counter_label = lv_label_create(lv_scr_act());
counter_label = lv_label_create(scr);
printf("Label created"); printf("Label created");
lv_obj_set_style_text_color(counter_label, lv_color_white(), 0);
//lv_obj_set_style_text_font(counter_label, &lv_font_montserrat_12, 0);
lv_label_set_text(counter_label, "00"); lv_label_set_text(counter_label, "00");
lv_obj_set_style_text_color(counter_label, lv_color_white(), 0);
lv_obj_set_style_text_font(counter_label, &lv_font_montserrat_44, 0);
lv_obj_set_style_pad_all(counter_label, 0, 0);
lv_obj_set_style_margin_all(counter_label, 0, 0);
lv_obj_set_width(counter_label, LV_SIZE_CONTENT);
lv_obj_set_style_text_align(counter_label, LV_TEXT_ALIGN_LEFT, 0);
lv_obj_align(counter_label, LV_ALIGN_CENTER, 0, 0); lv_obj_align(counter_label, LV_ALIGN_CENTER, 0, 0);
xTaskCreate(counter_task, "counter_task", 2048, NULL, 5, NULL); xTaskCreate(counter_task, "counter_task", 2048, NULL, 1, NULL);
printf("Counter task created"); printf("Counter task created");
} }
void clear_display(void)
{
printf("Clearing display...\n");
i2c_disp_send_cmd(0x21);
i2c_disp_send_cmd(0);
i2c_disp_send_cmd(127);
i2c_disp_send_cmd(0x22);
i2c_disp_send_cmd(0);
i2c_disp_send_cmd(7);
uint8_t zeros[128];
memset(zeros, 0x00, 128);
for (int page = 0; page < 8; page++)
{
i2c_disp_send_data(zeros, 128);
}
printf("Cleared!\n");
}
void draw_text_ok(void)
{
printf("Drawing 'OK'...\n");
uint8_t letter_O[8] = {
0b00000000, // column 0 (tyhjä)
0b01111110, // column 1 (vasen reuna)
0b10000001, // column 2
0b10000001, // column 3
0b10000001, // column 4
0b01111110, // column 5 (oikea reuna)
0b00000000, // column 6 (tyhjä)
0b00000000 // column 7 (väli)
};
// Kirjain K
uint8_t letter_K[8] = {
0b00000000, // column 0 (tyhjä)
0b11111111, // column 1 (pystyviiva)
0b00011000, // column 2
0b00100100, // column 3
0b01000010, // column 4
0b10000001, // column 5
0b00000000, // column 6 (tyhjä)
0b00000000 // column 7
};
// Aseta page 3 (keskellä näyttöä), column 50
i2c_disp_send_cmd(0x21);
i2c_disp_send_cmd(50);
i2c_disp_send_cmd(127);
i2c_disp_send_cmd(0x22);
i2c_disp_send_cmd(3);
i2c_disp_send_cmd(3);
// Lähetä "OK"
i2c_disp_send_data(letter_O, 8);
i2c_disp_send_data(letter_K, 8);
printf("'OK' drawn!\n");
}
void app_main(void){ void app_main(void){
init_i2c(); init_i2c();
vTaskDelay(pdMS_TO_TICKS(100)); vTaskDelay(pdMS_TO_TICKS(50));
init_display(); init_display();
vTaskDelay(pdMS_TO_TICKS(50));
vTaskDelay(pdMS_TO_TICKS(200));
init_graphics(); init_graphics();
vTaskDelay(pdMS_TO_TICKS(500)); vTaskDelay(pdMS_TO_TICKS(50));
create_counter();
vTaskDelay(pdMS_TO_TICKS(500));
xTaskCreate(lv_tick_task, "lv_tick", 4096, NULL, 1, NULL); xTaskCreate(lv_tick_task, "lv_tick", 4096, NULL, 1, NULL);
xTaskCreate(lv_task, "lv_task", 8192, NULL, 5, NULL); xTaskCreate(lv_task, "lv_task", 8192, NULL, 3, NULL);
vTaskDelay(pdMS_TO_TICKS(150));
create_counter();
/*while(1){
clear_display();
vTaskDelay(pdMS_TO_TICKS(1000));
draw_text_ok();
vTaskDelay(pdMS_TO_TICKS(1000));
}*/
} }