diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 07942027..aa35f2d9 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory(esp32spi) add_subdirectory(ltp305) add_subdirectory(ltr559) add_subdirectory(sgp30) +add_subdirectory(st7735) add_subdirectory(st7789) add_subdirectory(msa301) add_subdirectory(rv3028) diff --git a/drivers/st7735/CMakeLists.txt b/drivers/st7735/CMakeLists.txt new file mode 100644 index 00000000..080cb792 --- /dev/null +++ b/drivers/st7735/CMakeLists.txt @@ -0,0 +1 @@ +include(st7735.cmake) diff --git a/drivers/st7735/st7735.cmake b/drivers/st7735/st7735.cmake new file mode 100644 index 00000000..3a44ee58 --- /dev/null +++ b/drivers/st7735/st7735.cmake @@ -0,0 +1,10 @@ +set(DRIVER_NAME st7735) +add_library(${DRIVER_NAME} INTERFACE) + +target_sources(${DRIVER_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${DRIVER_NAME}.cpp) + +target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_spi hardware_pwm hardware_dma) diff --git a/drivers/st7735/st7735.cpp b/drivers/st7735/st7735.cpp new file mode 100644 index 00000000..5f2808fc --- /dev/null +++ b/drivers/st7735/st7735.cpp @@ -0,0 +1,209 @@ +#include "st7735.hpp" + +#include +#include + +#include "hardware/dma.h" +#include "hardware/pwm.h" + +namespace pimoroni { + + enum reg : uint8_t { + SWRESET = 0x01, + RDDID = 0x04, + RDDRST = 0x09, + RDDPM = 0x0A, + RDDMADCTL = 0x0B, + RDDCOLMOD = 0x0C, + RDDIM = 0x0D, + RDDSM = 0x0E, + RDDSDR = 0x0F, + SLPIN = 0x10, + SLPOUT = 0x11, + PTLON = 0x12, + NORON = 0x13, + INVOFF = 0x20, + INVON = 0x21, + GAMSET = 0x26, + DISPOFF = 0x28, + DISPON = 0x29, + CASET = 0x2A, + RASET = 0x2B, + RAMWR = 0x2C, + RGBSET = 0x2D, + RAMRD = 0x2E, + PTLAR = 0x30, + SCRLAR = 0x33, + TEOFF = 0x34, + TEON = 0x35, + MADCTL = 0x36, // Memory Data Access Control + VSCSAD = 0x37, + IDMOFF = 0x38, // Idle Mode Off + IDMON = 0x39, // Idle Mode On + COLMOD = 0x3A, + + FRMCTR1 = 0xB1, + FRMCTR2 = 0xB2, + FRMCTR3 = 0xB3, + INVCTR = 0xB4, + DISSET5 = 0xB6, + + PWCTR1 = 0xC0, + PWCTR2 = 0xC1, + PWCTR3 = 0xC2, + PWCTR4 = 0xC3, + PWCTR5 = 0xC4, + VMCTR1 = 0xC5, + + RDID1 = 0xDA, + RDID2 = 0xDB, + RDID3 = 0xDC, + RDID4 = 0xDD, + + GMCTRP1 = 0xE0, + GMCTRN1 = 0xE1, + + PWMTR6 = 0xFC + }; + + void ST7735::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); + + command(reg::SLPOUT); + + sleep_ms(500); + + command(reg::FRMCTR1, 3, "\x01\x2c\x2d"); // Rate = fosc/(1x2+40) * (LINE+2C+2D) + command(reg::FRMCTR2, 3, "\x01\x2c\x2d"); // Rate = fosc/(1x2+40) * (LINE+2C+2D) + command(reg::FRMCTR3, 6, "\x01\x2c\x2d\x01\x2c\x2d"); // Rate = fosc/(1x2+40) * (LINE+2C+2D) + + command(reg::INVCTR, 1, "\x07"); + + command(reg::PWCTR1, 3, "\xa2\x02\x84"); + command(reg::PWCTR2, 2, "\x0a\x00"); + command(reg::PWCTR4, 2, "\x8a\x2a"); + command(reg::PWCTR5, 2, "\x8a\xee"); + + command(reg::VMCTR1, 1, "\x0e"); + + // if invert + // command(reg::INVON) + // else + command(reg::INVON); + + command(reg::MADCTL, 1, "\x68"); // 0b0110 1000 (0x68) + command(reg::COLMOD, 1, "\x05"); + + offset_cols = (ROWS - width) / 2; + offset_rows = (COLS - height) / 2; + + char buf[4]; + buf[0] = 0; + buf[1] = offset_cols; + buf[2] = 0; + buf[3] = width + offset_cols - 1; + command(reg::CASET, 4, buf); + + buf[1] = offset_rows; + buf[3] = height + offset_rows - 1; + command(reg::RASET, 4, buf); + + command(reg::GMCTRP1, 16, "\x02\x1c\x07\x12\x37\x32\x29\x2d\x29\x25\x2b\x39\x00\x01\x03\x10"); + command(reg::GMCTRN1, 16, "\x03\x1d\x07\x06\x2e\x2c\x29\x2d\x2e\x2e\x37\x3f\x00\x00\x02\x10"); + + command(reg::NORON); + sleep_ms(100); + + command(reg::DISPON); + sleep_ms(100); + } + } + + spi_inst_t* ST7735::get_spi() const { + return spi; + } + + int ST7735::get_cs() const { + return cs; + } + + int ST7735::get_dc() const { + return dc; + } + + int ST7735::get_sck() const { + return sck; + } + + int ST7735::get_mosi() const { + return mosi; + } + + int ST7735::get_bl() const { + return bl; + } + + void ST7735::command(uint8_t command, size_t len, const char *data) { + 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 ST7735::update(bool dont_block) { + ST7735::command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer); + } + + void ST7735::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); + } +} \ No newline at end of file diff --git a/drivers/st7735/st7735.hpp b/drivers/st7735/st7735.hpp new file mode 100644 index 00000000..a4e67228 --- /dev/null +++ b/drivers/st7735/st7735.hpp @@ -0,0 +1,107 @@ +#pragma once + +#include "hardware/spi.h" +#include "hardware/gpio.h" + +namespace pimoroni { + + class ST7735 { + //-------------------------------------------------- + // Constants + //-------------------------------------------------- + private: + static const uint8_t ROWS = 162; + static const uint8_t COLS = 132; + + + //-------------------------------------------------- + // Enums + //-------------------------------------------------- + public: + enum BG_SPI_SLOT { + BG_SPI_FRONT, + BG_SPI_BACK + }; + + + //-------------------------------------------------- + // Variables + //-------------------------------------------------- + private: + // screen properties + uint16_t width; + uint16_t height; + uint16_t row_stride; + + public: + // frame buffer where pixel data is stored + uint16_t *frame_buffer; + + private: + spi_inst_t *spi = spi0; + + uint32_t dma_channel; + + // 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 = 30 * 1024 * 1024; + + uint8_t offset_cols = 0; + uint8_t offset_rows = 0; + + + //-------------------------------------------------- + // Constructors/Destructor + //-------------------------------------------------- + public: + ST7735(uint16_t width, uint16_t height, uint16_t *frame_buffer, BG_SPI_SLOT slot) : + width(width), height(height), frame_buffer(frame_buffer) { + switch(slot) { + case BG_SPI_FRONT: + cs = 17; + bl = 20; + break; + case BG_SPI_BACK: + cs = 22; + bl = 21; + break; + } + } + + ST7735(uint16_t width, uint16_t height, uint16_t *frame_buffer) : + width(width), height(height), frame_buffer(frame_buffer) {} + + ST7735(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, uint8_t bl = -1) : + width(width), height(height), frame_buffer(frame_buffer) , + spi(spi), + cs(cs), dc(dc), sck(sck), mosi(mosi), miso(miso), bl(bl) {} + + + //-------------------------------------------------- + // Methods + //-------------------------------------------------- + public: + void init(bool auto_init_sequence = true); + + spi_inst_t* get_spi() const; + int get_cs() const; + int get_dc() const; + int get_sck() const; + int get_mosi() const; + int get_bl() const; + + void command(uint8_t command, size_t len = 0, const char *data = NULL); + void update(bool dont_block = false); + void set_backlight(uint8_t brightness); + }; + +} diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index b31806ee..6804c506 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(breakout_dotmatrix) add_subdirectory(breakout_ltr559) +add_subdirectory(breakout_colourlcd160x80) add_subdirectory(breakout_roundlcd) add_subdirectory(breakout_rgbmatrix5x5) add_subdirectory(breakout_matrix11x7) diff --git a/examples/breakout_colourlcd160x80/CMakeLists.txt b/examples/breakout_colourlcd160x80/CMakeLists.txt new file mode 100644 index 00000000..c54ee549 --- /dev/null +++ b/examples/breakout_colourlcd160x80/CMakeLists.txt @@ -0,0 +1,12 @@ +set(OUTPUT_NAME colourlcd160x80_demo) + +add_executable( + ${OUTPUT_NAME} + demo.cpp +) + +# Pull in pico libraries that we need +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_colourlcd160x80) + +# create map/bin/hex file etc. +pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/breakout_colourlcd160x80/demo.cpp b/examples/breakout_colourlcd160x80/demo.cpp new file mode 100644 index 00000000..8d032f5a --- /dev/null +++ b/examples/breakout_colourlcd160x80/demo.cpp @@ -0,0 +1,42 @@ +#include "pico/stdlib.h" +#include "math.h" +#include "breakout_colourlcd160x80.hpp" + +using namespace pimoroni; + +uint16_t buffer[BreakoutColourLCD160x80::WIDTH * BreakoutColourLCD160x80::HEIGHT]; +BreakoutColourLCD160x80 lcd(buffer); + + int main() { + gpio_init(PICO_DEFAULT_LED_PIN); + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + + lcd.init(); + lcd.set_backlight(255); + + Pen my_pen = lcd.create_pen(255, 0, 0); + + + uint32_t t = 0; + + while(true) { + uint16_t x = (sinf(float(t) / 100.0f) * 30) + 30; + lcd.set_pen(0, 255, 0); + lcd.clear(); + lcd.set_pen(255, 255, 0); + lcd.rectangle(Rect(10, 10, 160-20, 80-20)); + + lcd.set_pen(0, 0, 255); + lcd.rectangle(Rect(10, 10, 30, 30)); + lcd.set_pen(255, 0, 0); + lcd.rectangle(Rect(x, x, 20, 20)); + lcd.update(); + gpio_put(PICO_DEFAULT_LED_PIN, true); + sleep_ms(8); + gpio_put(PICO_DEFAULT_LED_PIN, false); + sleep_ms(8); + t++; + } + + return 0; +} diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 6eda56b1..662a24e4 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(breakout_dotmatrix) add_subdirectory(breakout_ltr559) +add_subdirectory(breakout_colourlcd160x80) add_subdirectory(breakout_roundlcd) add_subdirectory(breakout_rgbmatrix5x5) add_subdirectory(breakout_matrix11x7) diff --git a/libraries/breakout_colourlcd160x80/CMakeLists.txt b/libraries/breakout_colourlcd160x80/CMakeLists.txt new file mode 100644 index 00000000..d855c97b --- /dev/null +++ b/libraries/breakout_colourlcd160x80/CMakeLists.txt @@ -0,0 +1 @@ +include(breakout_colourlcd160x80.cmake) diff --git a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cmake b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cmake new file mode 100644 index 00000000..ece9be90 --- /dev/null +++ b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cmake @@ -0,0 +1,11 @@ +set(LIB_NAME breakout_colourlcd160x80) +add_library(${LIB_NAME} INTERFACE) + +target_sources(${LIB_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp +) + +target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib st7735 pico_graphics hardware_spi) diff --git a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp new file mode 100644 index 00000000..f6469902 --- /dev/null +++ b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp @@ -0,0 +1,58 @@ +#include "breakout_colourlcd160x80.hpp" + +namespace pimoroni { + + BreakoutColourLCD160x80::BreakoutColourLCD160x80(uint16_t *buf) + : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf) { + __fb = buf; + } + + BreakoutColourLCD160x80::BreakoutColourLCD160x80(uint16_t *buf, spi_inst_t *spi, + uint8_t cs, uint8_t dc, uint8_t sck, uint8_t mosi, uint8_t miso, uint8_t bl) + : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf, spi, cs, dc, sck, mosi, miso, bl) { + __fb = buf; + } + + BreakoutColourLCD160x80::BreakoutColourLCD160x80(uint16_t *buf, ST7735::BG_SPI_SLOT slot) + : PicoGraphics(WIDTH, HEIGHT, buf), screen(WIDTH, HEIGHT, buf, slot) { + __fb = buf; + } + + void BreakoutColourLCD160x80::init() { + // initialise the screen + screen.init(); + } + + spi_inst_t* BreakoutColourLCD160x80::get_spi() const { + return screen.get_spi(); + } + + int BreakoutColourLCD160x80::get_cs() const { + return screen.get_cs(); + } + + int BreakoutColourLCD160x80::get_dc() const { + return screen.get_dc(); + } + + int BreakoutColourLCD160x80::get_sck() const { + return screen.get_sck(); + } + + int BreakoutColourLCD160x80::get_mosi() const { + return screen.get_mosi(); + } + + int BreakoutColourLCD160x80::get_bl() const { + return screen.get_bl(); + } + + void BreakoutColourLCD160x80::update() { + screen.update(); + } + + void BreakoutColourLCD160x80::set_backlight(uint8_t brightness) { + screen.set_backlight(brightness); + } + +} \ No newline at end of file diff --git a/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp new file mode 100644 index 00000000..97741431 --- /dev/null +++ b/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include "../../drivers/st7735/st7735.hpp" +#include "../../libraries/pico_graphics/pico_graphics.hpp" + +namespace pimoroni { + + class BreakoutColourLCD160x80 : public PicoGraphics { + //-------------------------------------------------- + // Constants + //-------------------------------------------------- + public: + static const int WIDTH = 160; + static const int HEIGHT = 80; + static const uint8_t PIN_UNUSED = UINT8_MAX; + + + //-------------------------------------------------- + // Variables + //-------------------------------------------------- + public: + uint16_t *__fb; + private: + ST7735 screen; + + + //-------------------------------------------------- + // Constructors/Destructor + //-------------------------------------------------- + public: + BreakoutColourLCD160x80(uint16_t *buf); + BreakoutColourLCD160x80(uint16_t *buf, spi_inst_t *spi, + uint8_t cs, uint8_t dc, uint8_t sck, uint8_t mosi, uint8_t miso = PIN_UNUSED, uint8_t bl = PIN_UNUSED); + BreakoutColourLCD160x80(uint16_t *buf, ST7735::BG_SPI_SLOT slot); + + + //-------------------------------------------------- + // Methods + //-------------------------------------------------- + public: + void init(); + + spi_inst_t* get_spi() const; + int get_cs() const; + int get_dc() const; + int get_sck() const; + int get_mosi() const; + int get_bl() const; + + void update(); + void set_backlight(uint8_t brightness); + }; + +} diff --git a/micropython/examples/breakout_colourlcd160x80/demo.py b/micropython/examples/breakout_colourlcd160x80/demo.py new file mode 100644 index 00000000..ed9b66fa --- /dev/null +++ b/micropython/examples/breakout_colourlcd160x80/demo.py @@ -0,0 +1,62 @@ +import time +import random +from breakout_colourlcd160x80 import BreakoutColourLCD160x80 + +width = BreakoutColourLCD160x80.WIDTH +height = BreakoutColourLCD160x80.HEIGHT + +display_buffer = bytearray(width * height * 2) # 2-bytes per pixel (RGB565) +display = BreakoutColourLCD160x80(display_buffer) + +display.set_backlight(1.0) + + +class Ball: + def __init__(self, x, y, r, dx, dy, pen): + self.x = x + self.y = y + self.r = r + self.dx = dx + self.dy = dy + self.pen = pen + + +# initialise shapes +balls = [] +for i in range(0, 100): + r = random.randint(0, 10) + 3 + balls.append( + Ball( + random.randint(r, r + (width - 2 * r)), + random.randint(r, r + (height - 2 * r)), + r, + (14 - r) / 2, + (14 - r) / 2, + display.create_pen(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)), + ) + ) + +while True: + display.set_pen(40, 40, 40) + display.clear() + + for ball in balls: + ball.x += ball.dx + ball.y += ball.dy + + xmax = width - ball.r + xmin = ball.r + ymax = height - ball.r + ymin = ball.r + + if ball.x < xmin or ball.x > xmax: + ball.dx *= -1 + + if ball.y < ymin or ball.y > ymax: + ball.dy *= -1 + + display.set_pen(ball.pen) + display.circle(int(ball.x), int(ball.y), int(ball.r)) + + display.update() + time.sleep(0.01) diff --git a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.c b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.c new file mode 100644 index 00000000..aab86b02 --- /dev/null +++ b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.c @@ -0,0 +1,78 @@ +#include "breakout_colourlcd160x80.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// BreakoutColourLCD160x80 Class +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Methods *****/ +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutColourLCD160x80_update_obj, BreakoutColourLCD160x80_update); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_set_backlight_obj, 1, BreakoutColourLCD160x80_set_backlight); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_set_pen_obj, 1, BreakoutColourLCD160x80_set_pen); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_create_pen_obj, 1, BreakoutColourLCD160x80_create_pen); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_set_clip_obj, 1, BreakoutColourLCD160x80_set_clip); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutColourLCD160x80_remove_clip_obj, BreakoutColourLCD160x80_remove_clip); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutColourLCD160x80_clear_obj, BreakoutColourLCD160x80_clear); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_pixel_obj, 1, BreakoutColourLCD160x80_pixel); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_pixel_span_obj, 1, BreakoutColourLCD160x80_pixel_span); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_rectangle_obj, 1, BreakoutColourLCD160x80_rectangle); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_circle_obj, 1, BreakoutColourLCD160x80_circle); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_character_obj, 1, BreakoutColourLCD160x80_character); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_text_obj, 1, BreakoutColourLCD160x80_text); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_polygon_obj, 1, BreakoutColourLCD160x80_polygon); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_triangle_obj, 1, BreakoutColourLCD160x80_triangle); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutColourLCD160x80_line_obj, 1, BreakoutColourLCD160x80_line); + +/***** Binding of Methods *****/ +STATIC const mp_rom_map_elem_t BreakoutColourLCD160x80_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&BreakoutColourLCD160x80_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&BreakoutColourLCD160x80_set_backlight_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&BreakoutColourLCD160x80_set_pen_obj) }, + { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&BreakoutColourLCD160x80_create_pen_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&BreakoutColourLCD160x80_set_clip_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove_clip), MP_ROM_PTR(&BreakoutColourLCD160x80_remove_clip_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&BreakoutColourLCD160x80_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&BreakoutColourLCD160x80_pixel_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixel_span), MP_ROM_PTR(&BreakoutColourLCD160x80_pixel_span_obj) }, + { MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&BreakoutColourLCD160x80_rectangle_obj) }, + { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&BreakoutColourLCD160x80_circle_obj) }, + { MP_ROM_QSTR(MP_QSTR_character), MP_ROM_PTR(&BreakoutColourLCD160x80_character_obj) }, + { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&BreakoutColourLCD160x80_text_obj) }, + { MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&BreakoutColourLCD160x80_polygon_obj) }, + { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&BreakoutColourLCD160x80_triangle_obj) }, + { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&BreakoutColourLCD160x80_line_obj) }, + { MP_ROM_QSTR(MP_QSTR_WIDTH), MP_ROM_INT(WIDTH) }, + { MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(HEIGHT) }, +}; +STATIC MP_DEFINE_CONST_DICT(BreakoutColourLCD160x80_locals_dict, BreakoutColourLCD160x80_locals_dict_table); + +/***** Class Definition *****/ +const mp_obj_type_t breakout_colourlcd160x80_BreakoutColourLCD160x80_type = { + { &mp_type_type }, + .name = MP_QSTR_breakout_colourlcd160x80, + .print = BreakoutColourLCD160x80_print, + .make_new = BreakoutColourLCD160x80_make_new, + .locals_dict = (mp_obj_dict_t*)&BreakoutColourLCD160x80_locals_dict, +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// breakout_colourlcd160x80 Module +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Globals Table *****/ +STATIC const mp_map_elem_t breakout_colourlcd160x80_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_breakout_colourlcd160x80) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_BreakoutColourLCD160x80), (mp_obj_t)&breakout_colourlcd160x80_BreakoutColourLCD160x80_type }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_breakout_colourlcd160x80_globals, breakout_colourlcd160x80_globals_table); + +/***** Module Definition *****/ +const mp_obj_module_t breakout_colourlcd160x80_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_breakout_colourlcd160x80_globals, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +MP_REGISTER_MODULE(MP_QSTR_breakout_colourlcd160x80, breakout_colourlcd160x80_user_cmodule, MODULE_BREAKOUT_COLOURLCD160X80_ENABLED); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp new file mode 100644 index 00000000..2aa9055a --- /dev/null +++ b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.cpp @@ -0,0 +1,545 @@ +#include "../../../pimoroni-pico/libraries/breakout_colourlcd160x80/breakout_colourlcd160x80.hpp" + +#define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o)) + +#define IS_VALID_PERIPH(spi, pin) ((((pin) & 8) >> 3) == (spi)) +#define IS_VALID_SCK(spi, pin) (((pin) & 3) == 2 && IS_VALID_PERIPH(spi, pin)) +#define IS_VALID_MOSI(spi, pin) (((pin) & 3) == 3 && IS_VALID_PERIPH(spi, pin)) +#define IS_VALID_MISO(spi, pin) (((pin) & 3) == 0 && IS_VALID_PERIPH(spi, pin)) + + +using namespace pimoroni; + +extern "C" { +#include "breakout_colourlcd160x80.h" + +/***** Variables Struct *****/ +typedef struct _breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t { + mp_obj_base_t base; + BreakoutColourLCD160x80 *breakout; +} breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t; + +/***** Print *****/ +void BreakoutColourLCD160x80_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; //Unused input parameter + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + BreakoutColourLCD160x80* breakout = self->breakout; + mp_print_str(print, "BreakoutColourLCD160x80("); + + mp_print_str(print, "spi = "); + mp_obj_print_helper(print, mp_obj_new_int((breakout->get_spi() == spi0) ? 0 : 1), PRINT_REPR); + + mp_print_str(print, ", cs = "); + mp_obj_print_helper(print, mp_obj_new_int(breakout->get_cs()), PRINT_REPR); + + mp_print_str(print, ", dc = "); + mp_obj_print_helper(print, mp_obj_new_int(breakout->get_dc()), PRINT_REPR); + + mp_print_str(print, ", sck = "); + mp_obj_print_helper(print, mp_obj_new_int(breakout->get_sck()), PRINT_REPR); + + mp_print_str(print, ", mosi = "); + mp_obj_print_helper(print, mp_obj_new_int(breakout->get_mosi()), PRINT_REPR); + + mp_print_str(print, ", bl = "); + mp_obj_print_helper(print, mp_obj_new_int(breakout->get_bl()), PRINT_REPR); + + mp_print_str(print, ")"); +} + +/***** Constructor *****/ +mp_obj_t BreakoutColourLCD160x80_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = nullptr; + + if(n_args <= 1) { + enum { ARG_buffer }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + // Parse args. + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + self = m_new_obj(breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + self->base.type = &breakout_colourlcd160x80_BreakoutColourLCD160x80_type; + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); + + self->breakout = new BreakoutColourLCD160x80((uint16_t *)bufinfo.buf); + } + else if(n_args == 2) { + enum { ARG_buffer, ARG_slot }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_slot, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + // Parse args. + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int slot = args[ARG_slot].u_int; + if(slot == ST7735::BG_SPI_FRONT || slot == ST7735::BG_SPI_BACK) { + self = m_new_obj(breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + self->base.type = &breakout_colourlcd160x80_BreakoutColourLCD160x80_type; + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); + + self->breakout = new BreakoutColourLCD160x80((uint16_t *)bufinfo.buf, (ST7735::BG_SPI_SLOT)slot); + } + else { + mp_raise_ValueError("slot not a valid value. Expected 0 to 1"); + } + } + else { + enum { ARG_buffer, ARG_spi, ARG_cs, ARG_dc, ARG_sck, ARG_mosi, ARG_bl }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_spi, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_cs, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_dc, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_sck, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_mosi, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_bl, MP_ARG_INT, {.u_int = BreakoutColourLCD160x80::PIN_UNUSED} }, + }; + + // Parse args. + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); + + // Get SPI bus. + int spi_id = args[ARG_spi].u_int; + if(spi_id < 0 || spi_id > 1) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), spi_id); + } + + int sck = args[ARG_sck].u_int; + if(!IS_VALID_SCK(spi_id, sck)) { + mp_raise_ValueError(MP_ERROR_TEXT("bad SCK pin")); + } + + int mosi = args[ARG_mosi].u_int; + if(!IS_VALID_SCK(spi_id, mosi)) { + mp_raise_ValueError(MP_ERROR_TEXT("bad MOSI pin")); + } + + self = m_new_obj(breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + self->base.type = &breakout_colourlcd160x80_BreakoutColourLCD160x80_type; + + spi_inst_t *spi = (spi_id == 0) ? spi0 : spi1; + self->breakout = new BreakoutColourLCD160x80((uint16_t *)bufinfo.buf, spi, + args[ARG_cs].u_int, args[ARG_dc].u_int, sck, mosi, BreakoutColourLCD160x80::PIN_UNUSED, args[ARG_bl].u_int); + } + + self->breakout->init(); + + return MP_OBJ_FROM_PTR(self); +} + +/***** Methods *****/ +mp_obj_t BreakoutColourLCD160x80_update(mp_obj_t self_in) { + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + self->breakout->update(); + + return mp_const_none; +} + +mp_obj_t BreakoutColourLCD160x80_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_brightness }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_brightness, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + + float brightness = mp_obj_get_float(args[ARG_brightness].u_obj); + + if(brightness < 0 || brightness > 1.0f) + mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0"); + else + self->breakout->set_backlight((uint8_t)(brightness * 255.0f)); + + return mp_const_none; +} + +mp_obj_t BreakoutColourLCD160x80_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + if(n_args <= 2) { + enum { ARG_self, ARG_pen }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_pen, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + + int pen = args[ARG_pen].u_int; + + if(pen < 0 || pen > 0xffff) + mp_raise_ValueError("p is not a valid pen."); + else + self->breakout->set_pen(pen); + } + else { + enum { ARG_self, ARG_r, ARG_g, ARG_b }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + + int r = args[ARG_r].u_int; + int g = args[ARG_g].u_int; + int b = args[ARG_b].u_int; + + if(r < 0 || r > 255) + mp_raise_ValueError("r out of range. Expected 0 to 255"); + else if(g < 0 || g > 255) + mp_raise_ValueError("g out of range. Expected 0 to 255"); + else if(b < 0 || b > 255) + mp_raise_ValueError("b out of range. Expected 0 to 255"); + else + self->breakout->set_pen(r, g, b); + } + + return mp_const_none; +} + +mp_obj_t BreakoutColourLCD160x80_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + int pen = 0; + + enum { ARG_self, ARG_r, ARG_g, ARG_b }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + + int r = args[ARG_r].u_int; + int g = args[ARG_g].u_int; + int b = args[ARG_b].u_int; + + if(r < 0 || r > 255) + mp_raise_ValueError("r out of range. Expected 0 to 255"); + else if(g < 0 || g > 255) + mp_raise_ValueError("g out of range. Expected 0 to 255"); + else if(b < 0 || b > 255) + mp_raise_ValueError("b out of range. Expected 0 to 255"); + else + pen = self->breakout->create_pen(r, g, b); + + return mp_obj_new_int(pen); +} + +mp_obj_t BreakoutColourLCD160x80_set_clip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_w, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_h, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + + int x = args[ARG_x].u_int; + int y = args[ARG_y].u_int; + int w = args[ARG_w].u_int; + int h = args[ARG_h].u_int; + + Rect r(x, y, w, h); + self->breakout->set_clip(r); + + return mp_const_none; +} + +mp_obj_t BreakoutColourLCD160x80_remove_clip(mp_obj_t self_in) { + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + self->breakout->remove_clip(); + + return mp_const_none; +} + +mp_obj_t BreakoutColourLCD160x80_clear(mp_obj_t self_in) { + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + self->breakout->clear(); + + return mp_const_none; +} + +mp_obj_t BreakoutColourLCD160x80_pixel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_x, ARG_y }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + + int x = args[ARG_x].u_int; + int y = args[ARG_y].u_int; + + Point p(x, y); + self->breakout->pixel(p); + + return mp_const_none; +} + +mp_obj_t BreakoutColourLCD160x80_pixel_span(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_x, ARG_y, ARG_l }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_l, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + + int x = args[ARG_x].u_int; + int y = args[ARG_y].u_int; + int l = args[ARG_l].u_int; + + Point p(x, y); + self->breakout->pixel_span(p, l); + + return mp_const_none; +} + +mp_obj_t BreakoutColourLCD160x80_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_w, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_h, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + + int x = args[ARG_x].u_int; + int y = args[ARG_y].u_int; + int w = args[ARG_w].u_int; + int h = args[ARG_h].u_int; + + Rect r(x, y, w, h); + self->breakout->rectangle(r); + + return mp_const_none; +} + +mp_obj_t BreakoutColourLCD160x80_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_x, ARG_y, ARG_r }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + + int x = args[ARG_x].u_int; + int y = args[ARG_y].u_int; + int r = args[ARG_r].u_int; + + Point p(x, y); + self->breakout->circle(p, r); + + return mp_const_none; +} + +mp_obj_t BreakoutColourLCD160x80_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_char, ARG_x, ARG_y, ARG_scale }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_char, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + + int c = mp_obj_get_int(args[ARG_char].u_obj); + int x = args[ARG_y].u_int; + int y = args[ARG_y].u_int; + + Point p(x, y); + if(n_args == 4) { + int scale = args[ARG_scale].u_int; + self->breakout->character((char)c, p, scale); + } + else + self->breakout->character((char)c, p); + + return mp_const_none; +} + +mp_obj_t BreakoutColourLCD160x80_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_text, ARG_x, ARG_y, ARG_wrap, ARG_scale }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_wr, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + + mp_check_self(mp_obj_is_str_or_bytes(args[ARG_text].u_obj)); + GET_STR_DATA_LEN(args[ARG_text].u_obj, str, str_len); + + std::string t((const char*)str); + + int x = args[ARG_x].u_int; + int y = args[ARG_y].u_int; + int wrap = args[ARG_wrap].u_int; + + Point p(x, y); + if(n_args == 5) { + int scale = args[ARG_scale].u_int; + self->breakout->text(t, p, wrap, scale); + } + else + self->breakout->text(t, p, wrap); + + return mp_const_none; +} + +mp_obj_t BreakoutColourLCD160x80_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // enum { ARG_self, ARG_x, ARG_y, ARG_r }; + // static const mp_arg_t allowed_args[] = { + // { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + // { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT }, + // { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT }, + // { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, + // }; + + // mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + // mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + + // int x = args[ARG_x].u_int; + // int y = args[ARG_y].u_int; + // int r = args[ARG_r].u_int; + + // Point p(x, y); + // self->breakout->circle(p, r); + + mp_raise_NotImplementedError("polygon is not implemented. Please avoid using this function for now"); + + return mp_const_none; +} + +mp_obj_t BreakoutColourLCD160x80_triangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_x3, ARG_y3 }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_x3, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y3, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + + int x1 = args[ARG_x1].u_int; + int y1 = args[ARG_y1].u_int; + int x2 = args[ARG_x1].u_int; + int y2 = args[ARG_y1].u_int; + int x3 = args[ARG_x1].u_int; + int y3 = args[ARG_y1].u_int; + + Point p1(x1, y1); + Point p2(x2, y2); + Point p3(x3, y3); + self->breakout->triangle(p1, p2, p3); + + return mp_const_none; +} + +mp_obj_t BreakoutColourLCD160x80_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_x1, ARG_y1, ARG_x2, ARG_y2 }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_colourlcd160x80_BreakoutColourLCD160x80_obj_t); + + int x1 = args[ARG_x1].u_int; + int y1 = args[ARG_y1].u_int; + int x2 = args[ARG_x1].u_int; + int y2 = args[ARG_y1].u_int; + + Point p1(x1, y1); + Point p2(x2, y2); + self->breakout->line(p1, p2); + + return mp_const_none; +} +} \ No newline at end of file diff --git a/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.h b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.h new file mode 100644 index 00000000..166c06a4 --- /dev/null +++ b/micropython/modules/breakout_colourlcd160x80/breakout_colourlcd160x80.h @@ -0,0 +1,32 @@ +// Include MicroPython API. +#include "py/runtime.h" +#include "py/objstr.h" + +/***** Constants *****/ +static const int WIDTH = 160; +static const int HEIGHT = 80; + + +/***** Extern of Class Definition *****/ +extern const mp_obj_type_t breakout_colourlcd160x80_BreakoutColourLCD160x80_type; + +/***** Extern of Class Methods *****/ +extern void BreakoutColourLCD160x80_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); +extern mp_obj_t BreakoutColourLCD160x80_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args); +extern mp_obj_t BreakoutColourLCD160x80_update(mp_obj_t self_in); +extern mp_obj_t BreakoutColourLCD160x80_set_backlight(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +extern mp_obj_t BreakoutColourLCD160x80_set_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutColourLCD160x80_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutColourLCD160x80_set_clip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutColourLCD160x80_remove_clip(mp_obj_t self_in); +extern mp_obj_t BreakoutColourLCD160x80_clear(mp_obj_t self_in); +extern mp_obj_t BreakoutColourLCD160x80_pixel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutColourLCD160x80_pixel_span(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutColourLCD160x80_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutColourLCD160x80_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutColourLCD160x80_character(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutColourLCD160x80_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutColourLCD160x80_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutColourLCD160x80_triangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutColourLCD160x80_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); \ No newline at end of file diff --git a/micropython/modules/breakout_colourlcd160x80/micropython.cmake b/micropython/modules/breakout_colourlcd160x80/micropython.cmake new file mode 100644 index 00000000..c38170ef --- /dev/null +++ b/micropython/modules/breakout_colourlcd160x80/micropython.cmake @@ -0,0 +1,20 @@ +set(MOD_NAME breakout_colourlcd160x80) +string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER) +add_library(usermod_${MOD_NAME} INTERFACE) + +target_sources(usermod_${MOD_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c + ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/${MOD_NAME}/${MOD_NAME}.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/st7735/st7735.cpp +) + +target_include_directories(usermod_${MOD_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +target_compile_definitions(usermod_${MOD_NAME} INTERFACE + -DMODULE_${MOD_NAME_UPPER}_ENABLED=1 +) + +target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}) \ No newline at end of file diff --git a/micropython/modules/breakout_colourlcd160x80/micropython.mk b/micropython/modules/breakout_colourlcd160x80/micropython.mk new file mode 100755 index 00000000..6e301518 --- /dev/null +++ b/micropython/modules/breakout_colourlcd160x80/micropython.mk @@ -0,0 +1,13 @@ +set(MOD_NAME breakout_colourlcd160x80) +BREAKOUT_MOD_DIR := $(USERMOD_DIR) + +# Add our source files to the respective variables. +SRC_USERMOD += $(BREAKOUT_MOD_DIR)/${MOD_NAME}.c +SRC_USERMOD_CXX += $(BREAKOUT_MOD_DIR)/${MOD_NAME}.cpp + +# Add our module directory to the include path. +CFLAGS_USERMOD += -I$(BREAKOUT_MOD_DIR) +CXXFLAGS_USERMOD += -I$(BREAKOUT_MOD_DIR) + +# We use C++ features so have to link against the standard library. +LDFLAGS_USERMOD += -lstdc++ \ No newline at end of file diff --git a/micropython/modules/micropython.cmake b/micropython/modules/micropython.cmake index c60387ba..eefe398c 100644 --- a/micropython/modules/micropython.cmake +++ b/micropython/modules/micropython.cmake @@ -1,5 +1,6 @@ include(${CMAKE_CURRENT_LIST_DIR}/breakout_dotmatrix/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_ltr559/micropython.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/breakout_colourlcd160x80/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_roundlcd/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_rgbmatrix5x5/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_matrix11x7/micropython.cmake)