diff --git a/drivers/st7789/st7789.cpp b/drivers/st7789/st7789.cpp index d5e99ed7..4abc5d6f 100644 --- a/drivers/st7789/st7789.cpp +++ b/drivers/st7789/st7789.cpp @@ -55,6 +55,8 @@ namespace pimoroni { }; void ST7789::init(bool auto_init_sequence, bool round, uint32_t spi_baud) { + this->round = round; + // configure spi interface and pins spi_init(spi, spi_baud); @@ -96,33 +98,29 @@ namespace pimoroni { sleep_ms(150); + // Common init command(reg::TEON); // enable frame sync signal if used command(reg::COLMOD, 1, "\x05"); // 16 bits per pixel + command(reg::PORCTRL, 5, "\x0c\x0c\x00\x33\x33"); + command(reg::LCMCTRL, 1, "\x2c"); + command(reg::VDVVRHEN, 1, "\x01"); + command(reg::VRHS, 1, "\x12"); + command(reg::VDVS, 1, "\x20"); + command(reg::PWCTRL1, 2, "\xa4\xa1"); + command(reg::FRCTRL2, 1, "\x0f"); + if(width == 240 && height == 240) { - command(reg::PORCTRL, 5, "\x0c\x0c\x00\x33\x33"); command(reg::GCTRL, 1, "\x14"); command(reg::VCOMS, 1, "\x37"); - command(reg::LCMCTRL, 1, "\x2c"); - command(reg::VDVVRHEN, 1, "\x01"); - command(reg::VRHS, 1, "\x12"); - command(reg::VDVS, 1, "\x20"); - command(reg::PWCTRL1, 2, "\xa4\xa1"); - command(reg::FRCTRL2, 1, "\x0f"); command(reg::GMCTRP1, 14, "\xD0\x04\x0D\x11\x13\x2B\x3F\x54\x4C\x18\x0D\x0B\x1F\x23"); command(reg::GMCTRN1, 14, "\xD0\x04\x0C\x11\x13\x2C\x3F\x44\x51\x2F\x1F\x1F\x20\x23"); } - if(width == 320 && height == 240) { - command(reg::PORCTRL, 5, "\x0c\x0c\x00\x33\x33"); + if((width == 320 && height == 240) + || (width == 240 && height == 320)) { command(reg::GCTRL, 1, "\x35"); command(reg::VCOMS, 1, "\x1f"); - command(reg::LCMCTRL, 1, "\x2c"); - command(reg::VDVVRHEN, 1, "\x01"); - command(reg::VRHS, 1, "\x12"); - command(reg::VDVS, 1, "\x20"); - command(reg::FRCTRL2, 1, "\x0f"); - command(reg::PWCTRL1, 2, "\xa4\xa1"); command(0xd6, 1, "\xa1"); // ??? command(reg::GMCTRP1, 14, "\xD0\x08\x11\x08\x0C\x15\x39\x33\x50\x36\x13\x14\x29\x2D"); command(reg::GMCTRN1, 14, "\xD0\x08\x10\x08\x06\x06\x39\x44\x51\x0B\x16\x14\x2F\x31"); @@ -134,48 +132,7 @@ namespace pimoroni { 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; - } - - if(width == 320 && height == 240) { - caset[0] = 0; - caset[1] = 319; - raset[0] = 0; - raset[1] = 239; - madctl = 0x70; - } - - // 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); + configure_display(false); if(bl != PIN_UNUSED) { update(); // Send the new buffer to the display to clear any previous content @@ -205,6 +162,65 @@ namespace pimoroni { // dma_channel, &config, &spi_get_hw(spi)->dr, frame_buffer, width * height, false); } + void ST7789::configure_display(bool rotate180) { + // 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; + } + + // Pico Display + if(width == 240 && height == 135) { + caset[0] = 40; // 240 cols + caset[1] = 279; + raset[0] = 53; // 135 rows + raset[1] = 187; + madctl = rotate180 ? MADCTL::ROW_ORDER : MADCTL::COL_ORDER; + madctl |= MADCTL::SWAP_XY | MADCTL::SCAN_ORDER; + } + + // Pico Display at 90 degree rotation + if(width == 135 && height == 240) { + caset[0] = 52; // 135 cols + caset[1] = 186; + raset[0] = 40; // 240 rows + raset[1] = 279; + madctl = rotate180 ? (MADCTL::COL_ORDER | MADCTL::ROW_ORDER) : 0; + } + + // Pico Display 2.0 + if(width == 320 && height == 240) { + caset[0] = 0; + caset[1] = 319; + raset[0] = 0; + raset[1] = 239; + madctl = rotate180 ? MADCTL::ROW_ORDER : MADCTL::COL_ORDER; + madctl |= MADCTL::SWAP_XY | MADCTL::SCAN_ORDER; + } + + // Pico Display 2.0 at 90 degree rotation + if(width == 240 && height == 320) { + caset[0] = 0; + caset[1] = 239; + raset[0] = 0; + raset[1] = 319; + madctl = rotate180 ? (MADCTL::COL_ORDER | MADCTL::ROW_ORDER) : 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); + } + spi_inst_t* ST7789::get_spi() const { return spi; } diff --git a/drivers/st7789/st7789.hpp b/drivers/st7789/st7789.hpp index 79fae446..62f7c532 100644 --- a/drivers/st7789/st7789.hpp +++ b/drivers/st7789/st7789.hpp @@ -17,6 +17,7 @@ namespace pimoroni { // screen properties uint16_t width; uint16_t height; + bool round; uint16_t row_stride; uint32_t dma_channel; @@ -33,6 +34,7 @@ namespace pimoroni { // 16 ns = 62,500,000 Hz static const uint32_t SPI_BAUD = 62'500'000; + public: // frame buffer where pixel data is stored uint16_t *frame_buffer; @@ -74,6 +76,7 @@ namespace pimoroni { //-------------------------------------------------- public: void init(bool auto_init_sequence = true, bool round = false, uint32_t spi_baud = SPI_BAUD); + void configure_display(bool rotate180); spi_inst_t* get_spi() const; uint get_cs() const; diff --git a/libraries/generic_st7789/generic_st7789.cpp b/libraries/generic_st7789/generic_st7789.cpp index b45ffd4e..a1cd28bd 100644 --- a/libraries/generic_st7789/generic_st7789.cpp +++ b/libraries/generic_st7789/generic_st7789.cpp @@ -56,4 +56,8 @@ namespace pimoroni { void ST7789Generic::set_backlight(uint8_t brightness) { st7789.set_backlight(brightness); } + + void ST7789Generic::configure_display(bool rotate180) { + st7789.configure_display(rotate180); + } } diff --git a/libraries/generic_st7789/generic_st7789.hpp b/libraries/generic_st7789/generic_st7789.hpp index 58027d44..f338cf54 100644 --- a/libraries/generic_st7789/generic_st7789.hpp +++ b/libraries/generic_st7789/generic_st7789.hpp @@ -25,6 +25,7 @@ namespace pimoroni { void update(); void flip(); void set_backlight(uint8_t brightness); + void configure_display(bool rotate180); }; } diff --git a/micropython/modules/st7789/st7789.cpp b/micropython/modules/st7789/st7789.cpp index 8cb84f1c..d6a9fbd3 100644 --- a/micropython/modules/st7789/st7789.cpp +++ b/micropython/modules/st7789/st7789.cpp @@ -51,10 +51,11 @@ void GenericST7789_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kin mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { GenericST7789_obj_t *self = nullptr; - enum { ARG_width, ARG_height, ARG_slot, ARG_buffer, ARG_spi, ARG_cs, ARG_dc, ARG_sck, ARG_mosi, ARG_bl }; + enum { ARG_width, ARG_height, ARG_rotate180, ARG_slot, ARG_buffer, ARG_spi, ARG_cs, ARG_dc, ARG_sck, ARG_mosi, ARG_bl }; static const mp_arg_t allowed_args[] = { { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_rotate180, MP_ARG_OBJ, {.u_obj = mp_const_false} }, { MP_QSTR_slot, MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_buffer, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_spi, MP_ARG_INT, {.u_int = -1} }, @@ -72,6 +73,7 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t self = m_new_obj(GenericST7789_obj_t); self->base.type = &GenericST7789_type; + bool rotate180 = args[ARG_rotate180].u_obj == mp_const_true; int width = args[ARG_width].u_int; int height = args[ARG_height].u_int; @@ -90,6 +92,9 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t if(args[ARG_slot].u_int != -1) { BG_SPI_SLOT slot = (BG_SPI_SLOT)args[ARG_slot].u_int; self->st7789 = new ST7789Generic(width, height, slot, buffer); + if (rotate180) { + self->st7789->configure_display(true); + } } else { // Get SPI bus. int spi_id = args[ARG_spi].u_int; @@ -117,6 +122,9 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t self->st7789 = new ST7789Generic(width, height, spi, cs, dc, sck, mosi, PIN_UNUSED, bl, buffer); + if (rotate180) { + self->st7789->configure_display(true); + } } return MP_OBJ_FROM_PTR(self);