Compare commits
2
Commits
master
...
b607bd8d41
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b607bd8d41 | ||
|
|
73f4e0d1c6 |
@@ -79,10 +79,50 @@ dependencies:
|
|||||||
source:
|
source:
|
||||||
type: idf
|
type: idf
|
||||||
version: 6.1.0
|
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:
|
direct_dependencies:
|
||||||
- esp-idf-lib/bmp280
|
- esp-idf-lib/bmp280
|
||||||
- espressif/cjson
|
- espressif/cjson
|
||||||
- idf
|
- idf
|
||||||
manifest_hash: 2b2fa2812480ea444900bab732b40d55618df67e034421f1a347f9de48f70eeb
|
- lvgl/lvgl
|
||||||
|
- tny-robotics/sh1106-esp-idf
|
||||||
|
manifest_hash: 35a13c57b5d80651f5e8a8efa2264804bbeec721529fc3fac1741cec178851f2
|
||||||
target: esp32
|
target: esp32
|
||||||
version: 3.0.0
|
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")
|
INCLUDE_DIRS "." "../common_esp32")
|
||||||
|
|||||||
@@ -16,3 +16,5 @@ dependencies:
|
|||||||
# public: true
|
# public: true
|
||||||
esp-idf-lib/bmp280: '*'
|
esp-idf-lib/bmp280: '*'
|
||||||
espressif/cjson: '*'
|
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/FreeRTOS.h>
|
||||||
#include <freertos/task.h>
|
#include <freertos/task.h>
|
||||||
#include <esp_system.h>
|
#include <esp_system.h>
|
||||||
|
#include <esp_timer.h>
|
||||||
|
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include "esp_http_server.h"
|
#include "esp_http_server.h"
|
||||||
@@ -12,16 +14,37 @@
|
|||||||
#include "ygg_bmp280.h"
|
#include "ygg_bmp280.h"
|
||||||
#include "ygg_http_req.h"
|
#include "ygg_http_req.h"
|
||||||
#include "ygg_state.h"
|
#include "ygg_state.h"
|
||||||
|
#include "ygg_sh1106.h"
|
||||||
|
#include "lvgl.h"
|
||||||
|
|
||||||
|
|
||||||
static const char *TAG = "thermo_sensor";
|
static const char *TAG = "thermo_sensor";
|
||||||
|
static lv_display_t *sh_display = NULL;
|
||||||
|
static lv_obj_t *label = NULL;
|
||||||
bmp280_t dev_bmp_280;
|
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
|
// Wait 1s, to avoid corrupted first sensor readout
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
while (1) {
|
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,
|
ygg_send_sensor_readouts(BASE_URL,
|
||||||
SENSOR_NAME,
|
SENSOR_NAME,
|
||||||
CURR_READOUT);
|
CURR_READOUT);
|
||||||
@@ -57,7 +80,24 @@ void app_main()
|
|||||||
httpd_register_uri_handler(server, &ygg_hum_uri);
|
httpd_register_uri_handler(server, &ygg_hum_uri);
|
||||||
|
|
||||||
ESP_ERROR_CHECK(i2cdev_init());
|
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);
|
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