Compare commits
2
Commits
master
...
b607bd8d41
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b607bd8d41 | ||
|
|
73f4e0d1c6 |
@@ -79,10 +79,50 @@ dependencies:
|
||||
source:
|
||||
type: idf
|
||||
version: 6.1.0
|
||||
lvgl/lvgl:
|
||||
component_hash: 7d82410747bbfb319531449749e940f440f8414f041f9eaba13f0d1dd7f58cdd
|
||||
dependencies:
|
||||
- name: espressif/freetype
|
||||
registry_url: https://components.espressif.com
|
||||
require: private
|
||||
rules:
|
||||
- if: idf_version >=5.5 && $CONFIG{LV_USE_FREETYPE} == True
|
||||
version: ^2.14.3
|
||||
- name: espressif/libjpeg-turbo
|
||||
registry_url: https://components.espressif.com
|
||||
require: private
|
||||
rules:
|
||||
- if: idf_version >=5.5 && $CONFIG{LV_USE_LIBJPEG_TURBO} == True
|
||||
version: ^3.1.1
|
||||
- name: espressif/libpng
|
||||
registry_url: https://components.espressif.com
|
||||
require: private
|
||||
rules:
|
||||
- if: idf_version >=5.5 && $CONFIG{LV_USE_LIBPNG} == True
|
||||
version: ^1.6.58
|
||||
- name: espressif/lz4
|
||||
registry_url: https://components.espressif.com
|
||||
require: private
|
||||
rules:
|
||||
- if: idf_version >=5.5 && $CONFIG{LV_USE_LZ4} == True && $CONFIG{LV_USE_LZ4_INTERNAL} == False
|
||||
version: ^1.10.0
|
||||
source:
|
||||
registry_url: https://components.espressif.com/
|
||||
type: service
|
||||
version: 9.6.0~1
|
||||
tny-robotics/sh1106-esp-idf:
|
||||
component_hash: 036f5aad73224c563c3edb5db6f9833f3eb47c41b3d479740edddf49488ced69
|
||||
dependencies: []
|
||||
source:
|
||||
registry_url: https://components.espressif.com/
|
||||
type: service
|
||||
version: 1.0.2
|
||||
direct_dependencies:
|
||||
- esp-idf-lib/bmp280
|
||||
- espressif/cjson
|
||||
- idf
|
||||
manifest_hash: 2b2fa2812480ea444900bab732b40d55618df67e034421f1a347f9de48f70eeb
|
||||
- lvgl/lvgl
|
||||
- tny-robotics/sh1106-esp-idf
|
||||
manifest_hash: 35a13c57b5d80651f5e8a8efa2264804bbeec721529fc3fac1741cec178851f2
|
||||
target: esp32
|
||||
version: 3.0.0
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
idf_component_register(SRCS "thermo_sensor.c" "ygg_http_routes.c" "ygg_bmp280.c" "ygg_http_req.c" "ygg_state.c" "../common_esp32/ygg_wifi.c" "../common_esp32/ygg_http_server.c"
|
||||
idf_component_register(SRCS "thermo_sensor.c" "ygg_http_routes.c" "ygg_bmp280.c" "ygg_http_req.c" "ygg_state.c" "ygg_sh1106.c" "../common_esp32/ygg_wifi.c" "../common_esp32/ygg_http_server.c"
|
||||
INCLUDE_DIRS "." "../common_esp32")
|
||||
|
||||
@@ -16,3 +16,5 @@ dependencies:
|
||||
# public: true
|
||||
esp-idf-lib/bmp280: '*'
|
||||
espressif/cjson: '*'
|
||||
lvgl/lvgl: ^9
|
||||
tny-robotics/sh1106-esp-idf: ^1.0.1
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include <stdio.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <esp_system.h>
|
||||
#include <esp_timer.h>
|
||||
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_http_server.h"
|
||||
@@ -12,16 +14,37 @@
|
||||
#include "ygg_bmp280.h"
|
||||
#include "ygg_http_req.h"
|
||||
#include "ygg_state.h"
|
||||
#include "ygg_sh1106.h"
|
||||
#include "lvgl.h"
|
||||
|
||||
|
||||
static const char *TAG = "thermo_sensor";
|
||||
static lv_display_t *sh_display = NULL;
|
||||
static lv_obj_t *label = NULL;
|
||||
bmp280_t dev_bmp_280;
|
||||
|
||||
void main_loop(void *pvParameters) {
|
||||
static void lvgl_tick_cb(void *arg) {
|
||||
lv_tick_inc(10);
|
||||
}
|
||||
|
||||
void lvgl_task(void *pvParameters) {
|
||||
while (1) {
|
||||
lv_timer_handler();
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
}
|
||||
|
||||
void sensor_task(void *pvParameters) {
|
||||
// Wait 1s, to avoid corrupted first sensor readout
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
while (1) {
|
||||
ygg_bmp280_read_sensor(&dev_bmp_280);
|
||||
ygg_bmp280_read_sensor(&dev_bmp_280);
|
||||
// Najpierw OLED, potem (blokujący) HTTP — żeby ekran
|
||||
// odświeżył się nawet gdy serwer nie odpowiada.
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "Temp: %.2f C",
|
||||
CURR_READOUT.temperature);
|
||||
ygg_set_display_label(sh_display, label, buf);
|
||||
ygg_send_sensor_readouts(BASE_URL,
|
||||
SENSOR_NAME,
|
||||
CURR_READOUT);
|
||||
@@ -57,7 +80,24 @@ void app_main()
|
||||
httpd_register_uri_handler(server, &ygg_hum_uri);
|
||||
|
||||
ESP_ERROR_CHECK(i2cdev_init());
|
||||
|
||||
sh_display = ygg_sh1106_init();
|
||||
// LVGL potrzebuje regularnego ticka, inaczej redraw nigdy się nie wykona
|
||||
// (to był powód, dla którego wisiało "FIRST").
|
||||
const esp_timer_create_args_t lvgl_tick_args = {
|
||||
.callback = lvgl_tick_cb,
|
||||
.name = "lvgl_tick",
|
||||
};
|
||||
esp_timer_handle_t lvgl_tick_handle = NULL;
|
||||
ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_args, &lvgl_tick_handle));
|
||||
ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_handle, 10 * 1000));
|
||||
|
||||
lv_obj_t *scr = lv_display_get_screen_active(sh_display);
|
||||
label = lv_label_create(scr);
|
||||
ygg_set_display_label(sh_display, label, "FIRST");
|
||||
|
||||
ygg_bmp280_init(&dev_bmp_280);
|
||||
xTaskCreatePinnedToCore(main_loop, "bmp280_test", configMINIMAL_STACK_SIZE * 8, NULL, 5, NULL, APP_CPU_NUM);
|
||||
xTaskCreatePinnedToCore(lvgl_task, "lvgl", 4096, NULL, 4, NULL, APP_CPU_NUM);
|
||||
xTaskCreatePinnedToCore(sensor_task, "bmp280_test", 8192, NULL, 5, NULL, APP_CPU_NUM);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
#include "ygg_sh1106.h"
|
||||
#include "lvgl.h"
|
||||
#include "i2cdev.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_lcd_io_i2c.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_lcd_panel_sh1106.h"
|
||||
|
||||
#define I2C_HOST I2C_NUM_0
|
||||
#define EXAMPLE_I2C_MASTER_FREQ_HZ 400000
|
||||
#define EXAMPLE_LCD_V_RES 64
|
||||
#define EXAMPLE_LCD_H_RES 128
|
||||
#define EXAMPLE_LVGL_PALETTE_SIZE 8
|
||||
#define SH1106_I2C_SDA_GPIO 19
|
||||
#define SH1106_I2C_SCL_GPIO 23
|
||||
|
||||
static uint8_t oled_buffer[EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES / 8];
|
||||
|
||||
static void example_lvgl_flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map)
|
||||
{
|
||||
esp_lcd_panel_handle_t panel_handle = lv_display_get_user_data(disp);
|
||||
|
||||
// This is necessary because LVGL reserves 2 x 4 bytes in the buffer, as these are assumed to be used as a palette. Skip the palette here
|
||||
// More information about the monochrome, please refer to https://docs.lvgl.io/9.2/porting/display.html#monochrome-displays
|
||||
px_map += EXAMPLE_LVGL_PALETTE_SIZE;
|
||||
|
||||
uint16_t hor_res = lv_display_get_physical_horizontal_resolution(disp);
|
||||
int x1 = area->x1;
|
||||
int x2 = area->x2;
|
||||
int y1 = area->y1;
|
||||
int y2 = area->y2;
|
||||
|
||||
for (int y = y1; y <= y2; y++) {
|
||||
for (int x = x1; x <= x2; x++) {
|
||||
/* The order of bits is MSB first
|
||||
MSB LSB
|
||||
bits 7 6 5 4 3 2 1 0
|
||||
pixels 0 1 2 3 4 5 6 7
|
||||
Left Right
|
||||
*/
|
||||
bool chroma_color = (px_map[(hor_res >> 3) * y + (x >> 3)] & 1 << (7 - x % 8));
|
||||
|
||||
/* Write to the buffer as required for the display.
|
||||
* It writes only 1-bit for monochrome displays mapped vertically.*/
|
||||
uint8_t *buf = oled_buffer + hor_res * (y >> 3) + (x);
|
||||
if (chroma_color) {
|
||||
(*buf) &= ~(1 << (y % 8));
|
||||
} else {
|
||||
(*buf) |= (1 << (y % 8));
|
||||
}
|
||||
}
|
||||
}
|
||||
// pass the draw buffer to the driver
|
||||
esp_lcd_panel_draw_bitmap(panel_handle, x1, y1, x2 + 1, y2 + 1, oled_buffer);
|
||||
lv_display_flush_ready(disp);
|
||||
}
|
||||
|
||||
lv_display_t* ygg_sh1106_init() {
|
||||
//ESP_ERROR_CHECK(i2cdev_init());
|
||||
|
||||
static i2c_dev_t oled_i2c_dev;
|
||||
memset(&oled_i2c_dev, 0, sizeof(oled_i2c_dev));
|
||||
oled_i2c_dev.port = I2C_HOST; // numer portu I2C
|
||||
oled_i2c_dev.addr = SH1106_I2C_ADDR; // adres OLED-a (0x3C)
|
||||
oled_i2c_dev.cfg.sda_io_num = SH1106_I2C_SDA_GPIO; // SDA z "idf menuconfig"
|
||||
oled_i2c_dev.cfg.scl_io_num = SH1106_I2C_SCL_GPIO; // SCL z "idf menuconfig"
|
||||
oled_i2c_dev.cfg.master.clk_speed = EXAMPLE_I2C_MASTER_FREQ_HZ;
|
||||
oled_i2c_dev.cfg.sda_pullup_en = true; // OLED zwykle nie ma pull-upów
|
||||
oled_i2c_dev.cfg.scl_pullup_en = true;
|
||||
|
||||
// Rejestracja urządzenia + utworzenie mutexu.
|
||||
// Przy pierwszym urządzeniu na danym porcie i2cdev tworzy magistralę
|
||||
// (i2c_new_master_bus) z podanymi pinami SDA/SCL.
|
||||
ESP_ERROR_CHECK(i2c_dev_create_mutex(&oled_i2c_dev));
|
||||
|
||||
// Opcjonalnie: sprawdź, czy OLED odpowiada na magistrali.
|
||||
ESP_ERROR_CHECK(i2c_dev_check_present(&oled_i2c_dev));
|
||||
|
||||
// Pobierz współdzielony uchwyt magistrali zarządzanej przez i2cdev,
|
||||
// żeby przekazać go do natywnego komponentu esp_lcd.
|
||||
// Dzięki temu inne sensory na i2cdev i wyświetlacz na esp_lcd
|
||||
// bezpiecznie dzielą tę samą magistralę I2C.
|
||||
// UWAGA: uchwytem zarządza i2cdev — NIE wołaj na nim i2c_del_master_bus().
|
||||
i2c_master_bus_handle_t i2c_bus_handle = NULL;
|
||||
ESP_ERROR_CHECK(i2cdev_get_shared_handle(I2C_HOST, (void **)&i2c_bus_handle));
|
||||
|
||||
// Create the i2c io handle
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
esp_lcd_panel_io_i2c_config_t io_config = ESP_SH1106_DEFAULT_IO_CONFIG;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus_handle, &io_config, &io_handle));
|
||||
|
||||
|
||||
/* SCREEN CONFIGURATION */
|
||||
|
||||
// sh1106 panel configuration (most of the values are not used, but must be set to avoid cpp warnings)
|
||||
esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = -1, // sh1106 does not have a reset pin, so set to -1
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, // not even used, but must be set to avoid cpp warnings
|
||||
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, // not even used, but must be set to avoid cpp warnings
|
||||
.bits_per_pixel = SH1106_PIXELS_PER_BYTE / 8, // bpp = 1 (monochrome, that's important)
|
||||
.flags = {
|
||||
.reset_active_high = false, // not even used, but must be set to avoid cpp warnings
|
||||
},
|
||||
.vendor_config = NULL, // no need for custom vendor config, not implemented
|
||||
};
|
||||
|
||||
// Create the panel handle from the sh1106 driver
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_sh1106(io_handle, &panel_config, &panel_handle));
|
||||
|
||||
// Reset the screen (no reset pin, so it's a no-op here, optional)
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
|
||||
|
||||
// Initialize the screen (this one isn't optional at all!)
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
|
||||
|
||||
// Turn on the screen (Easier to see something, right?)
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
|
||||
|
||||
void *buf = NULL;
|
||||
size_t draw_buffer_sz = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES / 8 + EXAMPLE_LVGL_PALETTE_SIZE;
|
||||
buf = heap_caps_calloc(1, draw_buffer_sz, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
|
||||
lv_init();
|
||||
lv_display_t *display = lv_display_create(EXAMPLE_LCD_H_RES, EXAMPLE_LCD_V_RES);
|
||||
lv_display_set_user_data(display, panel_handle);
|
||||
lv_display_set_color_format(display, LV_COLOR_FORMAT_I1);
|
||||
lv_display_set_buffers(display, buf, NULL, draw_buffer_sz, LV_DISPLAY_RENDER_MODE_FULL);
|
||||
lv_display_set_flush_cb(display, example_lvgl_flush_cb);
|
||||
|
||||
lv_obj_t *scr = lv_display_get_screen_active(display);
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
void ygg_set_display_label(lv_display_t *display, lv_obj_t *label, const char *str) {
|
||||
lv_label_set_text(label, str);
|
||||
/* Size of the screen (if you use rotation 90 or 270, please use lv_display_get_vertical_resolution) */
|
||||
lv_obj_set_width(label, lv_display_get_horizontal_resolution(display));
|
||||
lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 0);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef YGG_SH1106
|
||||
#define YGG_SH1106
|
||||
|
||||
#include "lvgl.h"
|
||||
|
||||
lv_display_t* ygg_sh1106_init();
|
||||
void ygg_set_display_label(lv_display_t *display, lv_obj_t *label, const char *str);
|
||||
|
||||
#endif
|
||||
+979
-8
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user