diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a751b67 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Code/picocalc_lvgl_graphics_demo/Code/picocalc_lvgl_graphics_demo/lib/lvgl/lvgl"] + path = Code/picocalc_lvgl_graphics_demo/Code/picocalc_lvgl_graphics_demo/lib/lvgl/lvgl + url = https://github.com/lvgl/lvgl.git diff --git a/Code/picocalc_lvgl_graphics_demo/.gitignore b/Code/picocalc_lvgl_graphics_demo/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/Code/picocalc_lvgl_graphics_demo/CMakeLists.txt b/Code/picocalc_lvgl_graphics_demo/CMakeLists.txt new file mode 100644 index 0000000..0b9dd90 --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/CMakeLists.txt @@ -0,0 +1,70 @@ +cmake_minimum_required(VERSION 3.16) + +# Setup board for Pico 1 +set(PICO_BOARD pico) + +# Setup board for Pico 2W +# set(PICO_BOARD pico2) + +include(pico_sdk_import.cmake) + +project(pico_lvgl_display_demo) +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + +pico_sdk_init() + +include_directories( + ${CMAKE_CURRENT_LIST_DIR} +) + + + +add_subdirectory(i2ckbd) +add_subdirectory(lcdspi) +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/lib/lvgl lvgl) + + +add_executable(pico_lvgl_display_demo + main.c + lv_port_indev_picocalc_kb.c + lv_port_disp_picocalc_ILI9488.c +) + +target_compile_options(pico_lvgl_display_demo PRIVATE -DPICOMITE + -DPICO_HEAP_SIZE=0x1000 + -DGUICONTROLS + -DPICO_CORE0_STACK_SIZE=0x1000 + ) + +target_compile_definitions(pico_lvgl_display_demo PRIVATE LV_USE_DEMO_WIDGETS=1) + +target_include_directories(pico_lvgl_display_demo PRIVATE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/lib/lvgl/lvgl + ${CMAKE_CURRENT_LIST_DIR}/lib/lvgl/lvgl/src + ${CMAKE_CURRENT_LIST_DIR}/lib/lvgl/lvgl/demos +) + + +target_link_libraries(pico_lvgl_display_demo + pico_stdlib + hardware_flash + hardware_irq + hardware_adc + hardware_pwm + hardware_i2c + hardware_spi + hardware_dma + hardware_exception + hardware_pio + pico_multicore + i2ckbd + lcdspi + lvgl + lvgl_demos +) + +pico_enable_stdio_usb(pico_lvgl_display_demo 0) +pico_enable_stdio_uart(pico_lvgl_display_demo 1) +pico_add_extra_outputs(pico_lvgl_display_demo) diff --git a/Code/picocalc_lvgl_graphics_demo/Code/picocalc_lvgl_graphics_demo/lib/lvgl/lvgl b/Code/picocalc_lvgl_graphics_demo/Code/picocalc_lvgl_graphics_demo/lib/lvgl/lvgl new file mode 160000 index 0000000..b88fb67 --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/Code/picocalc_lvgl_graphics_demo/lib/lvgl/lvgl @@ -0,0 +1 @@ +Subproject commit b88fb674d3e54e27d05ef7595a77052c20453698 diff --git a/Code/picocalc_lvgl_graphics_demo/i2ckbd/CMakeLists.txt b/Code/picocalc_lvgl_graphics_demo/i2ckbd/CMakeLists.txt new file mode 100644 index 0000000..d7d7a22 --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/i2ckbd/CMakeLists.txt @@ -0,0 +1,20 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) + +project(i2ckbd + VERSION 0.0.1 + DESCRIPTION "i2ckbd for picocalc." + ) + +add_library(i2ckbd INTERFACE) + +target_sources(i2ckbd INTERFACE + i2ckbd.c + ) + +target_link_libraries(i2ckbd INTERFACE pico_stdlib hardware_spi hardware_i2c) + +target_include_directories(i2ckbd INTERFACE ${CMAKE_CURRENT_LIST_DIR}) \ No newline at end of file diff --git a/Code/picocalc_lvgl_graphics_demo/i2ckbd/i2ckbd.c b/Code/picocalc_lvgl_graphics_demo/i2ckbd/i2ckbd.c new file mode 100644 index 0000000..a403308 --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/i2ckbd/i2ckbd.c @@ -0,0 +1,57 @@ +#include +#include +#include "i2ckbd.h" + +static uint8_t i2c_inited = 0; + +void init_i2c_kbd() { + gpio_set_function(I2C_KBD_SCL, GPIO_FUNC_I2C); + gpio_set_function(I2C_KBD_SDA, GPIO_FUNC_I2C); + i2c_init(I2C_KBD_MOD, I2C_KBD_SPEED); + gpio_pull_up(I2C_KBD_SCL); + gpio_pull_up(I2C_KBD_SDA); + + i2c_inited = 1; +} + +int read_i2c_kbd() { + int retval; + static int ctrlheld = 0; + uint16_t buff = 0; + unsigned char msg[2]; + int c = -1; + msg[0] = 0x09; + + if (i2c_inited == 0) return -1; + + retval = i2c_write_timeout_us(I2C_KBD_MOD, I2C_KBD_ADDR, msg, 1, false, 500000); + if (retval == PICO_ERROR_GENERIC || retval == PICO_ERROR_TIMEOUT) { + printf("i2c write error\n"); + return -1; + } + + retval = i2c_read_timeout_us(I2C_KBD_MOD, I2C_KBD_ADDR, (unsigned char *) &buff, 2, false, 500000); + if (retval == PICO_ERROR_GENERIC || retval == PICO_ERROR_TIMEOUT) { + printf("i2c read error read\n"); + return -1; + } + + if (buff != 0) { + if (buff == 0x7e03)ctrlheld = 0; + else if (buff == 0x7e02) { + ctrlheld = 1; + } else if ((buff & 0xff) == 1) {//pressed + c = buff >> 8; + int realc = -1; + switch (c) { + default: + realc = c; + break; + } + c = realc; + if (c >= 'a' && c <= 'z' && ctrlheld)c = c - 'a' + 1; + } + return c; + } + return 0; +} \ No newline at end of file diff --git a/Code/picocalc_lvgl_graphics_demo/i2ckbd/i2ckbd.h b/Code/picocalc_lvgl_graphics_demo/i2ckbd/i2ckbd.h new file mode 100644 index 0000000..0281abd --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/i2ckbd/i2ckbd.h @@ -0,0 +1,19 @@ +#ifndef I2C_KEYBOARD_H +#define I2C_KEYBOARD_H +#include +#include +#include +#include + +#define I2C_KBD_MOD i2c1 +#define I2C_KBD_SDA 6 +#define I2C_KBD_SCL 7 + +#define I2C_KBD_SPEED 400000 // if dual i2c, then the speed of keyboard i2c should be 10khz + +#define I2C_KBD_ADDR 0x1F + +void init_i2c_kbd(); +int read_i2c_kbd(); + +#endif \ No newline at end of file diff --git a/Code/picocalc_lvgl_graphics_demo/lcdspi/CMakeLists.txt b/Code/picocalc_lvgl_graphics_demo/lcdspi/CMakeLists.txt new file mode 100644 index 0000000..35f4078 --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/lcdspi/CMakeLists.txt @@ -0,0 +1,20 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) + +project(lcdspi + VERSION 0.0.1 + DESCRIPTION "lcdspi for rp2040." + ) + +add_library(lcdspi INTERFACE) + +target_sources(lcdspi INTERFACE + lcdspi.c + ) + +target_link_libraries(lcdspi INTERFACE pico_stdlib hardware_spi) + +target_include_directories(lcdspi INTERFACE ${CMAKE_CURRENT_LIST_DIR}) \ No newline at end of file diff --git a/Code/picocalc_lvgl_graphics_demo/lcdspi/fonts/font1.h b/Code/picocalc_lvgl_graphics_demo/lcdspi/fonts/font1.h new file mode 100644 index 0000000..749ad88 --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/lcdspi/fonts/font1.h @@ -0,0 +1,233 @@ +// font1.c +// Font type : Full (223 characters) +// Font size : 8x12 pixels +// Memory usage : 2680 bytes +// Font adapted from: http://www.rinkydinkelectronics.com/r_fonts.php + +const unsigned char font1[] ={ + 0x08,0x0C,0x20,0xE0, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(32) + 0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x10,0x00,0x00, // Chr$(33) ! + 0x00,0x24,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(34) " + 0x00,0x24,0x24,0x7E,0x24,0x24,0x24,0x7E,0x24,0x24,0x00,0x00, // Chr$(35) # + 0x00,0x10,0x3C,0x52,0x50,0x3C,0x12,0x52,0x3C,0x10,0x00,0x00, // Chr$(36) $ + 0x00,0x00,0x62,0x62,0x04,0x08,0x10,0x20,0x46,0x46,0x00,0x00, // Chr$(37) % + 0x00,0x00,0x38,0x44,0x44,0x38,0x4A,0x44,0x4C,0x3A,0x00,0x00, // Chr$(38) & + 0x00,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(39) ' + 0x00,0x0C,0x10,0x20,0x20,0x20,0x20,0x20,0x20,0x10,0x0C,0x00, // Chr$(40) ( + 0x00,0x30,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x30,0x00, // Chr$(41) ) + 0x00,0x42,0x24,0x18,0x7E,0x18,0x24,0x42,0x00,0x00,0x00,0x00, // Chr$(42) * + 0x00,0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x00,0x00,0x00, // Chr$(43) + + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x08,0x10,0x00, // Chr$(44) , + 0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(45) - + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00, // Chr$(46) . + 0x00,0x02,0x02,0x04,0x04,0x08,0x10,0x20,0x20,0x40,0x40,0x00, // Chr$(47) / + 0x00,0x3C,0x46,0x4E,0x4A,0x5A,0x52,0x72,0x62,0x3C,0x00,0x00, // Chr$(48) 0 + 0x00,0x10,0x30,0x50,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00, // Chr$(49) 1 + 0x00,0x3C,0x42,0x02,0x02,0x04,0x08,0x10,0x20,0x7E,0x00,0x00, // Chr$(50) 2 + 0x00,0x3C,0x42,0x02,0x02,0x1C,0x02,0x02,0x42,0x3C,0x00,0x00, // Chr$(51) 3 + 0x00,0x04,0x44,0x44,0x44,0x7E,0x04,0x04,0x04,0x04,0x00,0x00, // Chr$(52) 4 + 0x00,0x7E,0x40,0x40,0x7C,0x02,0x02,0x02,0x42,0x3C,0x00,0x00, // Chr$(53) 5 + 0x00,0x18,0x20,0x40,0x40,0x7C,0x42,0x42,0x42,0x3C,0x00,0x00, // Chr$(54) 6 + 0x00,0x7E,0x42,0x02,0x02,0x04,0x08,0x10,0x10,0x10,0x00,0x00, // Chr$(55) 7 + 0x00,0x3C,0x42,0x42,0x42,0x3C,0x42,0x42,0x42,0x3C,0x00,0x00, // Chr$(56) 8 + 0x00,0x3C,0x42,0x42,0x42,0x3E,0x02,0x04,0x08,0x30,0x00,0x00, // Chr$(57) 9 + 0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00,0x00,0x00, // Chr$(58) : + 0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x08,0x10,0x00, // Chr$(59) ; + 0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00,0x00, // Chr$(60) < + 0x00,0x00,0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00, // Chr$(61) = + 0x00,0x20,0x10,0x08,0x04,0x02,0x04,0x08,0x10,0x20,0x00,0x00, // Chr$(62) > + 0x00,0x3C,0x42,0x02,0x06,0x08,0x10,0x10,0x00,0x10,0x10,0x00, // Chr$(63) ? + 0x00,0x3C,0x42,0x42,0x5E,0x56,0x5C,0x40,0x40,0x3C,0x00,0x00, // Chr$(64) @ + 0x00,0x18,0x24,0x42,0x42,0x42,0x7E,0x42,0x42,0x42,0x00,0x00, // Chr$(65) A + 0x00,0x7C,0x42,0x42,0x42,0x7C,0x42,0x42,0x42,0x7C,0x00,0x00, // Chr$(66) B + 0x00,0x3C,0x42,0x40,0x40,0x40,0x40,0x40,0x42,0x3C,0x00,0x00, // Chr$(67) C + 0x00,0x78,0x44,0x42,0x42,0x42,0x42,0x42,0x44,0x78,0x00,0x00, // Chr$(68) D + 0x00,0x7E,0x40,0x40,0x40,0x78,0x40,0x40,0x40,0x7E,0x00,0x00, // Chr$(69) E + 0x00,0x7E,0x40,0x40,0x40,0x78,0x40,0x40,0x40,0x40,0x00,0x00, // Chr$(70) F + 0x00,0x3C,0x42,0x40,0x40,0x40,0x4E,0x42,0x42,0x3E,0x00,0x00, // Chr$(71) G + 0x00,0x42,0x42,0x42,0x42,0x7E,0x42,0x42,0x42,0x42,0x00,0x00, // Chr$(72) H + 0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00, // Chr$(73) I + 0x00,0x02,0x02,0x02,0x02,0x02,0x02,0x42,0x42,0x3C,0x00,0x00, // Chr$(74) J + 0x00,0x42,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x42,0x00,0x00, // Chr$(75) K + 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7E,0x00,0x00, // Chr$(76) L + 0x00,0x42,0x66,0x66,0x5A,0x42,0x42,0x42,0x42,0x42,0x00,0x00, // Chr$(77) M + 0x00,0x42,0x62,0x62,0x52,0x5A,0x4A,0x46,0x46,0x42,0x00,0x00, // Chr$(78) N + 0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00, // Chr$(79) O + 0x00,0x7C,0x42,0x42,0x42,0x7C,0x40,0x40,0x40,0x40,0x00,0x00, // Chr$(80) P + 0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x4A,0x44,0x3A,0x00,0x00, // Chr$(81) Q + 0x00,0x7C,0x42,0x42,0x42,0x7C,0x48,0x44,0x42,0x42,0x00,0x00, // Chr$(82) R + 0x00,0x3C,0x42,0x40,0x60,0x18,0x04,0x02,0x42,0x3C,0x00,0x00, // Chr$(83) S + 0x00,0x7E,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, // Chr$(84) T + 0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00, // Chr$(85) U + 0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x24,0x18,0x00,0x00, // Chr$(86) V + 0x00,0x42,0x42,0x42,0x42,0x42,0x5A,0x24,0x24,0x24,0x00,0x00, // Chr$(87) W + 0x00,0x42,0x42,0x24,0x24,0x18,0x24,0x24,0x42,0x42,0x00,0x00, // Chr$(88) X + 0x00,0x44,0x44,0x44,0x44,0x38,0x10,0x10,0x10,0x10,0x00,0x00, // Chr$(89) Y + 0x00,0x7E,0x02,0x02,0x04,0x18,0x20,0x40,0x40,0x7E,0x00,0x00, // Chr$(90) Z + 0x00,0x3C,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3C,0x00,0x00, // Chr$(91) [ + 0x00,0x40,0x40,0x20,0x20,0x10,0x08,0x04,0x04,0x02,0x02,0x00, // Chr$(92) backslash + 0x00,0x3C,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x3C,0x00,0x00, // Chr$(93) ] + 0x00,0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(94) ^ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00, // Chr$(95) _ + 0x00,0x18,0x24,0x24,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(96) ` + 0x00,0x00,0x00,0x00,0x3C,0x02,0x3E,0x42,0x42,0x3E,0x00,0x00, // Chr$(97) a + 0x00,0x40,0x40,0x40,0x7C,0x42,0x42,0x42,0x42,0x7C,0x00,0x00, // Chr$(98) b + 0x00,0x00,0x00,0x00,0x3C,0x40,0x40,0x40,0x40,0x3C,0x00,0x00, // Chr$(99) c + 0x00,0x02,0x02,0x02,0x3E,0x42,0x42,0x42,0x42,0x3E,0x00,0x00, // Chr$(100) d + 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x7C,0x40,0x3C,0x00,0x00, // Chr$(101) e + 0x00,0x00,0x1C,0x20,0x20,0x7C,0x20,0x20,0x20,0x20,0x00,0x00, // Chr$(102) f + 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x3E,0x02,0x3C,0x00, // Chr$(103) g + 0x00,0x40,0x40,0x40,0x7C,0x42,0x42,0x42,0x42,0x42,0x00,0x00, // Chr$(104) h + 0x00,0x00,0x10,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, // Chr$(105) i + 0x00,0x00,0x04,0x00,0x04,0x04,0x04,0x04,0x04,0x44,0x38,0x00, // Chr$(106) j + 0x00,0x40,0x40,0x40,0x44,0x48,0x70,0x50,0x48,0x44,0x00,0x00, // Chr$(107) k + 0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x18,0x00,0x00, // Chr$(108) l + 0x00,0x00,0x00,0x00,0x74,0x4A,0x4A,0x42,0x42,0x42,0x00,0x00, // Chr$(109) m + 0x00,0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x44,0x00,0x00, // Chr$(110) n + 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x3C,0x00,0x00, // Chr$(111) o + 0x00,0x00,0x00,0x00,0x7C,0x42,0x42,0x42,0x7C,0x40,0x40,0x00, // Chr$(112) p + 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x3C,0x06,0x00, // Chr$(113) q + 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x40,0x40,0x40,0x00,0x00, // Chr$(114) r + 0x00,0x00,0x00,0x00,0x1E,0x20,0x1C,0x02,0x02,0x3C,0x00,0x00, // Chr$(115) s + 0x00,0x00,0x00,0x10,0x7C,0x10,0x10,0x10,0x10,0x08,0x00,0x00, // Chr$(116) t + 0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00, // Chr$(117) u + 0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00, // Chr$(118) v + 0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x5A,0x24,0x24,0x00,0x00, // Chr$(119) w + 0x00,0x00,0x00,0x00,0x42,0x24,0x18,0x18,0x24,0x42,0x00,0x00, // Chr$(120) x + 0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x3E,0x02,0x42,0x3C,0x00, // Chr$(121) y + 0x00,0x00,0x00,0x00,0x7E,0x04,0x08,0x10,0x20,0x7E,0x00,0x00, // Chr$(122) z + 0x00,0x1C,0x20,0x10,0x10,0x60,0x10,0x10,0x20,0x1C,0x00,0x00, // Chr$(123) { + 0x00,0x10,0x10,0x10,0x10,0x00,0x10,0x10,0x10,0x10,0x00,0x00, // Chr$(124) | + 0x00,0x38,0x04,0x08,0x08,0x06,0x08,0x08,0x04,0x38,0x00,0x00, // Chr$(125) } + 0x00,0x22,0x5A,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(126) ~ + 0x00,0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x7E,0x00,0x00,0x00, // Chr$(127)  + 0x00,0xFF,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0xFF,0x00, // Chr$(128) € + 0x00,0xFF,0x81,0x81,0x85,0x85,0xA9,0x91,0x81,0x81,0xFF,0x00, // Chr$(129)  + 0x00,0xFF,0x81,0xA5,0xA5,0x99,0x99,0xA5,0xA5,0x81,0xFF,0x00, // Chr$(130) ‚ + 0x00,0xFF,0x81,0x81,0x81,0x99,0x99,0x81,0x81,0x81,0xFF,0x00, // Chr$(131) ƒ + 0x00,0xFF,0x81,0x81,0x81,0x81,0x81,0xBD,0x81,0x81,0xFF,0x00, // Chr$(132) „ + 0x00,0xFF,0x81,0x99,0x99,0x99,0x99,0x81,0x99,0x81,0xFF,0x00, // Chr$(133) … + 0x00,0xFF,0x81,0x99,0xA5,0x89,0x89,0x81,0x89,0x81,0xFF,0x00, // Chr$(134) † + 0x00,0x3E,0x7F,0x7F,0x6B,0x7F,0x6B,0x77,0x7F,0x3E,0x00,0x00, // Chr$(135) ‡ + 0x00,0x3E,0x63,0x41,0x55,0x41,0x55,0x49,0x63,0x3E,0x00,0x00, // Chr$(136) ˆ + 0x00,0x00,0x08,0x1C,0x3E,0x7F,0x7F,0x3E,0x1C,0x08,0x00,0x00, // Chr$(137) ‰ + 0x00,0x00,0x00,0x18,0x18,0x66,0x66,0x18,0x18,0x3C,0x00,0x00, // Chr$(138) Š + 0x00,0x00,0x00,0x18,0x3C,0x7E,0x7E,0x18,0x18,0x3C,0x00,0x00, // Chr$(139) ‹ + 0x00,0x00,0x36,0x3E,0x7F,0x7F,0x7F,0x3E,0x1C,0x08,0x00,0x00, // Chr$(140) Œ + 0xFF,0xFF,0xC3,0x81,0x99,0xBD,0xBD,0x99,0x81,0xC3,0xFF,0xFF, // Chr$(141)  + 0x00,0x00,0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00, // Chr$(142) Ž + 0x00,0x1F,0x19,0x1F,0x18,0x18,0x18,0x38,0x78,0x30,0x00,0x00, // Chr$(143)  + 0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00, // Chr$(144)  + 0x00,0x00,0x00,0x24,0x66,0xFF,0xFF,0x66,0x24,0x00,0x00,0x00, // Chr$(145) ‘ + 0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00, // Chr$(146) ’ + 0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00, // Chr$(147) “ + 0x00,0x00,0x00,0x08,0x0C,0xFE,0xFE,0x0C,0x08,0x00,0x00,0x00, // Chr$(148) ” + 0x00,0x00,0x00,0x10,0x30,0x7F,0x7F,0x30,0x10,0x00,0x00,0x00, // Chr$(149) • + 0x00,0x00,0x08,0x2A,0x49,0x49,0x49,0x41,0x41,0x3E,0x00,0x00, // Chr$(150) – + 0x1C,0x22,0x41,0x5D,0x49,0x2A,0x1C,0x00,0x1C,0x00,0x1C,0x00, // Chr$(151) — + 0x18,0x18,0x00,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x18,0x00,0x00, // Chr$(152) ˜ + 0xF8,0x8C,0xBE,0x8F,0xE3,0x85,0xF5,0xF5,0xF3,0xFF,0x00,0x00, // Chr$(153) ™ + 0x00,0x18,0x24,0x42,0x42,0x42,0x7E,0x7E,0x24,0x24,0x24,0x24, // Chr$(154) š + 0x00,0x18,0x3C,0x7E,0x7E,0x7E,0x7E,0x7E,0x24,0x24,0x24,0x24, // Chr$(155) › + 0x00,0x20,0x64,0xE2,0xE9,0xE5,0xE9,0xE2,0x64,0x20,0x00,0x00, // Chr$(156) œ + 0x00,0x3F,0x4B,0x4B,0x4B,0x3B,0x0B,0x0B,0x0B,0x0B,0x00,0x00, // Chr$(157)  + 0x00,0x7E,0x44,0x48,0x6E,0x24,0x28,0x50,0x60,0x40,0x00,0x00, // Chr$(158) ž + 0x00,0x00,0x21,0x36,0x1E,0x3C,0xFE,0x1B,0x10,0x10,0x00,0x00, // Chr$(159) Ÿ + 0x00,0x3C,0x42,0x81,0xA5,0xA5,0xA5,0x81,0x42,0x3C,0x00,0x00, // Chr$(160)   + 0x00,0x3C,0x42,0x91,0x99,0x9D,0x99,0x91,0x42,0x3C,0x00,0x00, // Chr$(161) ¡ + 0x00,0x3C,0x42,0x81,0xBD,0xBD,0xBD,0x81,0x42,0x3C,0x00,0x00, // Chr$(162) ¢ + 0x00,0x00,0x38,0x44,0x44,0x44,0x3C,0x06,0x03,0x01,0x00,0x00, // Chr$(163) £ + 0x00,0x0C,0x10,0x20,0x7C,0x20,0x20,0x7C,0x20,0x10,0x0C,0x00, // Chr$(164) ¤ + 0x00,0x00,0x1A,0x26,0x42,0x81,0x42,0x42,0x42,0x7E,0x00,0x00, // Chr$(165) ¥ + 0x00,0x00,0x3C,0x24,0xFF,0x42,0x42,0x42,0x42,0x7E,0x00,0x00, // Chr$(166) ¦ + 0x00,0x18,0x66,0x42,0x81,0xC3,0xC3,0x42,0x00,0x00,0x00,0x00, // Chr$(167) § + 0x00,0x00,0xFF,0x81,0x81,0x81,0x81,0xFF,0x18,0x3C,0x00,0x00, // Chr$(168) ¨ + 0x00,0x18,0x3C,0x3C,0x3C,0x3C,0x18,0x00,0x18,0x18,0x00,0x00, // Chr$(169) © + 0x28,0x56,0x41,0x83,0xFE,0x0C,0x10,0x10,0x20,0x00,0x00,0x00, // Chr$(170) ª + 0x00,0x30,0x48,0x48,0x48,0x4A,0x32,0x02,0x02,0x02,0x02,0x00, // Chr$(171) « + 0x18,0x24,0x66,0x5A,0x66,0x18,0x38,0x18,0x38,0x18,0x38,0x00, // Chr$(172) ¬ + 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF, // Chr$(173) ­ + 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, // Chr$(174) ® + 0xCC,0xCC,0x33,0x33,0xCC,0xCC,0x33,0x33,0xCC,0xCC,0x33,0x33, // Chr$(175) ¯ + 0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49, // Chr$(176) ° + 0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA, // Chr$(177) ± + 0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6,0x6D,0xDB,0xB6, // Chr$(178) ² + 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // Chr$(179) ³ + 0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18, // Chr$(180) ´ + 0x18,0x18,0x18,0x18,0xF8,0x18,0x18,0xF8,0x18,0x18,0x18,0x18, // Chr$(181) µ + 0x66,0x66,0x66,0x66,0x66,0xE6,0x66,0x66,0x66,0x66,0x66,0x66, // Chr$(182) ¶ + 0x00,0x00,0x00,0x00,0x00,0xFE,0x66,0x66,0x66,0x66,0x66,0x66, // Chr$(183) · + 0x00,0x00,0x00,0x00,0xF8,0x18,0x18,0xF8,0x18,0x18,0x18,0x18, // Chr$(184) ¸ + 0x66,0x66,0x66,0x66,0xE6,0x06,0x06,0xE6,0x66,0x66,0x66,0x66, // Chr$(185) ¹ + 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, // Chr$(186) º + 0x00,0x00,0x00,0x00,0xFE,0x06,0x06,0xE6,0x66,0x66,0x66,0x66, // Chr$(187) » + 0x66,0x66,0x66,0x66,0xE6,0x06,0x06,0xFE,0x00,0x00,0x00,0x00, // Chr$(188) ¼ + 0x66,0x66,0x66,0x66,0x66,0xFE,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(189) ½ + 0x18,0x18,0x18,0x18,0xF8,0x18,0x18,0xF8,0x00,0x00,0x00,0x00, // Chr$(190) ¾ + 0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0x18,0x18,0x18,0x18,0x18, // Chr$(191) ¿ + 0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(192) À + 0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(193) Á + 0x00,0x00,0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18, // Chr$(194)  + 0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18, // Chr$(195) à + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(196) Ä + 0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18, // Chr$(197) Å + 0x18,0x18,0x18,0x18,0x1F,0x18,0x18,0x1F,0x18,0x18,0x18,0x18, // Chr$(198) Æ + 0x66,0x66,0x66,0x66,0x66,0x67,0x66,0x66,0x66,0x66,0x66,0x66, // Chr$(199) Ç + 0x66,0x66,0x66,0x66,0x67,0x60,0x60,0x7F,0x00,0x00,0x00,0x00, // Chr$(200) È + 0x00,0x00,0x00,0x00,0x7F,0x60,0x60,0x67,0x66,0x66,0x66,0x66, // Chr$(201) É + 0x66,0x66,0x66,0x66,0xE7,0x00,0x00,0xFF,0x00,0x00,0x00,0x00, // Chr$(202) Ê + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0xE7,0x66,0x66,0x66,0x66, // Chr$(203) Ë + 0x66,0x66,0x66,0x66,0x67,0x60,0x60,0x67,0x66,0x66,0x66,0x66, // Chr$(204) Ì + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00, // Chr$(205) Í + 0x66,0x66,0x66,0x66,0xE7,0x00,0x00,0xE7,0x66,0x66,0x66,0x66, // Chr$(206) Î + 0x18,0x18,0x18,0x18,0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00, // Chr$(207) Ï + 0x66,0x66,0x66,0x66,0x66,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(208) Ð + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,0x18,0x18,0x18,0x18, // Chr$(209) Ñ + 0x00,0x00,0x00,0x00,0x00,0xFF,0x66,0x66,0x66,0x66,0x66,0x66, // Chr$(210) Ò + 0x66,0x66,0x66,0x66,0x66,0x7F,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(211) Ó + 0x18,0x18,0x18,0x18,0x1F,0x18,0x18,0x1F,0x00,0x00,0x00,0x00, // Chr$(212) Ô + 0x00,0x00,0x00,0x00,0x1F,0x18,0x18,0x1F,0x18,0x18,0x18,0x18, // Chr$(213) Õ + 0x00,0x00,0x00,0x00,0x00,0x7F,0x66,0x66,0x66,0x66,0x66,0x66, // Chr$(214) Ö + 0x66,0x66,0x66,0x66,0x66,0xE7,0x66,0x66,0x66,0x66,0x66,0x66, // Chr$(215) × + 0x18,0x18,0x18,0x18,0xFF,0x00,0x00,0xFF,0x18,0x18,0x18,0x18, // Chr$(216) Ø + 0x18,0x18,0x18,0x18,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(217) Ù + 0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x18,0x18,0x18,0x18,0x18, // Chr$(218) Ú + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // Chr$(219) Û + 0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // Chr$(220) Ü + 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, // Chr$(221) Ý + 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // Chr$(222) Þ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(223) ß + 0x00,0x00,0x00,0x00,0x3A,0x44,0x44,0x44,0x44,0x3A,0x00,0x00, // Chr$(224) à + 0x00,0x38,0x44,0x44,0x58,0x44,0x44,0x44,0x78,0x40,0x40,0x00, // Chr$(225) á + 0x00,0x00,0x7E,0x42,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00, // Chr$(226) â + 0x00,0x00,0x00,0x00,0x7C,0x28,0x28,0x28,0x28,0x68,0x00,0x00, // Chr$(227) ã + 0x00,0x7E,0x42,0x20,0x10,0x08,0x10,0x20,0x42,0x7E,0x00,0x00, // Chr$(228) ä + 0x00,0x00,0x00,0x00,0x3E,0x48,0x44,0x44,0x44,0x38,0x00,0x00, // Chr$(229) å + 0x00,0x00,0x00,0x24,0x24,0x24,0x24,0x3C,0x42,0x40,0x80,0x00, // Chr$(230) æ + 0x00,0x00,0x00,0x00,0x44,0xA8,0x10,0x10,0x10,0x10,0x00,0x00, // Chr$(231) ç + 0x00,0x00,0x7C,0x00,0x38,0x44,0x44,0x44,0x38,0x00,0x7C,0x00, // Chr$(232) è + 0x00,0x00,0x18,0x24,0x42,0x42,0x7E,0x42,0x42,0x24,0x18,0x00, // Chr$(233) é + 0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x6C,0x28,0x6C,0x00,0x00, // Chr$(234) ê + 0x00,0x00,0x00,0x1C,0x20,0x38,0x44,0x44,0x44,0x38,0x00,0x00, // Chr$(235) ë + 0x00,0x00,0x00,0x00,0x00,0x6C,0x92,0x92,0x6C,0x00,0x00,0x00, // Chr$(236) ì + 0x00,0x00,0x00,0x00,0x02,0x6C,0x9A,0xB2,0x6C,0x80,0x00,0x00, // Chr$(237) í + 0x00,0x18,0x20,0x40,0x40,0x78,0x40,0x40,0x20,0x18,0x00,0x00, // Chr$(238) î + 0x00,0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x00,0x00, // Chr$(239) ï + 0x00,0x00,0x3C,0x00,0x00,0x3C,0x00,0x00,0x3C,0x00,0x00,0x00, // Chr$(240) ð + 0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x7C,0x00,0x00,0x00, // Chr$(241) ñ + 0x00,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x00,0x7E,0x00,0x00, // Chr$(242) ò + 0x00,0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x00,0x7E,0x00,0x00, // Chr$(243) ó + 0x40,0x41,0x42,0x44,0x48,0x10,0x26,0x49,0x02,0x04,0x0F,0x00, // Chr$(244) ô + 0x40,0x41,0x42,0x44,0x48,0x12,0x26,0x4A,0x0F,0x02,0x02,0x00, // Chr$(245) õ + 0x00,0x00,0x18,0x18,0x00,0x7E,0x00,0x18,0x18,0x00,0x00,0x00, // Chr$(246) ö + 0x00,0x00,0x22,0x52,0x4C,0x00,0x22,0x52,0x4C,0x00,0x00,0x00, // Chr$(247) ÷ + 0x00,0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(248) ø + 0x00,0x00,0x00,0x00,0x1C,0x1C,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(249) ù + 0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(250) ú + 0x00,0x00,0x0E,0x08,0x08,0x08,0x08,0x48,0x28,0x18,0x08,0x00, // Chr$(251) û + 0x00,0x3C,0x12,0x12,0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(252) ü + 0x00,0x18,0x24,0x08,0x10,0x3C,0x00,0x00,0x00,0x00,0x00,0x00, // Chr$(253) ý + 0x00,0x00,0x00,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x00,0x00,0x00, // Chr$(254) þ + 0x00,0x00,0x10,0x54,0x28,0xC6,0x28,0x54,0x10,0x00,0x00,0x00 // Chr$(255) ÿ +}; diff --git a/Code/picocalc_lvgl_graphics_demo/lcdspi/lcdspi.c b/Code/picocalc_lvgl_graphics_demo/lcdspi/lcdspi.c new file mode 100644 index 0000000..a3da45e --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/lcdspi/lcdspi.c @@ -0,0 +1,730 @@ +#include +#include +#include + +#include +#include "hardware/timer.h" +#include +#include + +#include "lcdspi.h" +#include "i2ckbd.h" +#include "pico/multicore.h" +////////////////////**************************************fonts + +#include "fonts/font1.h" +unsigned char *MainFont = (unsigned char *) font1; + +static int gui_fcolour; +static int gui_bcolour; +static short current_x = 0, current_y = 0; // the current default position for the next char to be written +static short gui_font_width, gui_font_height; +static short hres = 320; // Horizontal resolution for ILI9488 +static short vres = 320; // Vertical resolution for ILI9488 +static char s_height; +static char s_width; +int lcd_char_pos = 0; +unsigned char lcd_buffer[320 * 3] = {0};// 1440 = 480*3, 320*3 = 960 + +void __not_in_flash_func(spi_write_fast)(spi_inst_t *spi, const uint8_t *src, size_t len) { + // Write to TX FIFO whilst ignoring RX, then clean up afterward. When RX + // is full, PL022 inhibits RX pushes, and sets a sticky flag on + // push-on-full, but continues shifting. Safe if SSPIMSC_RORIM is not set. + for (size_t i = 0; i < len; ++i) { + while (!spi_is_writable(spi)) + tight_loop_contents(); + spi_get_hw(spi)->dr = (uint32_t) src[i]; + } +} + +void __not_in_flash_func(spi_finish)(spi_inst_t *spi) { + // Drain RX FIFO, then wait for shifting to finish (which may be *after* + // TX FIFO drains), then drain RX FIFO again + while (spi_is_readable(spi)) + (void) spi_get_hw(spi)->dr; + while (spi_get_hw(spi)->sr & SPI_SSPSR_BSY_BITS) + tight_loop_contents(); + while (spi_is_readable(spi)) + (void) spi_get_hw(spi)->dr; + + // Don't leave overrun flag set + spi_get_hw(spi)->icr = SPI_SSPICR_RORIC_BITS; +} + +void set_font() { + + gui_font_width = MainFont[0]; + gui_font_height = MainFont[1]; + + s_height = vres / gui_font_height; + s_width = hres / gui_font_width; +} + +void define_region_spi(int xstart, int ystart, int xend, int yend, int rw) { + unsigned char coord[4]; + lcd_spi_lower_cs(); + gpio_put(Pico_LCD_DC, 0);//gpio_put(Pico_LCD_DC,0); + hw_send_spi(&(uint8_t) {ILI9341_COLADDRSET}, 1); + gpio_put(Pico_LCD_DC, 1); + coord[0] = xstart >> 8; + coord[1] = xstart; + coord[2] = xend >> 8; + coord[3] = xend; + hw_send_spi(coord, 4);// HAL_SPI_Transmit(&hspi3,coord,4,500); + gpio_put(Pico_LCD_DC, 0); + hw_send_spi(&(uint8_t) {ILI9341_PAGEADDRSET}, 1); + gpio_put(Pico_LCD_DC, 1); + coord[0] = ystart >> 8; + coord[1] = ystart; + coord[2] = yend >> 8; + coord[3] = yend; + hw_send_spi(coord, 4);// HAL_SPI_Transmit(&hspi3,coord,4,500); + gpio_put(Pico_LCD_DC, 0); + if (rw) { + hw_send_spi(&(uint8_t) {ILI9341_MEMORYWRITE}, 1); + } else { + hw_send_spi(&(uint8_t) {ILI9341_RAMRD}, 1); + } + gpio_put(Pico_LCD_DC, 1); +} + +void read_buffer_spi(int x1, int y1, int x2, int y2, unsigned char *p) { + int r, N, t; + unsigned char h, l; +// PInt(x1);PIntComma(y1);PIntComma(x2);PIntComma(y2);PRet(); + // make sure the coordinates are kept within the display area + if (x2 <= x1) { + t = x1; + x1 = x2; + x2 = t; + } + if (y2 <= y1) { + t = y1; + y1 = y2; + y2 = t; + } + if (x1 < 0) x1 = 0; + if (x1 >= hres) x1 = hres - 1; + if (x2 < 0) x2 = 0; + if (x2 >= hres) x2 = hres - 1; + if (y1 < 0) y1 = 0; + if (y1 >= vres) y1 = vres - 1; + if (y2 < 0) y2 = 0; + if (y2 >= vres) y2 = vres - 1; + N = (x2 - x1 + 1) * (y2 - y1 + 1) * 3; + + define_region_spi(x1, y1, x2, y2, 0); + + //spi_init(Pico_LCD_SPI_MOD, 6000000); + spi_set_baudrate(Pico_LCD_SPI_MOD, 6000000); + //spi_read_data_len(p, 1); + hw_read_spi((uint8_t *) p, 1); + r = 0; + hw_read_spi((uint8_t *) p, N); + gpio_put(Pico_LCD_DC, 0); + lcd_spi_raise_cs(); + spi_set_baudrate(Pico_LCD_SPI_MOD, LCD_SPI_SPEED); + r = 0; + + while (N) { + h = (uint8_t) p[r + 2]; + l = (uint8_t) p[r]; + p[r] = h;//(h & 0xF8); + p[r + 2] = l;//(l & 0xF8); + r += 3; + N -= 3; + } +} + +void draw_buffer_spi(int x1, int y1, int x2, int y2, unsigned char *p) { + int i, t; + unsigned char q[3]; + + // Boundary checking + if (x2 <= x1) { + t = x1; + x1 = x2; + x2 = t; + } + if (y2 <= y1) { + t = y1; + y1 = y2; + y2 = t; + } + if (x1 < 0) x1 = 0; + if (x1 >= hres) x1 = hres - 1; + if (x2 < 0) x2 = 0; + if (x2 >= hres) x2 = hres - 1; + if (y1 < 0) y1 = 0; + if (y1 >= vres) y1 = vres - 1; + if (y2 < 0) y2 = 0; + if (y2 >= vres) y2 = vres - 1; + + // Calculate total number of pixels + int pixelCount = (x2 - x1 + 1) * (y2 - y1 + 1); + uint16_t *pixelBuffer = (uint16_t *)p; + + define_region_spi(x1, y1, x2, y2, 1); + + for (i = 0; i < pixelCount; i++) { + uint16_t pixel = pixelBuffer[i]; + + // Extract RGB565 components + uint8_t r5 = (pixel >> 11) & 0x1F; + uint8_t g6 = (pixel >> 5) & 0x3F; + uint8_t b5 = pixel & 0x1F; + + // Convert to 8-bit values (scaling approximation) + uint8_t r8 = (r5 << 3) | (r5 >> 2); + uint8_t g8 = (g6 << 2) | (g6 >> 4); + uint8_t b8 = (b5 << 3) | (b5 >> 2); + +#ifdef ILI9488 + // Convert each RGB565 pixel to RGB888 (3 bytes per pixel) for ILI9488 + uint8_t rgb[3]; + rgb[0] = r8; // Red + rgb[1] = g8; // Green + rgb[2] = b8; // Blue + hw_send_spi(rgb, 3); +#else + // For other controllers or if using 16-bit mode, retain the original conversion + hw_send_spi(q, 2); +#endif + } + + lcd_spi_raise_cs(); +} + +//Print the bitmap of a char on the video output +// x, y - the top left of the char +// width, height - size of the char's bitmap +// scale - how much to scale the bitmap +// fc, bc - foreground and background colour +// bitmap - pointer to the bitmap +void draw_bitmap_spi(int x1, int y1, int width, int height, int scale, int fc, int bc, unsigned char *bitmap) { + int i, j, k, m, n; + char f[3], b[3]; + int vertCoord, horizCoord, XStart, XEnd, YEnd; + char *p = 0; + union colourmap { + char rgbbytes[4]; + unsigned int rgb; + } c; + + if (x1 >= hres || y1 >= vres || x1 + width * scale < 0 || y1 + height * scale < 0)return; + // adjust when part of the bitmap is outside the displayable coordinates + vertCoord = y1; + if (y1 < 0) y1 = 0; // the y coord is above the top of the screen + XStart = x1; + if (XStart < 0) XStart = 0; // the x coord is to the left of the left marginn + XEnd = x1 + (width * scale) - 1; + if (XEnd >= hres) XEnd = hres - 1; // the width of the bitmap will extend beyond the right margin + YEnd = y1 + (height * scale) - 1; + if (YEnd >= vres) YEnd = vres - 1;// the height of the bitmap will extend beyond the bottom margin + +#ifdef ILI9488 + // convert the colours to 565 format + f[0] = (fc >> 16); + f[1] = (fc >> 8) & 0xFF; + f[2] = (fc & 0xFF); + b[0] = (bc >> 16); + b[1] = (bc >> 8) & 0xFF; + b[2] = (bc & 0xFF); + +#endif + //printf("draw_bitmap_spi-> XStart %d, y1 %d, XEnd %d, YEnd %d\n",XStart,y1,XEnd,YEnd); + define_region_spi(XStart, y1, XEnd, YEnd, 1); + + n = 0; + for (i = 0; i < height; i++) { // step thru the font scan line by line + for (j = 0; j < scale; j++) { // repeat lines to scale the font + if (vertCoord++ < 0) continue; // we are above the top of the screen + if (vertCoord > vres) { // we have extended beyond the bottom of the screen + lcd_spi_raise_cs(); //set CS high + return; + } + horizCoord = x1; + for (k = 0; k < width; k++) { // step through each bit in a scan line + for (m = 0; m < scale; m++) { // repeat pixels to scale in the x axis + if (horizCoord++ < 0) continue; // we have not reached the left margin + if (horizCoord > hres) continue; // we are beyond the right margin + if ((bitmap[((i * width) + k) / 8] >> (((height * width) - ((i * width) + k) - 1) % 8)) & 1) { + hw_send_spi((uint8_t *) &f, 3); + } else { + if (bc == -1) { + c.rgbbytes[0] = p[n]; + c.rgbbytes[1] = p[n + 1]; + c.rgbbytes[2] = p[n + 2]; +#ifdef ILI9488 + b[0] = c.rgbbytes[2]; + b[1] = c.rgbbytes[1]; + b[2] = c.rgbbytes[0]; +#endif + } + hw_send_spi((uint8_t *) &b, 3); + } + n += 3; + } + } + } + } + lcd_spi_raise_cs(); //set CS high + +} + +// Draw a filled rectangle +// this is the basic drawing promitive used by most drawing routines +// x1, y1, x2, y2 - the coordinates +// c - the colour +void draw_rect_spi(int x1, int y1, int x2, int y2, int c) { + // convert the colours to 565 format + unsigned char col[3]; + if (x1 == x2 && y1 == y2) { + if (x1 < 0) return; + if (x1 >= hres) return; + if (y1 < 0) return; + if (y1 >= vres) return; + define_region_spi(x1, y1, x2, y2, 1); +#ifdef ILI9488 + col[0] = (c >> 16); + col[1] = (c >> 8) & 0xFF; + col[2] = (c & 0xFF); +#endif + hw_send_spi(col, 3); + } else { + int i, t, y; + unsigned char *p; + // make sure the coordinates are kept within the display area + if (x2 <= x1) { + t = x1; + x1 = x2; + x2 = t; + } + if (y2 <= y1) { + t = y1; + y1 = y2; + y2 = t; + } + if (x1 < 0) x1 = 0; + if (x1 >= hres) x1 = hres - 1; + if (x2 < 0) x2 = 0; + if (x2 >= hres) x2 = hres - 1; + if (y1 < 0) y1 = 0; + if (y1 >= vres) y1 = vres - 1; + if (y2 < 0) y2 = 0; + if (y2 >= vres) y2 = vres - 1; + define_region_spi(x1, y1, x2, y2, 1); +#ifdef ILI9488 + i = x2 - x1 + 1; + i *= 3; + p = lcd_buffer; + col[0] = (c >> 16); + col[1] = (c >> 8) & 0xFF; + col[2] = (c & 0xFF); + for (t = 0; t < i; t += 3) { + p[t] = col[0]; + p[t + 1] = col[1]; + p[t + 2] = col[2]; + } + for (y = y1; y <= y2; y++) { + spi_write_fast(Pico_LCD_SPI_MOD, p, i); + } +#endif + } + spi_finish(Pico_LCD_SPI_MOD); + lcd_spi_raise_cs(); +} + +/****************************************************************************************** + Print a char on the LCD display + Any characters not in the font will print as a space. + The char is printed at the current location defined by current_x and current_y +*****************************************************************************************/ +void lcd_print_char( int fc, int bc, char c, int orientation) { + unsigned char *p, *fp, *np = NULL; + int modx, mody, scale = 0x01; + int height, width; + + // to get the +, - and = chars for font 6 we fudge them by scaling up font 1 + fp = (unsigned char *) MainFont; + + height = fp[1]; + width = fp[0]; + modx = mody = 0; + //printf("fp %d, c %d ,height %d width %d\n",fp,c, height,width); + + if (c >= fp[2] && c < fp[2] + fp[3]) { + p = fp + 4 + (int) (((c - fp[2]) * height * width) / 8); + //printf("p = %d\n",p); + np = p; + + draw_bitmap_spi(current_x + modx, current_y + mody, width, height, scale, fc, bc, np); + } else { + draw_rect_spi(current_x + modx, current_y + mody, current_x + modx + (width * scale), + current_y + mody + (height * scale), bc); + } + + if (orientation == ORIENT_NORMAL) current_x += width * scale; + +} + +unsigned char scrollbuff[LCD_WIDTH * 3]; + +void scroll_lcd_spi(int lines) { + if (lines == 0)return; + if (lines >= 0) { + for (int i = 0; i < vres - lines; i++) { + read_buffer_spi(0, i + lines, hres - 1, i + lines, scrollbuff); + draw_buffer_spi(0, i, hres - 1, i, scrollbuff); + } + draw_rect_spi(0, vres - lines, hres - 1, vres - 1, gui_bcolour); // erase the lines to be scrolled off + } else { + lines = -lines; + for (int i = vres - 1; i >= lines; i--) { + read_buffer_spi(0, i - lines, hres - 1, i - lines, scrollbuff); + draw_buffer_spi(0, i, hres - 1, i, scrollbuff); + } + draw_rect_spi(0, 0, hres - 1, lines - 1, gui_bcolour); // erase the lines introduced at the top + } + +} + +void display_put_c(char c) { + // if it is printable and it is going to take us off the right hand end of the screen do a CRLF + if (c >= MainFont[2] && c < MainFont[2] + MainFont[3]) { + if (current_x + gui_font_width > hres) { + display_put_c('\r'); + display_put_c('\n'); + } + } + + // handle the standard control chars + switch (c) { + case '\b': + current_x -= gui_font_width; + //if (current_x < 0) current_x = 0; + if (current_x < 0) { //Go to end of previous line + current_y -= gui_font_height; //Go up one line + if (current_y < 0) current_y = 0; + current_x = (s_width - 1) * gui_font_width; //go to last character + } + return; + case '\r': + current_x = 0; + return; + case '\n': + current_x = 0; + current_y += gui_font_height; + if (current_y + gui_font_height >= vres) { + scroll_lcd_spi(current_y + gui_font_height - vres); + current_y -= (current_y + gui_font_height - vres); + } + return; + case '\t': + do { + display_put_c(' '); + } while ((current_x / gui_font_width) % 2);// 2 3 4 8 + return; + } + lcd_print_char(gui_fcolour, gui_bcolour, c, ORIENT_NORMAL);// print it +} + +/*** + * +****//// +char lcd_put_char(char c, int flush) { + lcd_putc(0, c); + if (isprint(c)) lcd_char_pos++; + if (c == '\r') { + lcd_char_pos = 1; + } + return c; +} + +void lcd_print_string(char *s) { + while (*s) { + if (s[1])lcd_put_char(*s, 0); + else lcd_put_char(*s, 1); + s++; + } + fflush(stdout); +} + +///////=----------------------------------------===////// +void lcd_clear() { + draw_rect_spi(0, 0, hres - 1, vres - 1, BLACK); +} + +void lcd_putc(uint8_t devn, uint8_t c) { + display_put_c(c); +} + +int lcd_getc(uint8_t devn) { + //i2c keyboard + int c = read_i2c_kbd(); + return c; +} + +unsigned char __not_in_flash_func(hw1_swap_spi)(unsigned char data_out) { + unsigned char data_in = 0; + spi_write_read_blocking(spi1, &data_out, &data_in, 1); + return data_in; +} + +void hw_read_spi(unsigned char *buff, int cnt) { + spi_read_blocking(Pico_LCD_SPI_MOD, 0xff, buff, cnt); +} + +void hw_send_spi(const unsigned char *buff, int cnt) { + + spi_write_blocking(Pico_LCD_SPI_MOD, buff, cnt); + +} + +void pin_set_bit(int pin, unsigned int offset) { + switch (offset) { + case LATCLR: + gpio_set_pulls(pin, false, false); + gpio_pull_down(pin); + gpio_put(pin, 0); + return; + case LATSET: + gpio_set_pulls(pin, false, false); + gpio_pull_up(pin); + gpio_put(pin, 1); + return; + case LATINV: + gpio_xor_mask(1 << pin); + return; + case TRISSET: + gpio_set_dir(pin, GPIO_IN); + sleep_us(2); + return; + case TRISCLR: + gpio_set_dir(pin, GPIO_OUT); + gpio_set_drive_strength(pin, GPIO_DRIVE_STRENGTH_12MA); + sleep_us(2); + return; + case CNPUSET: + gpio_set_pulls(pin, true, false); + return; + case CNPDSET: + gpio_set_pulls(pin, false, true); + return; + case CNPUCLR: + case CNPDCLR: + gpio_set_pulls(pin, false, false); + return; + case ODCCLR: + gpio_set_dir(pin, GPIO_OUT); + gpio_put(pin, 0); + sleep_us(2); + return; + case ODCSET: + gpio_set_pulls(pin, true, false); + gpio_set_dir(pin, GPIO_IN); + sleep_us(2); + return; + case ANSELCLR: + gpio_set_function(pin, GPIO_FUNC_SIO); + gpio_set_dir(pin, GPIO_IN); + return; + default: + break; + //printf("Unknown pin_set_bit command"); + } +} + +//important for read lcd memory +void reset_controller(void) { + pin_set_bit(Pico_LCD_RST, LATSET); + sleep_us(10000); + pin_set_bit(Pico_LCD_RST, LATCLR); + sleep_us(10000); + pin_set_bit(Pico_LCD_RST, LATSET); + sleep_us(200000); +} + + +void pico_lcd_init() { +#ifdef ILI9488 + reset_controller(); + + hres = 320; + vres = 320; + + spi_write_command(0xE0); // Positive Gamma Control + spi_write_data(0x00); + spi_write_data(0x03); + spi_write_data(0x09); + spi_write_data(0x08); + spi_write_data(0x16); + spi_write_data(0x0A); + spi_write_data(0x3F); + spi_write_data(0x78); + spi_write_data(0x4C); + spi_write_data(0x09); + spi_write_data(0x0A); + spi_write_data(0x08); + spi_write_data(0x16); + spi_write_data(0x1A); + spi_write_data(0x0F); + + spi_write_command(0XE1); // Negative Gamma Control + spi_write_data(0x00); + spi_write_data(0x16); + spi_write_data(0x19); + spi_write_data(0x03); + spi_write_data(0x0F); + spi_write_data(0x05); + spi_write_data(0x32); + spi_write_data(0x45); + spi_write_data(0x46); + spi_write_data(0x04); + spi_write_data(0x0E); + spi_write_data(0x0D); + spi_write_data(0x35); + spi_write_data(0x37); + spi_write_data(0x0F); + + spi_write_command(0XC0); // Power Control 1 + spi_write_data(0x17); + spi_write_data(0x15); + + spi_write_command(0xC1); // Power Control 2 + spi_write_data(0x41); + + spi_write_command(0xC5); // VCOM Control + spi_write_data(0x00); + spi_write_data(0x12); + spi_write_data(0x80); + + spi_write_command(TFT_MADCTL); // Memory Access Control + spi_write_data(0x48); // MX, BGR + + spi_write_command(0x3A); // Pixel Interface Format + spi_write_data(0x66); // 18/24-bit colour for SPI (RGB666/RGB888) + + spi_write_command(0xB0); // Interface Mode Control + spi_write_data(0x00); + + spi_write_command(0xB1); // Frame Rate Control + spi_write_data(0xA0); + + spi_write_command(TFT_INVON); + + spi_write_command(0xB4); // Display Inversion Control + spi_write_data(0x02); + + spi_write_command(0xB6); // Display Function Control + spi_write_data(0x02); + spi_write_data(0x02); + spi_write_data(0x3B); + + spi_write_command(0xB7); // Entry Mode Set + spi_write_data(0xC6); + spi_write_command(0xE9); + spi_write_data(0x00); + + spi_write_command(0xF7); // Adjust Control 3 + spi_write_data(0xA9); + spi_write_data(0x51); + spi_write_data(0x2C); + spi_write_data(0x82); + + spi_write_command(TFT_SLPOUT); //Exit Sleep + sleep_ms(120); + + spi_write_command(TFT_DISPON); //Display on + sleep_ms(120); + + spi_write_command(TFT_MADCTL); + spi_write_cd(ILI9341_MEMCONTROL, 1, ILI9341_Portrait); +#endif +} + +void lcd_spi_raise_cs(void) { + gpio_put(Pico_LCD_CS, 1); +} + +void lcd_spi_lower_cs(void) { + + gpio_put(Pico_LCD_CS, 0); + +} + +void spi_write_data(unsigned char data) { + gpio_put(Pico_LCD_DC, 1); + lcd_spi_lower_cs(); + hw_send_spi(&data, 1); + lcd_spi_raise_cs(); +} + +void spi_write_data24(uint32_t data) { + uint8_t data_array[3]; + data_array[0] = data >> 16; + data_array[1] = (data >> 8) & 0xFF; + data_array[2] = data & 0xFF; + + + gpio_put(Pico_LCD_DC, 1); // Data mode + gpio_put(Pico_LCD_CS, 0); + spi_write_blocking(Pico_LCD_SPI_MOD, data_array, 3); + gpio_put(Pico_LCD_CS, 1); +} + +void spi_write_command(unsigned char data) { + gpio_put(Pico_LCD_DC, 0); + gpio_put(Pico_LCD_CS, 0); + + spi_write_blocking(Pico_LCD_SPI_MOD, &data, 1); + + gpio_put(Pico_LCD_CS, 1); +} + +void spi_write_cd(unsigned char command, int data, ...) { + int i; + va_list ap; + va_start(ap, data); + spi_write_command(command); + for (i = 0; i < data; i++) spi_write_data((char) va_arg(ap, int)); + va_end(ap); +} + +void lcd_spi_init() { + // init GPIO + gpio_init(Pico_LCD_SCK); + gpio_init(Pico_LCD_TX); + gpio_init(Pico_LCD_RX); + gpio_init(Pico_LCD_CS); + gpio_init(Pico_LCD_DC); + gpio_init(Pico_LCD_RST); + + gpio_set_dir(Pico_LCD_SCK, GPIO_OUT); + gpio_set_dir(Pico_LCD_TX, GPIO_OUT); + //gpio_set_dir(Pico_LCD_RX, GPIO_IN); + gpio_set_dir(Pico_LCD_CS, GPIO_OUT); + gpio_set_dir(Pico_LCD_DC, GPIO_OUT); + gpio_set_dir(Pico_LCD_RST, GPIO_OUT); + + // init SPI + spi_init(Pico_LCD_SPI_MOD, LCD_SPI_SPEED); + gpio_set_function(Pico_LCD_SCK, GPIO_FUNC_SPI); + gpio_set_function(Pico_LCD_TX, GPIO_FUNC_SPI); + gpio_set_function(Pico_LCD_RX, GPIO_FUNC_SPI); + gpio_set_input_hysteresis_enabled(Pico_LCD_RX, true); + + gpio_put(Pico_LCD_CS, 1); + gpio_put(Pico_LCD_RST, 1); +} + + +void lcd_init() { + lcd_spi_init(); + pico_lcd_init(); + + set_font(); + gui_fcolour = GREEN; + gui_bcolour = BLACK; + +} diff --git a/Code/picocalc_lvgl_graphics_demo/lcdspi/lcdspi.h b/Code/picocalc_lvgl_graphics_demo/lcdspi/lcdspi.h new file mode 100644 index 0000000..3fe3f0f --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/lcdspi/lcdspi.h @@ -0,0 +1,146 @@ +#ifndef LCDSPI_H +#define LCDSPI_H +#include "pico/multicore.h" +#include + +//#define LCD_SPI_SPEED 6000000 +#define LCD_SPI_SPEED 25000000 +//#define LCD_SPI_SPEED 50000000 + +#define Pico_LCD_SCK 10 // +#define Pico_LCD_TX 11 // MOSI +#define Pico_LCD_RX 12 // MISO +#define Pico_LCD_CS 13 // +#define Pico_LCD_DC 14 +#define Pico_LCD_RST 15 + +#define ILI9488 1 +#ifdef ILI9488 +#define LCD_WIDTH 320 +#define LCD_HEIGHT 320 +#endif + +#define PIXFMT_BGR 1 + +#define TFT_SLPOUT 0x11 +#define TFT_INVOFF 0x20 +#define TFT_INVON 0x21 + +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_MADCTL 0x36 + +#define ILI9341_MEMCONTROL 0x36 +#define ILI9341_MADCTL_MX 0x40 +#define ILI9341_MADCTL_BGR 0x08 + +#define ILI9341_COLADDRSET 0x2A +#define ILI9341_PAGEADDRSET 0x2B +#define ILI9341_MEMORYWRITE 0x2C +#define ILI9341_RAMRD 0x2E + +#define ILI9341_Portrait ILI9341_MADCTL_MX | ILI9341_MADCTL_BGR + +#define ORIENT_NORMAL 0 + +#define RGB(red, green, blue) (unsigned int) (((red & 0b11111111) << 16) | ((green & 0b11111111) << 8) | (blue & 0b11111111)) +#define WHITE RGB(255, 255, 255) //0b1111 +#define YELLOW RGB(255, 255, 0) //0b1110 +#define LILAC RGB(255, 128, 255) //0b1101 +#define BROWN RGB(255, 128, 0) //0b1100 +#define FUCHSIA RGB(255, 64, 255) //0b1011 +#define RUST RGB(255, 64, 0) //0b1010 +#define MAGENTA RGB(255, 0, 255) //0b1001 +#define RED RGB(255, 0, 0) //0b1000 +#define CYAN RGB(0, 255, 255) //0b0111 +#define GREEN RGB(0, 255, 0) //0b0110 +#define CERULEAN RGB(0, 128, 255) //0b0101 +#define MIDGREEN RGB(0, 128, 0) //0b0100 +#define COBALT RGB(0, 64, 255) //0b0011 +#define MYRTLE RGB(0, 64, 0) //0b0010 +#define BLUE RGB(0, 0, 255) //0b0001 +#define BLACK RGB(0, 0, 0) //0b0000 +#define BROWN RGB(255, 128, 0) +#define GRAY RGB(128, 128, 128) +#define LITEGRAY RGB(210, 210, 210) +#define ORANGE RGB(0xff, 0xA5, 0) +#define PINK RGB(0xFF, 0xA0, 0xAB) +#define GOLD RGB(0xFF, 0xD7, 0x00) +#define SALMON RGB(0xFA, 0x80, 0x72) +#define BEIGE RGB(0xF5, 0xF5, 0xDC) + +//Pico spi0 or spi1 must match GPIO pins used above. +#define Pico_LCD_SPI_MOD spi1 +#define nop asm("NOP") +//xmit_byte_multi == HW1SendSPI + + +#define PORTCLR 1 +#define PORTSET 2 +#define PORTINV 3 +#define LAT 4 +#define LATCLR 5 +#define LATSET 6 +#define LATINV 7 +#define ODC 8 +#define ODCCLR 9 +#define ODCSET 10 +#define CNPU 12 +#define CNPUCLR 13 +#define CNPUSET 14 +#define CNPUINV 15 +#define CNPD 16 +#define CNPDCLR 17 +#define CNPDSET 18 + +#define ANSELCLR -7 +#define ANSELSET -6 +#define ANSELINV -5 +#define TRIS -4 +#define TRISCLR -3 +#define TRISSET -2 + +extern void __not_in_flash_func(spi_write_fast)(spi_inst_t *spi, const uint8_t *src, size_t len); +extern void __not_in_flash_func(spi_finish)(spi_inst_t *spi); +extern void hw_read_spi(unsigned char *buff, int cnt); +extern void hw_send_spi(const unsigned char *buff, int cnt); +extern unsigned char __not_in_flash_func(hw1_swap_spi)(unsigned char data_out); + +extern void lcd_spi_raise_cs(void); +extern void lcd_spi_lower_cs(void); +extern void spi_write_data(unsigned char data); +extern void spi_write_command(unsigned char data); +extern void spi_write_cd(unsigned char command, int data, ...); +extern void spi_write_data24(uint32_t data); + +extern void spi_draw_pixel(uint16_t x, uint16_t y, uint16_t color) ; +extern void lcd_putc(uint8_t devn, uint8_t c); +extern int lcd_getc(uint8_t devn); +extern void lcd_sleeping(uint8_t devn); + + +void draw_rect_spi(int x1, int y1, int x2, int y2, int c); +void define_region_spi(int xstart, int ystart, int xend, int yend, int rw); + + +//Print the bitmap of a char on the video output +// x, y - the top left of the char +// width, height - size of the char's bitmap +// scale - how much to scale the bitmap +// fc, bc - foreground and background colour +// bitmap - pointer to the bitmap +void draw_bitmap_spi(int x1, int y1, int width, int height, int scale, int fc, int bc, unsigned char *bitmap); +void draw_buffer_spi(int x1, int y1, int x2, int y2, unsigned char *p); + + +extern char lcd_put_char(char c, int flush); +extern void lcd_print_string(char* s); + +extern void lcd_spi_init(); +extern void lcd_init(); +extern void lcd_clear(); +extern void reset_controller(void); +extern void pin_set_bit(int pin, unsigned int offset); + + +#endif diff --git a/Code/picocalc_lvgl_graphics_demo/lib/lvgl/CMakeLists.txt b/Code/picocalc_lvgl_graphics_demo/lib/lvgl/CMakeLists.txt new file mode 100644 index 0000000..872edc3 --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/lib/lvgl/CMakeLists.txt @@ -0,0 +1,17 @@ +file(GLOB_RECURSE LVGL_SOURCES lvgl/src/*.c lvgl/port/*.c) +add_library(lvgl ${LVGL_SOURCES}) + +set_property(TARGET lvgl APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES +$ +) + +# Add LVGL demo sources +file(GLOB_RECURSE LVGL_DEMO_SOURCES lvgl/demos/*.c) +add_library(lvgl_demos ${LVGL_DEMO_SOURCES}) + +set_property(TARGET lvgl_demos APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES +$ +) + +# Link lvgl library to lvgl_demos +target_link_libraries(lvgl_demos PRIVATE lvgl) diff --git a/Code/picocalc_lvgl_graphics_demo/lib/lvgl/lvgl b/Code/picocalc_lvgl_graphics_demo/lib/lvgl/lvgl new file mode 160000 index 0000000..04ffa24 --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/lib/lvgl/lvgl @@ -0,0 +1 @@ +Subproject commit 04ffa24f4bca05af35de82947e215f4cf1e4f84d diff --git a/Code/picocalc_lvgl_graphics_demo/lv_conf.h b/Code/picocalc_lvgl_graphics_demo/lv_conf.h new file mode 100644 index 0000000..606a772 --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/lv_conf.h @@ -0,0 +1,148 @@ +/** + * @file lv_conf.h + * Configuration file for LVGL v8.3.0 + * + * Author: LVGL, Hsuan Han Lai + * Date: 2025-03-31 + * Description: LVGL configuration file for the PicoCalc (Raspberry Pi Pico with ILI9488 display) + * + */ + + #ifndef LV_CONF_H + #define LV_CONF_H + + #include + + /*==================== + COLOR SETTINGS + *====================*/ + #define LV_COLOR_DEPTH 16 /*16-bit color depth*/ + #define LV_COLOR_16_SWAP 0 + #define LV_COLOR_MIX_ROUND_OFS (128) + + /*==================== + MEMORY SETTINGS + *====================*/ + #define LV_MEM_SIZE (48 * 1024U) /*48KB memory pool*/ + #define LV_MEM_CUSTOM 0 + + /*==================== + HAL SETTINGS + *====================*/ + #define LV_TICK_CUSTOM 0 + #if LV_TICK_CUSTOM + #define LV_TICK_CUSTOM_INCLUDE "pico/stdlib.h" + #define LV_TICK_CUSTOM_SYS_TIME_EXPR (to_ms_since_boot(get_absolute_time())) + #endif + + /*==================== + DISPLAY SETTINGS + *====================*/ + #define LV_HOR_RES_MAX 320 /*ILI9488 typical width (when oriented vertically)*/ + #define LV_VER_RES_MAX 320 /*ILI9488 typical height*/ + + /* Use 2 buffers (1/10 screen size) */ + #define LV_DISP_DOUBLE_BUFFER 0 + #define LV_DISP_BUF_SIZE (LV_HOR_RES_MAX * LV_VER_RES_MAX / 10) + + /*=================== + * INPUT DEVICE SETTINGS + *===================*/ + #define LV_INDEV_DEF_READ_PERIOD 30 + + /*=================== + * FEATURE CONFIGURATION + *===================*/ + #define LV_USE_ASSERT_NULL 1 + #define LV_USE_ASSERT_MALLOC 1 + #define LV_USE_LOG 1 + #if LV_USE_LOG + #define LV_LOG_PRINTF 1 + #endif + + /*=================== + * FONT USAGE + *===================*/ + #define LV_FONT_MONTSERRAT_12 1 + #define LV_FONT_MONTSERRAT_14 1 + #define LV_FONT_DEFAULT &lv_font_montserrat_14 + + /*=================== + * THEME USAGE + *===================*/ + #define LV_USE_THEME_DEFAULT 1 + + /*=================== + * WIDGET USAGE + *===================*/ + #define LV_USE_LABEL 1 + #define LV_USE_BTN 1 + #define LV_USE_SLIDER 1 + #define LV_USE_IMG 1 + #define LV_USE_ARC 1 + #define LV_USE_BAR 1 + #define LV_USE_CHART 1 + #define LV_USE_CHECKBOX 1 + #define LV_USE_DROPDOWN 1 + #define LV_USE_LINE 1 + #define LV_USE_ROLLER 1 + #define LV_USE_SWITCH 1 + #define LV_USE_TABLE 1 + #define LV_USE_TEXTAREA 1 + /* Add other widgets as needed */ + + /*=================== + * LAYOUT USAGE + *===================*/ + #define LV_USE_GRID 1 + #define LV_USE_FLEX 1 + + /*=================== + * DEMO USAGE + ====================*/ + +/* Show some widget. It might be required to increase `LV_MEM_SIZE` */ +#define LV_USE_DEMO_WIDGETS 1 + +/* Demonstrate the usage of encoder and keyboard */ +#define LV_USE_DEMO_KEYPAD_AND_ENCODER 0 + +/* Benchmark your system */ +#define LV_USE_DEMO_BENCHMARK 0 + +/* Stress test for LVGL */ +#define LV_USE_DEMO_STRESS 0 + +/* Music player demo */ +#define LV_USE_DEMO_MUSIC 0 +#if LV_USE_DEMO_MUSIC +# define LV_DEMO_MUSIC_SQUARE 0 +# define LV_DEMO_MUSIC_LANDSCAPE 0 +# define LV_DEMO_MUSIC_ROUND 0 +# define LV_DEMO_MUSIC_LARGE 0 +# define LV_DEMO_MUSIC_AUTO_PLAY 0 +#endif + +/* Flex layout demo */ +#define LV_USE_DEMO_FLEX_LAYOUT 0 + +/* Smart-phone like multi-language demo */ +#define LV_USE_DEMO_MULTILANG 0 + +/* Widget transformation demo */ +#define LV_USE_DEMO_TRANSFORM 0 + +/* Demonstrate scroll settings */ +#define LV_USE_DEMO_SCROLL 0 + + + /*================== + * COMPILER SETTINGS + *==================*/ + #ifdef __cplusplus + #define LV_EXTERN_C extern "C" + #else + #define LV_EXTERN_C + #endif + + #endif /*LV_CONF_H*/ diff --git a/Code/picocalc_lvgl_graphics_demo/lv_port_disp_picocalc_ILI9488.c b/Code/picocalc_lvgl_graphics_demo/lv_port_disp_picocalc_ILI9488.c new file mode 100644 index 0000000..c831294 --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/lv_port_disp_picocalc_ILI9488.c @@ -0,0 +1,122 @@ +/** + * @file lv_port_disp.c + * + */ + +/*Copy this file as "lv_port_disp.c" and set this value to "1" to enable content*/ +#if 1 + +/********************* + * INCLUDES + *********************/ +#include "lv_port_disp_picocalc_ILI9488.h" +#include +#include "lcdspi/lcdspi.h" + + + +/********************* + * DEFINES + *********************/ +#define LV_DISP_ROT_NONE 0 + +#ifndef MY_DISP_HOR_RES + #define MY_DISP_HOR_RES 320 +#endif + +#ifndef MY_DISP_VER_RES + #define MY_DISP_VER_RES 320 +#endif + +#define BYTE_PER_PIXEL (LV_COLOR_FORMAT_GET_SIZE(LV_COLOR_FORMAT_RGB565)) /*will be 2 for RGB565 */ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void disp_init(void); + +static void disp_flush(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void lv_port_disp_init(void) +{ + /*------------------------- + * Initialize your display + * -----------------------*/ + disp_init(); + + /*------------------------------------ + * Create a display and set a flush_cb + * -----------------------------------*/ + lv_display_t * disp = lv_display_create(MY_DISP_HOR_RES, MY_DISP_VER_RES); + lv_display_set_flush_cb(disp, disp_flush); + + /* One buffer for partial rendering */ + LV_ATTRIBUTE_MEM_ALIGN + static uint8_t buf_1[MY_DISP_HOR_RES * 10 * BYTE_PER_PIXEL]; /*A buffer for 10 rows*/ + lv_display_set_buffers(disp, buf_1, NULL, sizeof(buf_1), LV_DISPLAY_RENDER_MODE_PARTIAL); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/*Initialize your display and the required peripherals.*/ +static void disp_init(void) +{ + /* Initialize the custom LCD SPI interface */ + lcd_init(); +} + +volatile bool disp_flush_enabled = true; + +/* Enable updating the screen (the flushing process) when disp_flush() is called by LVGL + */ +void disp_enable_update(void) +{ + disp_flush_enabled = true; +} + +/* Disable updating the screen (the flushing process) when disp_flush() is called by LVGL + */ +void disp_disable_update(void) +{ + disp_flush_enabled = false; +} + +/*Flush the content of the internal buffer the specific area on the display. + *`px_map` contains the rendered image as raw pixel map and it should be copied to `area` on the display. + *You can use DMA or any hardware acceleration to do this operation in the background but + *'lv_display_flush_ready()' has to be called when it's finished.*/ +static void disp_flush(lv_display_t * disp_drv, const lv_area_t * area, uint8_t * px_map) +{ + if(disp_flush_enabled) { + /* Use the lcdspi function to transfer the rendered area to the screen */ + draw_buffer_spi(area->x1, area->y1, area->x2, area->y2, px_map); + } + + /*IMPORTANT!!! + *Inform the graphics library that you are ready with the flushing*/ + lv_display_flush_ready(disp_drv); +} + +#else /*Enable this file at the top*/ + +/*This dummy typedef exists purely to silence -Wpedantic.*/ +typedef int keep_pedantic_happy; +#endif diff --git a/Code/picocalc_lvgl_graphics_demo/lv_port_disp_picocalc_ILI9488.h b/Code/picocalc_lvgl_graphics_demo/lv_port_disp_picocalc_ILI9488.h new file mode 100644 index 0000000..f04c18c --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/lv_port_disp_picocalc_ILI9488.h @@ -0,0 +1,56 @@ +/** + * @file lv_port_disp_picocalc_ILI9488.h + * + */ + +#if 1 + +#ifndef LV_PORT_DISP_PICOCALC_ILI9488_H +#define LV_PORT_DISP_PICOCALC_ILI9488_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#if defined(LV_LVGL_H_INCLUDE_SIMPLE) +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/* Initialize low level display driver */ +void lv_port_disp_init(void); + +/* Enable updating the screen (the flushing process) when disp_flush() is called by LVGL + */ +void disp_enable_update(void); + +/* Disable updating the screen (the flushing process) when disp_flush() is called by LVGL + */ +void disp_disable_update(void); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_PORT_DISP_PICOCALC_ILI9488_H*/ + +#endif /*Disable/Enable content*/ diff --git a/Code/picocalc_lvgl_graphics_demo/lv_port_indev_picocalc_kb.c b/Code/picocalc_lvgl_graphics_demo/lv_port_indev_picocalc_kb.c new file mode 100644 index 0000000..e008eec --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/lv_port_indev_picocalc_kb.c @@ -0,0 +1,151 @@ +/** + * @file lv_port_indev_templ.c + * + */ + +/*Copy this file as "lv_port_indev.c" and set this value to "1" to enable content*/ + +/********************* + * INCLUDES + *********************/ +#include "i2ckbd.h" +#include +#include +#include +#include "lv_port_indev_picocalc_kb.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void keypad_init(void); +static void keypad_read(lv_indev_t * indev, lv_indev_data_t * data); +static int keypad_get_key(void); + + +/********************** + * STATIC VARIABLES + **********************/ +lv_indev_t * indev_keypad; +static lv_group_t *g; /* Group for keyboard navigation */ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void lv_port_indev_init(void) +{ + /** + * Here you will find example implementation of input devices supported by LittelvGL: + * - Touchpad + * - Mouse (with cursor support) + * - Keypad (supports GUI usage only with key) + * - Encoder (supports GUI usage only with: left, right, push) + * - Button (external buttons to press points on the screen) + * + * The `..._read()` function are only examples. + * You should shape them according to your hardware + */ + + + /*------------------ + * Keypad + * -----------------*/ + + keypad_init(); + + /*Register a keypad input device*/ + indev_keypad = lv_indev_create(); + lv_indev_set_type(indev_keypad, LV_INDEV_TYPE_KEYPAD); + lv_indev_set_read_cb(indev_keypad, keypad_read); + + /*Create a group for keyboard navigation*/ + g = lv_group_create(); + lv_group_set_default(g); + lv_group_set_wrap(g, true); + lv_indev_set_group(indev_keypad, g); + + /* + * For keyboard navigation to work: + * 1. Objects must be added to this group either: + * - Automatically if they support default grouping + * - Manually using lv_group_add_obj(g, obj) + * 2. The group receives key events from the input device + * 3. The group navigates focus among objects when arrow keys are pressed + * 4. Focused objects receive other key events (like Enter) + */ +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void keypad_init(void) +{ + init_i2c_kbd(); +} + +static void keypad_read(lv_indev_t * indev_drv, lv_indev_data_t * data) +{ + static uint32_t last_key = 0; + static bool pending_release = false; + + /* Check if we need to send a release event for the previous key */ + if(pending_release) { + data->state = LV_INDEV_STATE_RELEASED; + data->key = last_key; + pending_release = false; + return; + } + + /*Get whether the a key is pressed and save the pressed key*/ + int r = keypad_get_key(); + + if (r > 0) { + printf("Key event %x\n", r); + + uint32_t act_key = 0; + /*Translate the keys to LVGL control characters according to your key definitions*/ + switch(r) { + case 0xb5: + act_key = LV_KEY_NEXT; + break; + case 0xb6: + act_key = LV_KEY_PREV; + break; + default: + act_key = r; + break; + } + + data->state = LV_INDEV_STATE_PRESSED; + data->key = act_key; + last_key = act_key; + pending_release = true; + } + else { + data->state = LV_INDEV_STATE_RELEASED; + data->key = 0; + } +} + +static int keypad_get_key(void) +{ + int key_code = read_i2c_kbd(); + if (key_code < 0) { + return 0; + } + + return key_code; +} diff --git a/Code/picocalc_lvgl_graphics_demo/lv_port_indev_picocalc_kb.h b/Code/picocalc_lvgl_graphics_demo/lv_port_indev_picocalc_kb.h new file mode 100644 index 0000000..d4b0b2a --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/lv_port_indev_picocalc_kb.h @@ -0,0 +1,48 @@ + +/** + * @file lv_port_indev_picocalc_kb.h + * + */ + +#if 1 + +#ifndef LV_PORT_INDEV_PICOCALC_KB_H +#define LV_PORT_INDEV_PICOCALC_KB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#if defined(LV_LVGL_H_INCLUDE_SIMPLE) +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void lv_port_indev_init(void); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_PORT_INDEV_PICOCALC_KB_H*/ + +#endif /*Disable/Enable content*/ diff --git a/Code/picocalc_lvgl_graphics_demo/main.c b/Code/picocalc_lvgl_graphics_demo/main.c new file mode 100644 index 0000000..29260ad --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/main.c @@ -0,0 +1,79 @@ +/** + * PicoCalc LVGL Graphics Demo + * + * Demo App Uses LVGL to show demos on the PicoCalc. + * Implements basic keyboard input and display driver. + * + * Author: HsuahHanLai + * https://www.hsuanhanlai.com/ + */ + +#include +#include +#include "pico/stdlib.h" +#include "hardware/gpio.h" + + +#include "lv_conf.h" +#include "lvgl/lvgl.h" +#include "lv_port_indev_picocalc_kb.h" +#include "lv_port_disp_picocalc_ILI9488.h" +#include "lvgl/demos/lv_demos.h" + + +#define ILI9488 1 +#define USE_DEFAULT_DEMO 1 + +#define BYTE_PER_PIXEL (LV_COLOR_FORMAT_GET_SIZE(LV_COLOR_FORMAT_RGB565)) /*will be 2 for RGB565 */ + + +const unsigned int LEDPIN = 25; + +int main() +{ + // Initialize standard I/O + stdio_init_all(); + + // Initialize LED + gpio_init(LEDPIN); + gpio_set_dir(LEDPIN, GPIO_OUT); + + // Initialize LVGL + lv_init(); + + // Initialize the custom display driver + lv_port_disp_init(); + + // Initialize the keyboard input device (implementation in lv_port_indev_kbd.c) + lv_port_indev_init(); + + + +#ifdef USE_DEFAULT_DEMO + // Initialize and run LVGL demo + lv_demo_widgets(); // Replace with the correct demo function if needed +#else + // Create a screen + lv_obj_t *screen = lv_obj_create(NULL); + + // Create a text box + lv_obj_t *textbox = lv_textarea_create(screen); + lv_obj_set_size(textbox, 200, 50); // Set size of the text box + lv_obj_align(textbox, LV_ALIGN_CENTER, 0, 0); // Center the text box on the screen + + // Enable keyboard input for the text box + lv_textarea_set_placeholder_text(textbox, "Enter text..."); + lv_textarea_set_one_line(textbox, true); // Set to single-line mode + + // Load the screen + lv_scr_load(screen); +#endif + + // Main loop + while (1) + { + lv_timer_handler(); + lv_tick_inc(5); // Increment LVGL tick by 5 milliseconds + sleep_ms(1); // Sleep for 5 milliseconds} + } +} diff --git a/Code/picocalc_lvgl_graphics_demo/pico_sdk_import.cmake b/Code/picocalc_lvgl_graphics_demo/pico_sdk_import.cmake new file mode 100644 index 0000000..65f8a6f --- /dev/null +++ b/Code/picocalc_lvgl_graphics_demo/pico_sdk_import.cmake @@ -0,0 +1,73 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + GIT_SUBMODULES_RECURSE FALSE + ) + else () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + ) + endif () + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + FetchContent_Populate(pico_sdk) + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE})