From 237d59d1d16f0b9998b923ff9b2466ac005e6d0f Mon Sep 17 00:00:00 2001 From: David Tillotson Date: Sat, 6 Mar 2021 16:45:38 +0000 Subject: [PATCH 1/7] Slight efactor of st7789 driver, and addition of the flip function --- drivers/st7789/st7789.cpp | 19 +++++++++++++------ drivers/st7789/st7789.hpp | 1 + libraries/pico_display/pico_display.cpp | 5 ++++- libraries/pico_display/pico_display.hpp | 3 ++- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index 251e8e90..099fb0b4 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -7,6 +7,7 @@ #include "hardware/pwm.h" namespace pimoroni { + char madctl[2]; void ST7789::init(bool auto_init_sequence) { // configure spi interface and pins @@ -50,15 +51,16 @@ namespace pimoroni { sleep_ms(150); if(width == 240 && height == 240) { - command(reg::MADCTL, 1, "\x04"); // row/column addressing order - rgb pixel order - command(reg::TEON, 1, "\x00"); // enable frame sync signal if used - command(reg::COLMOD, 1, "\x05"); // 16 bits per pixel + madctl = 0x04; } if(width == 240 && height == 135) { - command(reg::MADCTL, 1, "\x70"); - command(reg::COLMOD, 1, "\x05"); + madctl = 0x70; } + + command(reg::MADCTL, 1, madctl); // row/column addressing order - rgb pixel order + command(reg::TEON, 1, "\x00"); // enable frame sync signal if used + command(reg::COLMOD, 1, "\x05"); // 16 bits per pixel command(reg::INVON); // set inversion mode command(reg::SLPOUT); // leave sleep mode @@ -147,4 +149,9 @@ namespace pimoroni { void ST7789::vsync_callback(gpio_irq_callback_t callback) { gpio_set_irq_enabled_with_callback(vsync, GPIO_IRQ_EDGE_RISE, true, callback); } -} \ No newline at end of file + + void ST7789::flip(){ + madctl[0] ^= 0xC0; + command(reg::MADCTL, 1, madctl); + } +} diff --git a/drivers/st7789/st7789.hpp b/drivers/st7789/st7789.hpp index d4b62bff..76bef36a 100644 --- a/drivers/st7789/st7789.hpp +++ b/drivers/st7789/st7789.hpp @@ -47,6 +47,7 @@ namespace pimoroni { void vsync_callback(gpio_irq_callback_t callback); void update(bool dont_block = false); void set_backlight(uint8_t brightness); + void flip(); enum reg { SWRESET = 0x01, diff --git a/libraries/pico_display/pico_display.cpp b/libraries/pico_display/pico_display.cpp index 9b2720a9..3cc66c52 100644 --- a/libraries/pico_display/pico_display.cpp +++ b/libraries/pico_display/pico_display.cpp @@ -79,4 +79,7 @@ namespace pimoroni { return !gpio_get(button); } -} \ No newline at end of file + void flip() { + screen.flip(); + } +} diff --git a/libraries/pico_display/pico_display.hpp b/libraries/pico_display/pico_display.hpp index 152c6e7c..abc4e41c 100644 --- a/libraries/pico_display/pico_display.hpp +++ b/libraries/pico_display/pico_display.hpp @@ -26,6 +26,7 @@ namespace pimoroni { void set_backlight(uint8_t brightness); void set_led(uint8_t r, uint8_t g, uint8_t b); bool is_pressed(uint8_t button); + void flip(); }; -} \ No newline at end of file +} From 98b633f31f1366bf57c700606ededc7698f754fa Mon Sep 17 00:00:00 2001 From: David Tillotson Date: Sat, 6 Mar 2021 17:02:48 +0000 Subject: [PATCH 2/7] Correct version of the st7789.cpp driver! --- drivers/st7789/st7789.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index 099fb0b4..77528dec 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -51,11 +51,11 @@ namespace pimoroni { sleep_ms(150); if(width == 240 && height == 240) { - madctl = 0x04; + madctl[0] = 0x04; } if(width == 240 && height == 135) { - madctl = 0x70; + madctl[0] = 0x70; } command(reg::MADCTL, 1, madctl); // row/column addressing order - rgb pixel order From baf16fc332b3e1c6ed658a7822464c06bfd616b6 Mon Sep 17 00:00:00 2001 From: David Tillotson Date: Sat, 6 Mar 2021 17:12:47 +0000 Subject: [PATCH 3/7] And the correct version of pico_display.cpp! --- libraries/pico_display/pico_display.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/pico_display/pico_display.cpp b/libraries/pico_display/pico_display.cpp index 3cc66c52..f4b38031 100644 --- a/libraries/pico_display/pico_display.cpp +++ b/libraries/pico_display/pico_display.cpp @@ -79,7 +79,7 @@ namespace pimoroni { return !gpio_get(button); } - void flip() { + void PicoDisplay::flip() { screen.flip(); } } From 1993d403e5e18b94384ecf5ee9428ec2da135223 Mon Sep 17 00:00:00 2001 From: David Tillotson Date: Sat, 6 Mar 2021 21:27:40 +0000 Subject: [PATCH 4/7] Added portrait mode (building with the work from hamid-elaosta:portrait) --- drivers/st7789/st7789.cpp | 9 +++++++++ libraries/pico_display/pico_display.cpp | 5 +++++ libraries/pico_display/pico_display.hpp | 5 ++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index 77528dec..0c1c567a 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -58,6 +58,10 @@ namespace pimoroni { madctl[0] = 0x70; } + if(width == 135 && height == 240) { + madctl[0] = 0x00; + } + command(reg::MADCTL, 1, madctl); // row/column addressing order - rgb pixel order command(reg::TEON, 1, "\x00"); // enable frame sync signal if used command(reg::COLMOD, 1, "\x05"); // 16 bits per pixel @@ -78,6 +82,11 @@ namespace pimoroni { command(reg::RASET, 4, "\x00\x35\x00\xbb"); // 53 .. 187 (135 rows) command(reg::CASET, 4, "\x00\x28\x01\x17"); // 40 .. 279 (240 columns) } + + if(width == 135 && height == 240) { + command(reg::CASET, 4, "\x00\x34\x00\xba"); // 52 .. 186 (135 rows) + command(reg::RASET, 4, "\x00\x28\x01\x17"); // 40 .. 279 (240 columns) + } } // the dma transfer works but without vsync it's not that useful as you could diff --git a/libraries/pico_display/pico_display.cpp b/libraries/pico_display/pico_display.cpp index f4b38031..0e2606e5 100644 --- a/libraries/pico_display/pico_display.cpp +++ b/libraries/pico_display/pico_display.cpp @@ -17,6 +17,11 @@ namespace pimoroni { __fb = buf; } + PicoDisplay::PicoDisplay(uint16_t *buf, int width, int height) + : PicoGraphics(width, height, buf), screen(width, height, buf) { + __fb = buf; + } + void PicoDisplay::init() { // setup the rgb led for pwm control pwm_config cfg = pwm_get_default_config(); diff --git a/libraries/pico_display/pico_display.hpp b/libraries/pico_display/pico_display.hpp index abc4e41c..a0553abf 100644 --- a/libraries/pico_display/pico_display.hpp +++ b/libraries/pico_display/pico_display.hpp @@ -9,7 +9,9 @@ namespace pimoroni { public: static const int WIDTH = 240; static const int HEIGHT = 135; - static const uint8_t A = 12; + static const int PORTRAIT_WIDTH = 135; + static const int PORTRAIT_HEIGHT = 240; + static const uint8_t A = 12; static const uint8_t B = 13; static const uint8_t X = 14; static const uint8_t Y = 15; @@ -20,6 +22,7 @@ namespace pimoroni { public: PicoDisplay(uint16_t *buf); + PicoDisplay(uint16_t *buf, int width, int height); void init(); void update(); From 43d7e65ee0bd4d4a6da5958444857513bddb99d4 Mon Sep 17 00:00:00 2001 From: David Tillotson Date: Mon, 8 Mar 2021 13:04:35 +0000 Subject: [PATCH 5/7] Added display.flip to the Micropython code. --- micropython/modules/pico_display/pico_display.c | 4 +++- micropython/modules/pico_display/pico_display.cpp | 9 +++++++++ micropython/modules/pico_display/pico_display.h | 3 ++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/micropython/modules/pico_display/pico_display.c b/micropython/modules/pico_display/pico_display.c index 7678d78f..91d794d6 100755 --- a/micropython/modules/pico_display/pico_display.c +++ b/micropython/modules/pico_display/pico_display.c @@ -22,6 +22,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay_update_obj, picodisplay_update); STATIC MP_DEFINE_CONST_FUN_OBJ_1(picodisplay_set_backlight_obj, picodisplay_set_backlight); STATIC MP_DEFINE_CONST_FUN_OBJ_3(picodisplay_set_led_obj, picodisplay_set_led); STATIC MP_DEFINE_CONST_FUN_OBJ_1(picodisplay_is_pressed_obj, picodisplay_is_pressed); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picodisplay_flip_obj, picodisplay_flip); //From PicoGraphics parent class STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picodisplay_set_pen_obj, 1, 3, picodisplay_set_pen); @@ -47,6 +48,7 @@ STATIC const mp_map_elem_t picodisplay_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&picodisplay_set_backlight_obj) }, { MP_ROM_QSTR(MP_QSTR_set_led), MP_ROM_PTR(&picodisplay_set_led_obj) }, { MP_ROM_QSTR(MP_QSTR_is_pressed), MP_ROM_PTR(&picodisplay_is_pressed_obj) }, + { MP_ROM_QSTR(MP_QSTR_flip), MP_ROM_PTR(&picodisplay_flip_obj) }, { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&picodisplay_set_pen_obj) }, { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&picodisplay_create_pen_obj) }, @@ -75,4 +77,4 @@ const mp_obj_module_t picodisplay_user_cmodule = { //////////////////////////////////////////////////////////////////////////////////////////////////// MP_REGISTER_MODULE(MP_QSTR_picodisplay, picodisplay_user_cmodule, MODULE_PICODISPLAY_ENABLED); //////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +//////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/micropython/modules/pico_display/pico_display.cpp b/micropython/modules/pico_display/pico_display.cpp index 0bf50d83..3d2c0d2b 100644 --- a/micropython/modules/pico_display/pico_display.cpp +++ b/micropython/modules/pico_display/pico_display.cpp @@ -43,6 +43,15 @@ mp_obj_t picodisplay_update() { return mp_const_none; } +mp_obj_t picodisplay_flip() { + if(display != nullptr) + display->flip(); + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + mp_obj_t picodisplay_set_backlight(mp_obj_t brightness_obj) { if(display != nullptr) { float brightness = mp_obj_get_float(brightness_obj); diff --git a/micropython/modules/pico_display/pico_display.h b/micropython/modules/pico_display/pico_display.h index d93fc360..1234e434 100644 --- a/micropython/modules/pico_display/pico_display.h +++ b/micropython/modules/pico_display/pico_display.h @@ -10,6 +10,7 @@ extern mp_obj_t picodisplay_set_backlight(mp_obj_t brightness_obj); extern mp_obj_t picodisplay_update(); extern mp_obj_t picodisplay_set_led(mp_obj_t r_obj, mp_obj_t g_obj, mp_obj_t b_obj); extern mp_obj_t picodisplay_is_pressed(mp_obj_t button_obj); +extern mp_obj_t picodisplay_flip(); // From PicoGraphics parent class extern mp_obj_t picodisplay_set_pen(mp_uint_t n_args, const mp_obj_t *args); @@ -22,4 +23,4 @@ extern mp_obj_t picodisplay_pixel_span(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t extern mp_obj_t picodisplay_rectangle(mp_uint_t n_args, const mp_obj_t *args); extern mp_obj_t picodisplay_circle(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t r_obj); extern mp_obj_t picodisplay_character(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picodisplay_text(mp_uint_t n_args, const mp_obj_t *args); \ No newline at end of file +extern mp_obj_t picodisplay_text(mp_uint_t n_args, const mp_obj_t *args); From f812e23d8e92dda252902c155ac409ab3f154122 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Wed, 24 Mar 2021 12:18:56 +0000 Subject: [PATCH 6/7] Cleaner RASET, CASET and MADCTL handling --- drivers/st7789/CMakeLists.txt | 5 +- drivers/st7789/st7789.cmake | 2 + drivers/st7789/st7789.cpp | 340 +++++++++++++++++----------------- drivers/st7789/st7789.hpp | 176 ++++++++++-------- 4 files changed, 272 insertions(+), 251 deletions(-) diff --git a/drivers/st7789/CMakeLists.txt b/drivers/st7789/CMakeLists.txt index ef26fdc5..d2c835a8 100644 --- a/drivers/st7789/CMakeLists.txt +++ b/drivers/st7789/CMakeLists.txt @@ -1,4 +1 @@ -add_library(st7789 st7789.cpp) - -# Pull in pico libraries that we need -target_link_libraries(st7789 pico_stdlib hardware_spi hardware_pwm hardware_dma) +include(${CMAKE_CURRENT_LIST_DIR}/st7789.cmake) \ No newline at end of file diff --git a/drivers/st7789/st7789.cmake b/drivers/st7789/st7789.cmake index 00c3ef7b..c8d13aea 100644 --- a/drivers/st7789/st7789.cmake +++ b/drivers/st7789/st7789.cmake @@ -1,5 +1,7 @@ add_library(st7789 ${CMAKE_CURRENT_LIST_DIR}/st7789.cpp) +target_include_directories(st7789 INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + # Pull in pico libraries that we need target_link_libraries(st7789 pico_stdlib hardware_spi hardware_pwm hardware_dma) diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index 0c1c567a..705641ff 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -1,166 +1,174 @@ -#include "st7789.hpp" - -#include -#include - -#include "hardware/dma.h" -#include "hardware/pwm.h" - -namespace pimoroni { - char madctl[2]; - - void ST7789::init(bool auto_init_sequence) { - // configure spi interface and pins - spi_init(spi, spi_baud); - - gpio_set_function(dc, GPIO_FUNC_SIO); - gpio_set_dir(dc, GPIO_OUT); - - gpio_set_function(cs, GPIO_FUNC_SIO); - gpio_set_dir(cs, GPIO_OUT); - - gpio_set_function(sck, GPIO_FUNC_SPI); - gpio_set_function(mosi, GPIO_FUNC_SPI); - - if(miso != -1) { - gpio_set_function(miso, GPIO_FUNC_SPI); - } - - // if supported by the display then the vsync pin is - // toggled high during vertical blanking period - if(vsync != -1) { - gpio_set_function(vsync, GPIO_FUNC_SIO); - gpio_set_dir(vsync, GPIO_IN); - gpio_set_pulls(vsync, false, true); - } - - // if a backlight pin is provided then set it up for - // pwm control - if(bl != -1) { - pwm_config cfg = pwm_get_default_config(); - pwm_set_wrap(pwm_gpio_to_slice_num(bl), 65535); - pwm_init(pwm_gpio_to_slice_num(bl), &cfg, true); - gpio_set_function(bl, GPIO_FUNC_PWM); - } - - // if auto_init_sequence then send initialisation sequence - // for our standard displays based on the width and height - if(auto_init_sequence) { - command(reg::SWRESET); - - sleep_ms(150); - - if(width == 240 && height == 240) { - madctl[0] = 0x04; - } - - if(width == 240 && height == 135) { - madctl[0] = 0x70; - } - - if(width == 135 && height == 240) { - madctl[0] = 0x00; - } - - command(reg::MADCTL, 1, madctl); // row/column addressing order - rgb pixel order - command(reg::TEON, 1, "\x00"); // enable frame sync signal if used - command(reg::COLMOD, 1, "\x05"); // 16 bits per pixel - - command(reg::INVON); // set inversion mode - command(reg::SLPOUT); // leave sleep mode - command(reg::DISPON); // turn display on - - sleep_ms(100); - - // setup correct addressing window - if(width == 240 && height == 240) { - command(reg::CASET, 4, "\x00\x00\x00\xef"); // 0 .. 239 columns - command(reg::RASET, 4, "\x00\x00\x00\xef"); // 0 .. 239 rows - } - - if(width == 240 && height == 135) { - command(reg::RASET, 4, "\x00\x35\x00\xbb"); // 53 .. 187 (135 rows) - command(reg::CASET, 4, "\x00\x28\x01\x17"); // 40 .. 279 (240 columns) - } - - if(width == 135 && height == 240) { - command(reg::CASET, 4, "\x00\x34\x00\xba"); // 52 .. 186 (135 rows) - command(reg::RASET, 4, "\x00\x28\x01\x17"); // 40 .. 279 (240 columns) - } - } - - // the dma transfer works but without vsync it's not that useful as you could - // be updating the framebuffer during transfer... - // - // this could be avoided by creating another buffer to draw into and flip - // buffers (but costs another ~100kb of ram) - // - // it's probably not worth it for this particular usecase but will consider it - // some more... - - // setup spi for 16-bit transfers - // spi_set_format(spi, 16, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST); - - // initialise dma channel for transmitting pixel data to screen - // dma_channel = dma_claim_unused_channel(true); - // dma_channel_config config = dma_channel_get_default_config(dma_channel); - // channel_config_set_transfer_data_size(&config, DMA_SIZE_16); - // channel_config_set_dreq(&config, spi_get_index(spi) ? DREQ_SPI1_TX : DREQ_SPI0_TX); - // dma_channel_configure( - // dma_channel, &config, &spi_get_hw(spi)->dr, frame_buffer, width * height, false); - } - - void ST7789::command(uint8_t command, size_t len, const char *data) { - //dma_channel_wait_for_finish_blocking(dma_channel); - - gpio_put(cs, 0); - - gpio_put(dc, 0); // command mode - spi_write_blocking(spi, &command, 1); - - if(data) { - gpio_put(dc, 1); // data mode - spi_write_blocking(spi, (const uint8_t*)data, len); - } - - gpio_put(cs, 1); - } - - void ST7789::update(bool dont_block) { - ST7789::command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer); - - /*if(dma_channel_is_busy(dma_channel) && dont_block) { - return; - } - - dma_channel_wait_for_finish_blocking(dma_channel); - - uint8_t r = reg::RAMWR; - - gpio_put(cs, 0); - - gpio_put(dc, 0); // command mode - spi_write_blocking(spi, &r, 1); - - gpio_put(dc, 1); // data mode - - dma_channel_set_read_addr(dma_channel, frame_buffer, true);*/ - } - - void ST7789::set_backlight(uint8_t brightness) { - // gamma correct the provided 0-255 brightness value onto a - // 0-65535 range for the pwm counter - float gamma = 2.8; - uint16_t value = (uint16_t)(pow((float)(brightness) / 255.0f, gamma) * 65535.0f + 0.5f); - pwm_set_gpio_level(bl, value); - } - - void ST7789::vsync_callback(gpio_irq_callback_t callback) { - gpio_set_irq_enabled_with_callback(vsync, GPIO_IRQ_EDGE_RISE, true, callback); - } - - void ST7789::flip(){ - madctl[0] ^= 0xC0; - command(reg::MADCTL, 1, madctl); - } -} +#include "st7789.hpp" + +#include +#include + +#include "hardware/dma.h" +#include "hardware/pwm.h" + +namespace pimoroni { + uint8_t madctl; + uint16_t caset[2] = {0, 0}; + uint16_t raset[2] = {0, 0}; + + void ST7789::init(bool auto_init_sequence, bool round) { + // configure spi interface and pins + spi_init(spi, spi_baud); + + gpio_set_function(dc, GPIO_FUNC_SIO); + gpio_set_dir(dc, GPIO_OUT); + + gpio_set_function(cs, GPIO_FUNC_SIO); + gpio_set_dir(cs, GPIO_OUT); + + gpio_set_function(sck, GPIO_FUNC_SPI); + gpio_set_function(mosi, GPIO_FUNC_SPI); + + if(miso != -1) { + gpio_set_function(miso, GPIO_FUNC_SPI); + } + + // if supported by the display then the vsync pin is + // toggled high during vertical blanking period + if(vsync != -1) { + gpio_set_function(vsync, GPIO_FUNC_SIO); + gpio_set_dir(vsync, GPIO_IN); + gpio_set_pulls(vsync, false, true); + } + + // if a backlight pin is provided then set it up for + // pwm control + if(bl != -1) { + pwm_config cfg = pwm_get_default_config(); + pwm_set_wrap(pwm_gpio_to_slice_num(bl), 65535); + pwm_init(pwm_gpio_to_slice_num(bl), &cfg, true); + gpio_set_function(bl, GPIO_FUNC_PWM); + } + + // if auto_init_sequence then send initialisation sequence + // for our standard displays based on the width and height + if(auto_init_sequence) { + command(reg::SWRESET); + + sleep_ms(150); + + command(reg::TEON, 1, "\x00"); // enable frame sync signal if used + command(reg::COLMOD, 1, "\x05"); // 16 bits per pixel + + command(reg::INVON); // set inversion mode + command(reg::SLPOUT); // leave sleep mode + command(reg::DISPON); // turn display on + + sleep_ms(100); + + // setup correct addressing window + if(width == 240 && height == 240) { + caset[0] = 0; + caset[1] = 239; + raset[0] = round ? 40 : 0; + raset[1] = round ? 279 : 239; + madctl = MADCTL::HORIZ_ORDER; + } + + if(width == 240 && height == 135) { + caset[0] = 40; // 240 cols + caset[1] = 279; + raset[0] = 53; // 135 rows + raset[1] = 187; + madctl = MADCTL::COL_ORDER | MADCTL::SWAP_XY | MADCTL::SCAN_ORDER; + } + + if(width == 135 && height == 240) { + caset[0] = 52; // 135 cols + caset[1] = 186; + raset[0] = 40; // 240 rows + raset[1] = 279; + madctl = 0; + } + + // Byte swap the 16bit rows/cols values + caset[0] = __builtin_bswap16(caset[0]); + caset[1] = __builtin_bswap16(caset[1]); + raset[0] = __builtin_bswap16(raset[0]); + raset[1] = __builtin_bswap16(raset[1]); + + command(reg::CASET, 4, (char *)caset); + command(reg::RASET, 4, (char *)raset); + command(reg::MADCTL, 1, (char *)&madctl); + } + + // the dma transfer works but without vsync it's not that useful as you could + // be updating the framebuffer during transfer... + // + // this could be avoided by creating another buffer to draw into and flip + // buffers (but costs another ~100kb of ram) + // + // it's probably not worth it for this particular usecase but will consider it + // some more... + + // setup spi for 16-bit transfers + // spi_set_format(spi, 16, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST); + + // initialise dma channel for transmitting pixel data to screen + // dma_channel = dma_claim_unused_channel(true); + // dma_channel_config config = dma_channel_get_default_config(dma_channel); + // channel_config_set_transfer_data_size(&config, DMA_SIZE_16); + // channel_config_set_dreq(&config, spi_get_index(spi) ? DREQ_SPI1_TX : DREQ_SPI0_TX); + // dma_channel_configure( + // dma_channel, &config, &spi_get_hw(spi)->dr, frame_buffer, width * height, false); + } + + void ST7789::command(uint8_t command, size_t len, const char *data) { + //dma_channel_wait_for_finish_blocking(dma_channel); + + gpio_put(cs, 0); + + gpio_put(dc, 0); // command mode + spi_write_blocking(spi, &command, 1); + + if(data) { + gpio_put(dc, 1); // data mode + spi_write_blocking(spi, (const uint8_t*)data, len); + } + + gpio_put(cs, 1); + } + + void ST7789::update(bool dont_block) { + ST7789::command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer); + + /*if(dma_channel_is_busy(dma_channel) && dont_block) { + return; + } + + dma_channel_wait_for_finish_blocking(dma_channel); + + uint8_t r = reg::RAMWR; + + gpio_put(cs, 0); + + gpio_put(dc, 0); // command mode + spi_write_blocking(spi, &r, 1); + + gpio_put(dc, 1); // data mode + + dma_channel_set_read_addr(dma_channel, frame_buffer, true);*/ + } + + void ST7789::set_backlight(uint8_t brightness) { + // gamma correct the provided 0-255 brightness value onto a + // 0-65535 range for the pwm counter + float gamma = 2.8; + uint16_t value = (uint16_t)(pow((float)(brightness) / 255.0f, gamma) * 65535.0f + 0.5f); + pwm_set_gpio_level(bl, value); + } + + void ST7789::vsync_callback(gpio_irq_callback_t callback) { + gpio_set_irq_enabled_with_callback(vsync, GPIO_IRQ_EDGE_RISE, true, callback); + } + + void ST7789::flip(){ + madctl ^= MADCTL::ROW_ORDER | MADCTL::COL_ORDER; + command(reg::MADCTL, 1, (char *)&madctl); + } +} diff --git a/drivers/st7789/st7789.hpp b/drivers/st7789/st7789.hpp index 76bef36a..4b352ada 100644 --- a/drivers/st7789/st7789.hpp +++ b/drivers/st7789/st7789.hpp @@ -1,81 +1,95 @@ -#pragma once - -#include "hardware/spi.h" -#include "hardware/gpio.h" - -namespace pimoroni { - - class ST7789 { - spi_inst_t *spi = spi0; - - uint32_t dma_channel; - - // screen properties - uint16_t width; - uint16_t height; - uint16_t row_stride; - - // interface pins with our standard defaults where appropriate - int8_t cs = 17; - int8_t dc = 16; - int8_t sck = 18; - int8_t mosi = 19; - int8_t miso = -1; // we generally don't use this pin - int8_t bl = 20; - int8_t vsync = -1; // only available on some products - - uint32_t spi_baud = 64 * 1024 * 1024; - - public: - // frame buffer where pixel data is stored - uint16_t *frame_buffer; - - public: - ST7789(uint16_t width, uint16_t height, uint16_t *frame_buffer) : - width(width), height(height), frame_buffer(frame_buffer) {} - - ST7789(uint16_t width, uint16_t height, uint16_t *frame_buffer, - spi_inst_t *spi, - uint8_t cs, uint8_t dc, uint8_t sck, uint8_t mosi, uint8_t miso = -1) : - spi(spi), - width(width), height(height), - cs(cs), dc(dc), sck(sck), mosi(mosi), miso(miso), frame_buffer(frame_buffer) {} - - void init(bool auto_init_sequence = true); - - void command(uint8_t command, size_t len = 0, const char *data = NULL); - void vsync_callback(gpio_irq_callback_t callback); - void update(bool dont_block = false); - void set_backlight(uint8_t brightness); - void flip(); - - enum reg { - SWRESET = 0x01, - TEON = 0x35, - MADCTL = 0x36, - COLMOD = 0x3A, - GCTRL = 0xB7, - VCOMS = 0xBB, - LCMCTRL = 0xC0, - VDVVRHEN = 0xC2, - VRHS = 0xC3, - VDVS = 0xC4, - FRCTRL2 = 0xC6, - PWRCTRL1 = 0xD0, - FRMCTR1 = 0xB1, - FRMCTR2 = 0xB2, - GMCTRP1 = 0xE0, - GMCTRN1 = 0xE1, - INVOFF = 0x20, - SLPOUT = 0x11, - DISPON = 0x29, - GAMSET = 0x26, - DISPOFF = 0x28, - RAMWR = 0x2C, - INVON = 0x21, - CASET = 0x2A, - RASET = 0x2B - }; - }; - -} +#pragma once + +#include "hardware/spi.h" +#include "hardware/gpio.h" + +namespace pimoroni { + + class ST7789 { + spi_inst_t *spi = spi0; + + uint32_t dma_channel; + + // screen properties + uint16_t width; + uint16_t height; + uint16_t row_stride; + + // interface pins with our standard defaults where appropriate + int8_t cs = 17; + int8_t dc = 16; + int8_t sck = 18; + int8_t mosi = 19; + int8_t miso = -1; // we generally don't use this pin + int8_t bl = 21; + int8_t vsync = -1; // only available on some products + + uint32_t spi_baud = 64 * 1024 * 1024; + + public: + // frame buffer where pixel data is stored + uint16_t *frame_buffer; + + public: + ST7789(uint16_t width, uint16_t height, uint16_t *frame_buffer) : + width(width), height(height), frame_buffer(frame_buffer) {} + + ST7789(uint16_t width, uint16_t height, uint16_t *frame_buffer, + spi_inst_t *spi, + uint8_t cs, uint8_t dc, uint8_t sck, uint8_t mosi, uint8_t miso = -1) : + spi(spi), + width(width), height(height), + cs(cs), dc(dc), sck(sck), mosi(mosi), miso(miso), frame_buffer(frame_buffer) {} + + void init(bool auto_init_sequence = true, bool round = false); + + void command(uint8_t command, size_t len = 0, const char *data = NULL); + void vsync_callback(gpio_irq_callback_t callback); + void update(bool dont_block = false); + void set_backlight(uint8_t brightness); + void flip(); + + enum MADCTL : uint8_t { + ROW_ORDER = 0b10000000, + COL_ORDER = 0b01000000, + SWAP_XY = 0b00100000, // AKA "MV" + SCAN_ORDER = 0b00010000, + RGB = 0b00001000, + HORIZ_ORDER = 0b00000100 + }; + + #define ROT_240_240_0 0 + #define ROT_240_240_90 MADCTL::SWAP_XY | MADCTL::HORIZ_ORDER | MADCTL::COL_ORDER + #define ROT_240_240_180 MADCTL::SCAN_ORDER | MADCTL::HORIZ_ORDER | MADCTL::COL_ORDER | MADCTL::ROW_ORDER + #define ROT_240_240_270 MADCTL::SWAP_XY | MADCTL::HORIZ_ORDER | MADCTL::ROW_ORDER + + enum reg { + SWRESET = 0x01, + TEON = 0x35, + MADCTL = 0x36, + COLMOD = 0x3A, + GCTRL = 0xB7, + VCOMS = 0xBB, + LCMCTRL = 0xC0, + VDVVRHEN = 0xC2, + VRHS = 0xC3, + VDVS = 0xC4, + FRCTRL2 = 0xC6, + PWRCTRL1 = 0xD0, + FRMCTR1 = 0xB1, + FRMCTR2 = 0xB2, + GMCTRP1 = 0xE0, + GMCTRN1 = 0xE1, + INVOFF = 0x20, + SLPOUT = 0x11, + DISPON = 0x29, + GAMSET = 0x26, + DISPOFF = 0x28, + RAMWR = 0x2C, + INVON = 0x21, + CASET = 0x2A, + RASET = 0x2B + }; + }; + +} From 67b11826b7cc8d196ff4c7a1f769c99bc9abd845 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 29 Mar 2021 13:18:24 +0100 Subject: [PATCH 7/7] Example/test for ST7789 displays --- examples/CMakeLists.txt | 1 + examples/st7789/CMakeLists.txt | 10 ++++ examples/st7789/demo.cpp | 59 +++++++++++++++++++++ libraries/pico_graphics/CMakeLists.txt | 2 +- libraries/pico_graphics/pico_graphics.cmake | 4 +- 5 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 examples/st7789/CMakeLists.txt create mode 100644 examples/st7789/demo.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index a54f5b34..71dc7e38 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -6,3 +6,4 @@ add_subdirectory(pico_explorer) add_subdirectory(pico_rgb_keypad) add_subdirectory(pico_rtc_display) add_subdirectory(pico_tof_display) +add_subdirectory(st7789) diff --git a/examples/st7789/CMakeLists.txt b/examples/st7789/CMakeLists.txt new file mode 100644 index 00000000..3af6fb42 --- /dev/null +++ b/examples/st7789/CMakeLists.txt @@ -0,0 +1,10 @@ +add_executable( + st7789_demo + demo.cpp +) + +# Pull in pico libraries that we need +target_link_libraries(st7789_demo pico_stdlib hardware_spi st7789 pico_graphics) + +# create map/bin/hex file etc. +pico_add_extra_outputs(st7789_demo) diff --git a/examples/st7789/demo.cpp b/examples/st7789/demo.cpp new file mode 100644 index 00000000..7aa39ea8 --- /dev/null +++ b/examples/st7789/demo.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include + +#include "st7789.hpp" +#include "pico_graphics.hpp" + +#define CS 17 +#define DC 16 +#define SCK 18 +#define MOSI 19 +#define MISO -1 + +using namespace pimoroni; + +class PicoDisplay : public PicoGraphics { + public: + static const int WIDTH = 240; + static const int HEIGHT = 240; + + uint16_t *__fb; + private: + ST7789 screen; + + public: + PicoDisplay(uint16_t *buf) : PicoGraphics(WIDTH, HEIGHT, buf), + screen(WIDTH, HEIGHT, buf, + spi0, + CS, DC, SCK, MOSI, MISO) { + __fb = buf; + } + + void init() { + screen.init(true, true); + //screen.flip(); + }; + void update() { + screen.update(); + } +}; + + +uint16_t buffer[PicoDisplay::WIDTH * PicoDisplay::HEIGHT]; +PicoDisplay display(buffer); + +int main() { + display.init(); + + while(1) { + display.set_pen(0, 0, 0); + display.clear(); + display.set_pen(255, 0, 0); + display.circle(Point(60, 120), 60); + display.set_pen(255, 255, 255); + display.text("Hello", Point(10, 10), 220, 4); + display.update(); + } +} \ No newline at end of file diff --git a/libraries/pico_graphics/CMakeLists.txt b/libraries/pico_graphics/CMakeLists.txt index da981b52..535785e6 100644 --- a/libraries/pico_graphics/CMakeLists.txt +++ b/libraries/pico_graphics/CMakeLists.txt @@ -1 +1 @@ -add_library(pico_graphics types.cpp font_data.cpp pico_graphics.cpp) \ No newline at end of file +include(pico_graphics.cmake) \ No newline at end of file diff --git a/libraries/pico_graphics/pico_graphics.cmake b/libraries/pico_graphics/pico_graphics.cmake index a90b5b40..a69b6463 100644 --- a/libraries/pico_graphics/pico_graphics.cmake +++ b/libraries/pico_graphics/pico_graphics.cmake @@ -1,4 +1,6 @@ add_library(pico_graphics ${CMAKE_CURRENT_LIST_DIR}/types.cpp ${CMAKE_CURRENT_LIST_DIR}/font_data.cpp - ${CMAKE_CURRENT_LIST_DIR}/pico_graphics.cpp) \ No newline at end of file + ${CMAKE_CURRENT_LIST_DIR}/pico_graphics.cpp) + +target_include_directories(pico_graphics INTERFACE ${CMAKE_CURRENT_LIST_DIR}) \ No newline at end of file