From 6a852ec2bde727a466eb131cebe81252aac103c5 Mon Sep 17 00:00:00 2001 From: noisehoho Date: Wed, 10 Dec 2025 03:21:21 +0800 Subject: [PATCH 1/9] Add ST7735 RGB TFT display support with colorful themes Features: - ST7735 driver with RGB565 color support (65K colors) - Colorful UI themes for each display mode (Cyberpunk, Matrix, Sunset, Neon) - Daisy Patch compatible pinout - New target: seed_st7735 for 128x160 TFT displays - GetDriver() method for accessing color functions New files: - source/st7735.h - ST7735 TFT driver - source/seed.st7735.json - Oopsy target configuration - source/ST7735_README.md - Documentation Modified files: - source/oopsy.js - ST7735 header detection and target path - source/genlib_daisy.h - Color theme switching per display mode --- source/ST7735_README.md | 168 ++++++++++++++++ source/genlib_daisy.h | 16 +- source/oopsy.js | 9 +- source/seed.st7735.json | 69 +++++++ source/st7735.h | 429 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 685 insertions(+), 6 deletions(-) create mode 100644 source/ST7735_README.md create mode 100644 source/seed.st7735.json create mode 100644 source/st7735.h diff --git a/source/ST7735_README.md b/source/ST7735_README.md new file mode 100644 index 0000000..15b17fc --- /dev/null +++ b/source/ST7735_README.md @@ -0,0 +1,168 @@ +# ST7735 TFT Display Support for Oopsy + +This adds support for **ST7735 RGB TFT displays** (128x160, 65K colors) to Oopsy, as a drop-in replacement for the standard SSD130x OLED displays. + +## Features + +- 🌈 **Full RGB565 Color Support** - 65,536 colors +- 🎨 **Colorful UI Themes** - Different color schemes for each display mode +- 🔌 **Daisy Patch Compatible Pinout** - Works with standard Daisy Patch wiring +- 📦 **Drop-in Replacement** - Same API as SSD130x, just change the target + +## Color Themes by Mode + +| Mode | Foreground | Background | Style | +|------|------------|------------|-------| +| **MENU** | Cyan | Dark Blue | Cyberpunk | +| **PARAMS** | Green | Black | Matrix | +| **SCOPE** | Orange | Purple | Sunset | +| **CONSOLE** | Magenta | Black | Neon | + +## Hardware Wiring + +### ST7735 Display Pinout (Daisy Seed) + +| ST7735 Pin | Daisy Seed Pin | Function | +|------------|----------------|----------| +| VCC | 3V3 | Power (3.3V) | +| GND | GND | Ground | +| SCL/SCK | D8 (PG11) | SPI Clock | +| SDA/MOSI | D10 (PB5) | SPI Data | +| DC | D9 (PB4) | Data/Command | +| CS | D7 (PA2) | Chip Select | +| RST/RES | D30 (PB15) | Reset | +| BLK | 3V3 or PWM | Backlight | + +### Encoder Pinout (Daisy Patch Compatible) + +| Encoder Pin | Daisy Seed Pin | +|-------------|----------------| +| A | D12 | +| B | D11 | +| Click/SW | D0 | + +### Knob Pinout + +| Knob | Daisy Seed Pin | +|------|----------------| +| Knob 1 | D15 | +| Knob 2 | D16 | +| Knob 3 | D21 | +| Knob 4 | D18 | + +## Usage with Oopsy + +### 1. Select the ST7735 Target + +In `oopsy.maxpat`, select **seed_st7735** from the Target dropdown menu. + +### 2. Create Your gen~ Patch + +Use standard gen~ with `Param` objects: + +``` +// Example gen~ code +Param gain(0.5, min=0, max=1); +Param frequency(440, min=20, max=2000); + +in 1 left; +out 1 output; + +output = left * gain; +``` + +### 3. Flash to Daisy + +Click the **Flash** button in Oopsy. The display will show your parameters with colorful themes! + +## Display Controls + +- **Long Press Encoder** (>0.5s) - Open mode selection menu +- **Rotate Encoder** - Navigate / Select +- **Short Press Encoder** - Confirm selection + +## Available Colors + +The driver provides these predefined colors: + +```cpp +COLOR_BLACK, COLOR_WHITE, COLOR_RED, COLOR_GREEN, COLOR_BLUE, +COLOR_CYAN, COLOR_MAGENTA, COLOR_YELLOW, COLOR_ORANGE, COLOR_GRAY, +COLOR_PINK, COLOR_PURPLE, COLOR_LIME, COLOR_NAVY, COLOR_TEAL, +COLOR_BROWN, COLOR_DARKGREEN, COLOR_DARKBLUE, COLOR_SKYBLUE, COLOR_GOLD +``` + +### Custom Colors + +Use `RGB565(r, g, b)` to create custom colors: + +```cpp +uint16_t myColor = Driver::RGB565(255, 128, 0); // Orange +``` + +## Files Modified/Added + +### New Files +- `source/libdaisy/src/dev/st7735.h` - ST7735 driver +- `source/seed.st7735.json` - Oopsy target configuration + +### Modified Files +- `source/oopsy.js` - Added ST7735 header detection and target path +- `source/genlib_daisy.h` - Added color theme switching +- `source/libdaisy/src/hid/disp/oled_display.h` - Added `GetDriver()` method +- `patchers/oopsy.maxpat` - Added seed_st7735 to target menu + +## Customizing Themes + +Edit `genlib_daisy.h` to change color themes: + +```cpp +#ifdef OOPSY_TARGET_ST7735 +{ + using Driver = daisy::ST7735_4WireSpi128x160Driver; + switch(mode) { + case MODE_MENU: + hardware.display.GetDriver().SetTheme( + Driver::COLOR_CYAN, // Foreground + Driver::COLOR_DARKBLUE, // Background + Driver::COLOR_MAGENTA // Accent + ); + break; + // ... other modes + } +} +#endif +``` + +## Display Specifications + +| Property | Value | +|----------|-------| +| Resolution | 128 x 160 pixels | +| Color Depth | 16-bit RGB565 (65K colors) | +| Interface | SPI (4-wire) | +| Controller | ST7735S | +| Refresh Rate | ~30 FPS | + +## Troubleshooting + +### Display is blank +- Check wiring connections +- Verify RST pin is connected to D30 +- Check backlight connection (BLK to 3V3) + +### Wrong colors +- Ensure ST7735S variant (not ST7735R) +- Check MADCTL setting in driver if colors are inverted + +### Encoder not working +- Verify encoder pins: A=D12, B=D11, Click=D0 +- Check if D0 conflicts with other hardware + +## Author + +Created by **noisehoho** for the Daisy/Oopsy community. + +## License + +MIT License - Same as Oopsy diff --git a/source/genlib_daisy.h b/source/genlib_daisy.h index 527c7f7..c8f3802 100644 --- a/source/genlib_daisy.h +++ b/source/genlib_daisy.h @@ -562,7 +562,21 @@ namespace oopsy { } #endif - // CLEAR DISPLAY + // ST7735 COLOR THEMES - Set different colors for each mode + #ifdef OOPSY_TARGET_ST7735 + { + using Driver = daisy::ST7735_4WireSpi128x160Driver; + switch(mode) { + case MODE_MENU: hardware.display.GetDriver().SetTheme(Driver::COLOR_CYAN, Driver::COLOR_DARKBLUE, Driver::COLOR_MAGENTA); break; + case MODE_PARAMS: hardware.display.GetDriver().SetTheme(Driver::COLOR_GREEN, Driver::COLOR_BLACK, Driver::COLOR_LIME); break; + case MODE_SCOPE: hardware.display.GetDriver().SetTheme(Driver::COLOR_ORANGE, Driver::COLOR_PURPLE, Driver::COLOR_YELLOW); break; + case MODE_CONSOLE: hardware.display.GetDriver().SetTheme(Driver::COLOR_MAGENTA, Driver::COLOR_BLACK, Driver::COLOR_CYAN); break; + default: hardware.display.GetDriver().SetTheme(Driver::COLOR_WHITE, Driver::COLOR_BLACK, Driver::COLOR_CYAN); break; + } + } + #endif + + // CLEAR DISPLAY #ifdef OOPSY_TARGET_HAS_OLED hardware.display.Fill(false); #endif diff --git a/source/oopsy.js b/source/oopsy.js index cead987..866bf8c 100755 --- a/source/oopsy.js +++ b/source/oopsy.js @@ -324,13 +324,11 @@ function generate_target_struct(target) { target.defines.OOPSY_OLED_DISPLAY_HEIGHT = target.display.dim[1] } - return ` + return ` #include "daisy_seed.h" -${target.display ? `#include "dev/oled_ssd130x.h"` : ""} +${target.display ? (target.display.driver.includes("ST7735") ? `#include "dev/st7735.h"` : `#include "dev/oled_ssd130x.h"`) : ""} // name: ${target.name} -struct Daisy { - - void Init(bool boost = false) { +struct Daisy { void Init(bool boost = false) { seed.Configure(); seed.Init(boost); ${components.filter((e) => e.init) @@ -469,6 +467,7 @@ function run() { case "versio": target = arg; break; case "bluemchen": target_path = path.join(__dirname, "seed.bluemchen.json"); break; case "nehcmeulb": target_path = path.join(__dirname, "seed.nehcmeulb.json"); break; + case "seed_st7735": target_path = path.join(__dirname, "seed.st7735.json"); break; case "watch": watch=true; break; diff --git a/source/seed.st7735.json b/source/seed.st7735.json new file mode 100644 index 0000000..a05f8b5 --- /dev/null +++ b/source/seed.st7735.json @@ -0,0 +1,69 @@ +{ + "name": "seed_st7735", + "max_apps": 8, + "defines": { + "OOPSY_TARGET_HAS_OLED": 1, + "OOPSY_TARGET_ST7735": 1, + "OOPSY_OLED_DISPLAY_WIDTH": 128, + "OOPSY_OLED_DISPLAY_HEIGHT": 160 + }, + "display": { + "driver": "daisy::ST7735_4WireSpi128x160Driver", + "dim": [128, 160], + "config": [] + }, + "inserts": [], + "components": { + "knob1": { + "component": "AnalogControl", + "pin": 15 + }, + "knob2": { + "component": "AnalogControl", + "pin": 16 + }, + "knob3": { + "component": "AnalogControl", + "pin": 21 + }, + "knob4": { + "component": "AnalogControl", + "pin": 18 + }, + "encoder": { + "component": "Encoder", + "pin": {"a": 12, "b": 11, "click": 0}, + "meta": [ + "menu_hold = ${name}.TimeHeldMs();", + "menu_click = ${name}.FallingEdge();", + "menu_rotate = ${name}.Increment();" + ] + }, + "gate1": { + "component": "GateIn", + "pin": 20 + }, + "gate2": { + "component": "GateIn", + "pin": 19 + } + }, + "labels": { + "params": { + "knob1": "knob1", + "knob2": "knob2", + "knob3": "knob3", + "knob4": "knob4", + "cv1": "knob1", + "cv2": "knob2", + "cv3": "knob3", + "cv4": "knob4", + "gate1": "gate1", + "gate2": "gate2", + "gate": "gate1" + }, + "outs": {}, + "datas": {} + }, + "aliases": {} +} diff --git a/source/st7735.h b/source/st7735.h new file mode 100644 index 0000000..3c5942b --- /dev/null +++ b/source/st7735.h @@ -0,0 +1,429 @@ +/** + * @file st7735.h + * @brief ST7735 TFT LCD Driver for Daisy + * + * Compatible with OledDisplay template, drop-in replacement for SSD130x + * Supports RGB565 color (65K colors) + * + * Default Wiring (Daisy Seed / Daisy Patch compatible): + * SCL -> D8 (SPI1_SCK / PG11) + * SDA -> D10 (SPI1_MOSI / PB5) + * DC -> D9 (PB4) + * CS -> D7 (PA2) - Software CS + * RES -> D30 (PB15) + */ + +#pragma once +#ifndef DSY_ST7735_H +#define DSY_ST7735_H + +#include "daisy_seed.h" + +namespace daisy +{ + +/** + * 4 Wire SPI Transport for ST7735 TFT display devices + */ +class ST7735_4WireSpiTransport +{ + public: + struct Config + { + struct + { + Pin dc; + Pin reset; + Pin cs; + } pin_config; + + void Defaults() + { + pin_config.dc = seed::D9; + pin_config.reset = seed::D30; + pin_config.cs = seed::D7; + } + }; + + void Init(const Config& config) + { + pin_dc_.Init(config.pin_config.dc, GPIO::Mode::OUTPUT); + pin_cs_.Init(config.pin_config.cs, GPIO::Mode::OUTPUT); + pin_reset_.Init(config.pin_config.reset, GPIO::Mode::OUTPUT); + + pin_dc_.Write(true); + pin_cs_.Write(true); + pin_reset_.Write(true); + + SpiHandle::Config spi_config; + spi_config.periph = SpiHandle::Config::Peripheral::SPI_1; + spi_config.mode = SpiHandle::Config::Mode::MASTER; + spi_config.direction = SpiHandle::Config::Direction::TWO_LINES_TX_ONLY; + spi_config.datasize = 8; + spi_config.clock_polarity = SpiHandle::Config::ClockPolarity::LOW; + spi_config.clock_phase = SpiHandle::Config::ClockPhase::ONE_EDGE; + spi_config.nss = SpiHandle::Config::NSS::SOFT; + spi_config.baud_prescaler = SpiHandle::Config::BaudPrescaler::PS_4; + spi_config.pin_config.sclk = seed::D8; + spi_config.pin_config.mosi = seed::D10; + spi_config.pin_config.miso = Pin(); + spi_config.pin_config.nss = Pin(); + + spi_.Init(spi_config); + + System::Delay(10); + + pin_reset_.Write(true); + System::Delay(10); + pin_reset_.Write(false); + System::Delay(10); + pin_reset_.Write(true); + System::Delay(120); + } + + void SendCommand(uint8_t cmd) + { + pin_dc_.Write(false); + pin_cs_.Write(false); + spi_.BlockingTransmit(&cmd, 1); + pin_cs_.Write(true); + } + + void SendData(uint8_t* buff, size_t size) + { + pin_dc_.Write(true); + pin_cs_.Write(false); + spi_.BlockingTransmit(buff, size); + pin_cs_.Write(true); + } + + private: + SpiHandle spi_; + GPIO pin_reset_; + GPIO pin_dc_; + GPIO pin_cs_; +}; + + +/** + * A driver implementation for the ST7735 TFT LCD + * API compatible with SSD130xDriver, with added color support + */ +template +class ST7735Driver +{ + public: + // RGB565 Color Constants - Rainbow Palette for Colorful UI + static constexpr uint16_t COLOR_BLACK = 0x0000; + static constexpr uint16_t COLOR_WHITE = 0xFFFF; + static constexpr uint16_t COLOR_RED = 0xF800; + static constexpr uint16_t COLOR_GREEN = 0x07E0; + static constexpr uint16_t COLOR_BLUE = 0x001F; + static constexpr uint16_t COLOR_CYAN = 0x07FF; + static constexpr uint16_t COLOR_MAGENTA = 0xF81F; + static constexpr uint16_t COLOR_YELLOW = 0xFFE0; + static constexpr uint16_t COLOR_ORANGE = 0xFC00; + static constexpr uint16_t COLOR_GRAY = 0x8410; + static constexpr uint16_t COLOR_PINK = 0xF81F; + static constexpr uint16_t COLOR_PURPLE = 0x780F; + static constexpr uint16_t COLOR_LIME = 0x87E0; + static constexpr uint16_t COLOR_NAVY = 0x0010; + static constexpr uint16_t COLOR_TEAL = 0x0410; + static constexpr uint16_t COLOR_BROWN = 0x8200; + static constexpr uint16_t COLOR_DARKGREEN = 0x0320; + static constexpr uint16_t COLOR_DARKBLUE = 0x0011; + static constexpr uint16_t COLOR_SKYBLUE = 0x5D1F; + static constexpr uint16_t COLOR_GOLD = 0xFEA0; + + // Convert RGB888 to RGB565 + static uint16_t RGB565(uint8_t r, uint8_t g, uint8_t b) + { + return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); + } + + struct Config + { + typename Transport::Config transport_config; + }; + + void Init(Config config) + { + transport_.Init(config.transport_config); + + // Initialize color palette for themes + foreground_color_ = COLOR_WHITE; + background_color_ = COLOR_BLACK; + accent_color_ = COLOR_CYAN; + + transport_.SendCommand(0x01); // SWRESET + System::Delay(150); + + transport_.SendCommand(0x11); // SLPOUT + System::Delay(120); + + transport_.SendCommand(0xB1); // FRMCTR1 + uint8_t frmctr1[] = {0x01, 0x2C, 0x2D}; + transport_.SendData(frmctr1, 3); + + transport_.SendCommand(0xB2); + transport_.SendData(frmctr1, 3); + + transport_.SendCommand(0xB3); + uint8_t frmctr3[] = {0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D}; + transport_.SendData(frmctr3, 6); + + transport_.SendCommand(0xB4); // INVCTR + uint8_t invctr = 0x07; + transport_.SendData(&invctr, 1); + + transport_.SendCommand(0xC0); // PWCTR1 + uint8_t pwctr1[] = {0xA2, 0x02, 0x84}; + transport_.SendData(pwctr1, 3); + + transport_.SendCommand(0xC1); + uint8_t pwctr2 = 0xC5; + transport_.SendData(&pwctr2, 1); + + transport_.SendCommand(0xC2); + uint8_t pwctr3[] = {0x0A, 0x00}; + transport_.SendData(pwctr3, 2); + + transport_.SendCommand(0xC3); + uint8_t pwctr4[] = {0x8A, 0x2A}; + transport_.SendData(pwctr4, 2); + + transport_.SendCommand(0xC4); + uint8_t pwctr5[] = {0x8A, 0xEE}; + transport_.SendData(pwctr5, 2); + + transport_.SendCommand(0xC5); // VMCTR1 + uint8_t vmctr1 = 0x0E; + transport_.SendData(&vmctr1, 1); + + transport_.SendCommand(0x20); // INVOFF + + transport_.SendCommand(0x36); // MADCTL + uint8_t madctl = 0xC8; + transport_.SendData(&madctl, 1); + + transport_.SendCommand(0x3A); // COLMOD + uint8_t colmod = 0x05; // 16-bit RGB565 + transport_.SendData(&colmod, 1); + + System::Delay(10); + + transport_.SendCommand(0xE0); // GMCTRP1 + uint8_t gmctrp1[] = {0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, + 0x29, 0x25, 0x2B, 0x39, 0x00, 0x01, 0x03, 0x10}; + transport_.SendData(gmctrp1, 16); + + transport_.SendCommand(0xE1); // GMCTRN1 + uint8_t gmctrn1[] = {0x03, 0x1d, 0x07, 0x06, 0x2E, 0x2C, 0x29, 0x2D, + 0x2E, 0x2E, 0x37, 0x3F, 0x00, 0x00, 0x02, 0x10}; + transport_.SendData(gmctrn1, 16); + + transport_.SendCommand(0x13); // NORON + System::Delay(10); + + transport_.SendCommand(0x29); // DISPON + System::Delay(100); + + Fill(false); + Update(); + } + + size_t Width() const { return width; } + size_t Height() const { return height; } + + // ============ Color Theme Functions ============ + + /** Set foreground (text) color */ + void SetForegroundColor(uint16_t color) { foreground_color_ = color; } + + /** Set background color */ + void SetBackgroundColor(uint16_t color) { background_color_ = color; } + + /** Set accent color (for highlights) */ + void SetAccentColor(uint16_t color) { accent_color_ = color; } + + /** Get current foreground color */ + uint16_t GetForegroundColor() const { return foreground_color_; } + + /** Get current background color */ + uint16_t GetBackgroundColor() const { return background_color_; } + + /** Get current accent color */ + uint16_t GetAccentColor() const { return accent_color_; } + + /** Set a complete color theme */ + void SetTheme(uint16_t fg, uint16_t bg, uint16_t accent) + { + foreground_color_ = fg; + background_color_ = bg; + accent_color_ = accent; + } + + /** Pre-defined themes */ + void SetThemeDefault() { SetTheme(COLOR_WHITE, COLOR_BLACK, COLOR_CYAN); } + void SetThemeCyberpunk() { SetTheme(COLOR_CYAN, COLOR_DARKBLUE, COLOR_MAGENTA); } + void SetThemeMatrix() { SetTheme(COLOR_GREEN, COLOR_BLACK, COLOR_LIME); } + void SetThemeSunset() { SetTheme(COLOR_ORANGE, COLOR_PURPLE, COLOR_YELLOW); } + void SetThemeOcean() { SetTheme(COLOR_SKYBLUE, COLOR_NAVY, COLOR_CYAN); } + void SetThemeRetro() { SetTheme(COLOR_YELLOW, COLOR_BROWN, COLOR_ORANGE); } + void SetThemeNeon() { SetTheme(COLOR_MAGENTA, COLOR_BLACK, COLOR_CYAN); } + + // ============ SSD130x Compatible Drawing Functions ============ + + /** Draw a pixel (SSD130x compatible - uses theme colors) */ + void DrawPixel(uint_fast8_t x, uint_fast8_t y, bool on) + { + DrawPixelColor(x, y, on ? foreground_color_ : background_color_); + } + + /** Draw a pixel with RGB565 color */ + void DrawPixelColor(uint_fast8_t x, uint_fast8_t y, uint16_t color) + { + if(x >= width || y >= height) + return; + size_t idx = (y * width + x) * 2; + buffer_[idx] = color >> 8; + buffer_[idx + 1] = color & 0xFF; + } + + /** Draw a pixel with RGB values (0-255) */ + void DrawPixelRGB(uint_fast8_t x, uint_fast8_t y, uint8_t r, uint8_t g, uint8_t b) + { + DrawPixelColor(x, y, RGB565(r, g, b)); + } + + /** Fill entire display (SSD130x compatible - uses theme colors) */ + void Fill(bool on) + { + FillColor(on ? foreground_color_ : background_color_); + } + + /** Fill entire display with RGB565 color */ + void FillColor(uint16_t color) + { + uint8_t hi = color >> 8; + uint8_t lo = color & 0xFF; + for(size_t i = 0; i < sizeof(buffer_); i += 2) + { + buffer_[i] = hi; + buffer_[i + 1] = lo; + } + } + + /** Draw a filled rectangle with color */ + void DrawRectFilled(uint_fast8_t x, uint_fast8_t y, + uint_fast8_t w, uint_fast8_t h, + uint16_t color) + { + for(uint_fast8_t j = y; j < y + h && j < height; j++) + for(uint_fast8_t i = x; i < x + w && i < width; i++) + DrawPixelColor(i, j, color); + } + + /** Draw rectangle outline (SSD130x compatible) */ + void DrawRect(uint_fast8_t x1, uint_fast8_t y1, + uint_fast8_t x2, uint_fast8_t y2, bool on) + { + DrawRectColor(x1, y1, x2, y2, on ? foreground_color_ : background_color_); + } + + /** Draw rectangle outline with color */ + void DrawRectColor(uint_fast8_t x1, uint_fast8_t y1, + uint_fast8_t x2, uint_fast8_t y2, uint16_t color) + { + DrawHLineColor(x1, y1, x2 - x1 + 1, color); + DrawHLineColor(x1, y2, x2 - x1 + 1, color); + DrawVLineColor(x1, y1, y2 - y1 + 1, color); + DrawVLineColor(x2, y1, y2 - y1 + 1, color); + } + + /** Draw a horizontal line (SSD130x compatible) */ + void DrawHLine(uint_fast8_t x, uint_fast8_t y, uint_fast8_t w, bool on) + { + DrawHLineColor(x, y, w, on ? foreground_color_ : background_color_); + } + + /** Draw a horizontal line with color */ + void DrawHLineColor(uint_fast8_t x, uint_fast8_t y, uint_fast8_t w, uint16_t color) + { + for(uint_fast8_t i = x; i < x + w && i < width; i++) + DrawPixelColor(i, y, color); + } + + /** Draw a vertical line (SSD130x compatible) */ + void DrawVLine(uint_fast8_t x, uint_fast8_t y, uint_fast8_t h, bool on) + { + DrawVLineColor(x, y, h, on ? foreground_color_ : background_color_); + } + + /** Draw a vertical line with color */ + void DrawVLineColor(uint_fast8_t x, uint_fast8_t y, uint_fast8_t h, uint16_t color) + { + for(uint_fast8_t j = y; j < y + h && j < height; j++) + DrawPixelColor(x, j, color); + } + + /** Draw a line (SSD130x compatible) */ + void DrawLine(uint_fast8_t x1, uint_fast8_t y1, + uint_fast8_t x2, uint_fast8_t y2, bool on) + { + DrawLineColor(x1, y1, x2, y2, on ? foreground_color_ : background_color_); + } + + /** Draw a line with color */ + void DrawLineColor(uint_fast8_t x1, uint_fast8_t y1, + uint_fast8_t x2, uint_fast8_t y2, uint16_t color) + { + int dx = abs((int)x2 - (int)x1); + int dy = abs((int)y2 - (int)y1); + int sx = (x1 < x2) ? 1 : -1; + int sy = (y1 < y2) ? 1 : -1; + int err = dx - dy; + + while(true) + { + DrawPixelColor(x1, y1, color); + if(x1 == x2 && y1 == y2) break; + int e2 = 2 * err; + if(e2 > -dy) { err -= dy; x1 += sx; } + if(e2 < dx) { err += dx; y1 += sy; } + } + } + + /** Update the display */ + void Update() + { + transport_.SendCommand(0x2A); + uint8_t caset[] = {0x00, 0x00, 0x00, (uint8_t)(width - 1)}; + transport_.SendData(caset, 4); + + transport_.SendCommand(0x2B); + uint8_t raset[] = {0x00, 0x00, 0x00, (uint8_t)(height - 1)}; + transport_.SendData(raset, 4); + + transport_.SendCommand(0x2C); + transport_.SendData(buffer_, sizeof(buffer_)); + } + + private: + Transport transport_; + uint8_t buffer_[width * height * 2]; + + // Theme colors + uint16_t foreground_color_; + uint16_t background_color_; + uint16_t accent_color_; +}; + +// Pre-defined driver types +using ST7735_4WireSpi128x160Driver = ST7735Driver<128, 160, ST7735_4WireSpiTransport>; +using ST7735_4WireSpi128x128Driver = ST7735Driver<128, 128, ST7735_4WireSpiTransport>; +using ST7735_4WireSpi80x160Driver = ST7735Driver<80, 160, ST7735_4WireSpiTransport>; + +} // namespace daisy + +#endif // DSY_ST7735_H From 83cf2773359192e0adb50a8c657980a47b58f422 Mon Sep 17 00:00:00 2001 From: noisehoho Date: Wed, 10 Dec 2025 03:41:42 +0800 Subject: [PATCH 2/9] Add support for multiple ST7735 screen resolutions - seed_st7735: 128x160 (standard 1.8" TFT) - seed_st7735_128x128: 128x128 (square 1.44" TFT) - seed_st7735_80x160: 80x160 (mini 0.96" TFT) --- source/oopsy.js | 2 ++ source/seed.st7735_128x128.json | 43 +++++++++++++++++++++++++++++++++ source/seed.st7735_80x160.json | 43 +++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 source/seed.st7735_128x128.json create mode 100644 source/seed.st7735_80x160.json diff --git a/source/oopsy.js b/source/oopsy.js index 866bf8c..0cbd143 100755 --- a/source/oopsy.js +++ b/source/oopsy.js @@ -468,6 +468,8 @@ function run() { case "bluemchen": target_path = path.join(__dirname, "seed.bluemchen.json"); break; case "nehcmeulb": target_path = path.join(__dirname, "seed.nehcmeulb.json"); break; case "seed_st7735": target_path = path.join(__dirname, "seed.st7735.json"); break; + case "seed_st7735_128x128": target_path = path.join(__dirname, "seed.st7735_128x128.json"); break; + case "seed_st7735_80x160": target_path = path.join(__dirname, "seed.st7735_80x160.json"); break; case "watch": watch=true; break; diff --git a/source/seed.st7735_128x128.json b/source/seed.st7735_128x128.json new file mode 100644 index 0000000..1277cce --- /dev/null +++ b/source/seed.st7735_128x128.json @@ -0,0 +1,43 @@ +{ + "name": "seed_st7735_128x128", + "max_apps": 8, + "defines": { + "OOPSY_TARGET_HAS_OLED": 1, + "OOPSY_TARGET_ST7735": 1, + "OOPSY_OLED_DISPLAY_WIDTH": 128, + "OOPSY_OLED_DISPLAY_HEIGHT": 128 + }, + "display": { + "driver": "daisy::ST7735_4WireSpi128x128Driver", + "dim": [128, 128], + "config": [] + }, + "inserts": [], + "components": { + "knob1": { "component": "AnalogControl", "pin": 15 }, + "knob2": { "component": "AnalogControl", "pin": 16 }, + "knob3": { "component": "AnalogControl", "pin": 21 }, + "knob4": { "component": "AnalogControl", "pin": 18 }, + "encoder": { + "component": "Encoder", + "pin": {"a": 12, "b": 11, "click": 0}, + "meta": [ + "menu_hold = ${name}.TimeHeldMs();", + "menu_click = ${name}.FallingEdge();", + "menu_rotate = ${name}.Increment();" + ] + }, + "gate1": { "component": "GateIn", "pin": 20 }, + "gate2": { "component": "GateIn", "pin": 19 } + }, + "labels": { + "params": { + "knob1": "knob1", "knob2": "knob2", "knob3": "knob3", "knob4": "knob4", + "cv1": "knob1", "cv2": "knob2", "cv3": "knob3", "cv4": "knob4", + "gate1": "gate1", "gate2": "gate2", "gate": "gate1" + }, + "outs": {}, + "datas": {} + }, + "aliases": {} +} diff --git a/source/seed.st7735_80x160.json b/source/seed.st7735_80x160.json new file mode 100644 index 0000000..6dcbd28 --- /dev/null +++ b/source/seed.st7735_80x160.json @@ -0,0 +1,43 @@ +{ + "name": "seed_st7735_80x160", + "max_apps": 8, + "defines": { + "OOPSY_TARGET_HAS_OLED": 1, + "OOPSY_TARGET_ST7735": 1, + "OOPSY_OLED_DISPLAY_WIDTH": 80, + "OOPSY_OLED_DISPLAY_HEIGHT": 160 + }, + "display": { + "driver": "daisy::ST7735_4WireSpi80x160Driver", + "dim": [80, 160], + "config": [] + }, + "inserts": [], + "components": { + "knob1": { "component": "AnalogControl", "pin": 15 }, + "knob2": { "component": "AnalogControl", "pin": 16 }, + "knob3": { "component": "AnalogControl", "pin": 21 }, + "knob4": { "component": "AnalogControl", "pin": 18 }, + "encoder": { + "component": "Encoder", + "pin": {"a": 12, "b": 11, "click": 0}, + "meta": [ + "menu_hold = ${name}.TimeHeldMs();", + "menu_click = ${name}.FallingEdge();", + "menu_rotate = ${name}.Increment();" + ] + }, + "gate1": { "component": "GateIn", "pin": 20 }, + "gate2": { "component": "GateIn", "pin": 19 } + }, + "labels": { + "params": { + "knob1": "knob1", "knob2": "knob2", "knob3": "knob3", "knob4": "knob4", + "cv1": "knob1", "cv2": "knob2", "cv3": "knob3", "cv4": "knob4", + "gate1": "gate1", "gate2": "gate2", "gate": "gate1" + }, + "outs": {}, + "datas": {} + }, + "aliases": {} +} From 94d4200687ecce40f5a56999bff87811defd315f Mon Sep 17 00:00:00 2001 From: noisehoho Date: Wed, 10 Dec 2025 03:44:26 +0800 Subject: [PATCH 3/9] Update README with multi-resolution support documentation --- source/ST7735_README.md | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/source/ST7735_README.md b/source/ST7735_README.md index 15b17fc..a88b5be 100644 --- a/source/ST7735_README.md +++ b/source/ST7735_README.md @@ -1,14 +1,23 @@ # ST7735 TFT Display Support for Oopsy -This adds support for **ST7735 RGB TFT displays** (128x160, 65K colors) to Oopsy, as a drop-in replacement for the standard SSD130x OLED displays. +This adds support for **ST7735 RGB TFT displays** (65K colors) to Oopsy, as a drop-in replacement for the standard SSD130x OLED displays. ## Features - 🌈 **Full RGB565 Color Support** - 65,536 colors - 🎨 **Colorful UI Themes** - Different color schemes for each display mode +- 📐 **Multiple Resolutions** - Support for 128x160, 128x128, and 80x160 displays - 🔌 **Daisy Patch Compatible Pinout** - Works with standard Daisy Patch wiring - 📦 **Drop-in Replacement** - Same API as SSD130x, just change the target +## Supported Screen Sizes + +| Target Name | Resolution | Screen Type | +|-------------|------------|-------------| +| `seed_st7735` | 128×160 | Standard 1.8" TFT | +| `seed_st7735_128x128` | 128×128 | Square 1.44" TFT | +| `seed_st7735_80x160` | 80×160 | Mini 0.96" TFT | + ## Color Themes by Mode | Mode | Foreground | Background | Style | @@ -54,7 +63,10 @@ This adds support for **ST7735 RGB TFT displays** (128x160, 65K colors) to Oopsy ### 1. Select the ST7735 Target -In `oopsy.maxpat`, select **seed_st7735** from the Target dropdown menu. +In `oopsy.maxpat`, select your display size from the Target dropdown menu: +- **seed_st7735** - for 128x160 displays +- **seed_st7735_128x128** - for 128x128 displays +- **seed_st7735_80x160** - for 80x160 displays ### 2. Create Your gen~ Patch @@ -100,17 +112,18 @@ Use `RGB565(r, g, b)` to create custom colors: uint16_t myColor = Driver::RGB565(255, 128, 0); // Orange ``` -## Files Modified/Added +## Files Added/Modified ### New Files -- `source/libdaisy/src/dev/st7735.h` - ST7735 driver -- `source/seed.st7735.json` - Oopsy target configuration +- `source/st7735.h` - ST7735 driver with color support +- `source/seed.st7735.json` - Target config for 128x160 +- `source/seed.st7735_128x128.json` - Target config for 128x128 +- `source/seed.st7735_80x160.json` - Target config for 80x160 +- `source/ST7735_README.md` - This documentation ### Modified Files -- `source/oopsy.js` - Added ST7735 header detection and target path +- `source/oopsy.js` - Added ST7735 header detection and target paths - `source/genlib_daisy.h` - Added color theme switching -- `source/libdaisy/src/hid/disp/oled_display.h` - Added `GetDriver()` method -- `patchers/oopsy.maxpat` - Added seed_st7735 to target menu ## Customizing Themes @@ -138,7 +151,6 @@ Edit `genlib_daisy.h` to change color themes: | Property | Value | |----------|-------| -| Resolution | 128 x 160 pixels | | Color Depth | 16-bit RGB565 (65K colors) | | Interface | SPI (4-wire) | | Controller | ST7735S | @@ -159,6 +171,10 @@ Edit `genlib_daisy.h` to change color themes: - Verify encoder pins: A=D12, B=D11, Click=D0 - Check if D0 conflicts with other hardware +### Screen offset issues +- Different ST7735 modules may need offset adjustment +- Edit `st7735.h` CASET/RASET values if needed + ## Author Created by **noisehoho** for the Daisy/Oopsy community. From 104776e3b0266c505fdf54e0b0a59cb469f5dc11 Mon Sep 17 00:00:00 2001 From: noisehoho Date: Wed, 10 Dec 2025 04:02:04 +0800 Subject: [PATCH 4/9] Add 128x64 resolution support (Daisy Patch compatible) --- source/oopsy.js | 1 + source/seed.st7735_128x64.json | 43 ++++++++++++++++++++++++++++++++++ source/st7735.h | 1 + 3 files changed, 45 insertions(+) create mode 100644 source/seed.st7735_128x64.json diff --git a/source/oopsy.js b/source/oopsy.js index 0cbd143..6c318c8 100755 --- a/source/oopsy.js +++ b/source/oopsy.js @@ -470,6 +470,7 @@ function run() { case "seed_st7735": target_path = path.join(__dirname, "seed.st7735.json"); break; case "seed_st7735_128x128": target_path = path.join(__dirname, "seed.st7735_128x128.json"); break; case "seed_st7735_80x160": target_path = path.join(__dirname, "seed.st7735_80x160.json"); break; + case "seed_st7735_128x64": target_path = path.join(__dirname, "seed.st7735_128x64.json"); break; case "watch": watch=true; break; diff --git a/source/seed.st7735_128x64.json b/source/seed.st7735_128x64.json new file mode 100644 index 0000000..f34c36b --- /dev/null +++ b/source/seed.st7735_128x64.json @@ -0,0 +1,43 @@ +{ + "name": "seed_st7735_128x64", + "max_apps": 8, + "defines": { + "OOPSY_TARGET_HAS_OLED": 1, + "OOPSY_TARGET_ST7735": 1, + "OOPSY_OLED_DISPLAY_WIDTH": 128, + "OOPSY_OLED_DISPLAY_HEIGHT": 64 + }, + "display": { + "driver": "daisy::ST7735_4WireSpi128x64Driver", + "dim": [128, 64], + "config": [] + }, + "inserts": [], + "components": { + "knob1": { "component": "AnalogControl", "pin": 15 }, + "knob2": { "component": "AnalogControl", "pin": 16 }, + "knob3": { "component": "AnalogControl", "pin": 21 }, + "knob4": { "component": "AnalogControl", "pin": 18 }, + "encoder": { + "component": "Encoder", + "pin": {"a": 12, "b": 11, "click": 0}, + "meta": [ + "menu_hold = ${name}.TimeHeldMs();", + "menu_click = ${name}.FallingEdge();", + "menu_rotate = ${name}.Increment();" + ] + }, + "gate1": { "component": "GateIn", "pin": 20 }, + "gate2": { "component": "GateIn", "pin": 19 } + }, + "labels": { + "params": { + "knob1": "knob1", "knob2": "knob2", "knob3": "knob3", "knob4": "knob4", + "cv1": "knob1", "cv2": "knob2", "cv3": "knob3", "cv4": "knob4", + "gate1": "gate1", "gate2": "gate2", "gate": "gate1" + }, + "outs": {}, + "datas": {} + }, + "aliases": {} +} diff --git a/source/st7735.h b/source/st7735.h index 3c5942b..e0b446b 100644 --- a/source/st7735.h +++ b/source/st7735.h @@ -423,6 +423,7 @@ class ST7735Driver using ST7735_4WireSpi128x160Driver = ST7735Driver<128, 160, ST7735_4WireSpiTransport>; using ST7735_4WireSpi128x128Driver = ST7735Driver<128, 128, ST7735_4WireSpiTransport>; using ST7735_4WireSpi80x160Driver = ST7735Driver<80, 160, ST7735_4WireSpiTransport>; +using ST7735_4WireSpi128x64Driver = ST7735Driver<128, 64, ST7735_4WireSpiTransport>; } // namespace daisy From 6feb3fa4f2ffcec5fb7f1628ce32c3a387b3b08f Mon Sep 17 00:00:00 2001 From: noisehoho Date: Wed, 10 Dec 2025 16:39:55 +0800 Subject: [PATCH 5/9] Delete source/ST7735_README.md --- source/ST7735_README.md | 184 ---------------------------------------- 1 file changed, 184 deletions(-) delete mode 100644 source/ST7735_README.md diff --git a/source/ST7735_README.md b/source/ST7735_README.md deleted file mode 100644 index a88b5be..0000000 --- a/source/ST7735_README.md +++ /dev/null @@ -1,184 +0,0 @@ -# ST7735 TFT Display Support for Oopsy - -This adds support for **ST7735 RGB TFT displays** (65K colors) to Oopsy, as a drop-in replacement for the standard SSD130x OLED displays. - -## Features - -- 🌈 **Full RGB565 Color Support** - 65,536 colors -- 🎨 **Colorful UI Themes** - Different color schemes for each display mode -- 📐 **Multiple Resolutions** - Support for 128x160, 128x128, and 80x160 displays -- 🔌 **Daisy Patch Compatible Pinout** - Works with standard Daisy Patch wiring -- 📦 **Drop-in Replacement** - Same API as SSD130x, just change the target - -## Supported Screen Sizes - -| Target Name | Resolution | Screen Type | -|-------------|------------|-------------| -| `seed_st7735` | 128×160 | Standard 1.8" TFT | -| `seed_st7735_128x128` | 128×128 | Square 1.44" TFT | -| `seed_st7735_80x160` | 80×160 | Mini 0.96" TFT | - -## Color Themes by Mode - -| Mode | Foreground | Background | Style | -|------|------------|------------|-------| -| **MENU** | Cyan | Dark Blue | Cyberpunk | -| **PARAMS** | Green | Black | Matrix | -| **SCOPE** | Orange | Purple | Sunset | -| **CONSOLE** | Magenta | Black | Neon | - -## Hardware Wiring - -### ST7735 Display Pinout (Daisy Seed) - -| ST7735 Pin | Daisy Seed Pin | Function | -|------------|----------------|----------| -| VCC | 3V3 | Power (3.3V) | -| GND | GND | Ground | -| SCL/SCK | D8 (PG11) | SPI Clock | -| SDA/MOSI | D10 (PB5) | SPI Data | -| DC | D9 (PB4) | Data/Command | -| CS | D7 (PA2) | Chip Select | -| RST/RES | D30 (PB15) | Reset | -| BLK | 3V3 or PWM | Backlight | - -### Encoder Pinout (Daisy Patch Compatible) - -| Encoder Pin | Daisy Seed Pin | -|-------------|----------------| -| A | D12 | -| B | D11 | -| Click/SW | D0 | - -### Knob Pinout - -| Knob | Daisy Seed Pin | -|------|----------------| -| Knob 1 | D15 | -| Knob 2 | D16 | -| Knob 3 | D21 | -| Knob 4 | D18 | - -## Usage with Oopsy - -### 1. Select the ST7735 Target - -In `oopsy.maxpat`, select your display size from the Target dropdown menu: -- **seed_st7735** - for 128x160 displays -- **seed_st7735_128x128** - for 128x128 displays -- **seed_st7735_80x160** - for 80x160 displays - -### 2. Create Your gen~ Patch - -Use standard gen~ with `Param` objects: - -``` -// Example gen~ code -Param gain(0.5, min=0, max=1); -Param frequency(440, min=20, max=2000); - -in 1 left; -out 1 output; - -output = left * gain; -``` - -### 3. Flash to Daisy - -Click the **Flash** button in Oopsy. The display will show your parameters with colorful themes! - -## Display Controls - -- **Long Press Encoder** (>0.5s) - Open mode selection menu -- **Rotate Encoder** - Navigate / Select -- **Short Press Encoder** - Confirm selection - -## Available Colors - -The driver provides these predefined colors: - -```cpp -COLOR_BLACK, COLOR_WHITE, COLOR_RED, COLOR_GREEN, COLOR_BLUE, -COLOR_CYAN, COLOR_MAGENTA, COLOR_YELLOW, COLOR_ORANGE, COLOR_GRAY, -COLOR_PINK, COLOR_PURPLE, COLOR_LIME, COLOR_NAVY, COLOR_TEAL, -COLOR_BROWN, COLOR_DARKGREEN, COLOR_DARKBLUE, COLOR_SKYBLUE, COLOR_GOLD -``` - -### Custom Colors - -Use `RGB565(r, g, b)` to create custom colors: - -```cpp -uint16_t myColor = Driver::RGB565(255, 128, 0); // Orange -``` - -## Files Added/Modified - -### New Files -- `source/st7735.h` - ST7735 driver with color support -- `source/seed.st7735.json` - Target config for 128x160 -- `source/seed.st7735_128x128.json` - Target config for 128x128 -- `source/seed.st7735_80x160.json` - Target config for 80x160 -- `source/ST7735_README.md` - This documentation - -### Modified Files -- `source/oopsy.js` - Added ST7735 header detection and target paths -- `source/genlib_daisy.h` - Added color theme switching - -## Customizing Themes - -Edit `genlib_daisy.h` to change color themes: - -```cpp -#ifdef OOPSY_TARGET_ST7735 -{ - using Driver = daisy::ST7735_4WireSpi128x160Driver; - switch(mode) { - case MODE_MENU: - hardware.display.GetDriver().SetTheme( - Driver::COLOR_CYAN, // Foreground - Driver::COLOR_DARKBLUE, // Background - Driver::COLOR_MAGENTA // Accent - ); - break; - // ... other modes - } -} -#endif -``` - -## Display Specifications - -| Property | Value | -|----------|-------| -| Color Depth | 16-bit RGB565 (65K colors) | -| Interface | SPI (4-wire) | -| Controller | ST7735S | -| Refresh Rate | ~30 FPS | - -## Troubleshooting - -### Display is blank -- Check wiring connections -- Verify RST pin is connected to D30 -- Check backlight connection (BLK to 3V3) - -### Wrong colors -- Ensure ST7735S variant (not ST7735R) -- Check MADCTL setting in driver if colors are inverted - -### Encoder not working -- Verify encoder pins: A=D12, B=D11, Click=D0 -- Check if D0 conflicts with other hardware - -### Screen offset issues -- Different ST7735 modules may need offset adjustment -- Edit `st7735.h` CASET/RASET values if needed - -## Author - -Created by **noisehoho** for the Daisy/Oopsy community. - -## License - -MIT License - Same as Oopsy From b8f9388114009585da0ab774f51f312c6079c5c1 Mon Sep 17 00:00:00 2001 From: noisehoho Date: Wed, 10 Dec 2025 16:43:17 +0800 Subject: [PATCH 6/9] Delete source/seed.st7735_128x128.json --- source/seed.st7735_128x128.json | 43 --------------------------------- 1 file changed, 43 deletions(-) delete mode 100644 source/seed.st7735_128x128.json diff --git a/source/seed.st7735_128x128.json b/source/seed.st7735_128x128.json deleted file mode 100644 index 1277cce..0000000 --- a/source/seed.st7735_128x128.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "seed_st7735_128x128", - "max_apps": 8, - "defines": { - "OOPSY_TARGET_HAS_OLED": 1, - "OOPSY_TARGET_ST7735": 1, - "OOPSY_OLED_DISPLAY_WIDTH": 128, - "OOPSY_OLED_DISPLAY_HEIGHT": 128 - }, - "display": { - "driver": "daisy::ST7735_4WireSpi128x128Driver", - "dim": [128, 128], - "config": [] - }, - "inserts": [], - "components": { - "knob1": { "component": "AnalogControl", "pin": 15 }, - "knob2": { "component": "AnalogControl", "pin": 16 }, - "knob3": { "component": "AnalogControl", "pin": 21 }, - "knob4": { "component": "AnalogControl", "pin": 18 }, - "encoder": { - "component": "Encoder", - "pin": {"a": 12, "b": 11, "click": 0}, - "meta": [ - "menu_hold = ${name}.TimeHeldMs();", - "menu_click = ${name}.FallingEdge();", - "menu_rotate = ${name}.Increment();" - ] - }, - "gate1": { "component": "GateIn", "pin": 20 }, - "gate2": { "component": "GateIn", "pin": 19 } - }, - "labels": { - "params": { - "knob1": "knob1", "knob2": "knob2", "knob3": "knob3", "knob4": "knob4", - "cv1": "knob1", "cv2": "knob2", "cv3": "knob3", "cv4": "knob4", - "gate1": "gate1", "gate2": "gate2", "gate": "gate1" - }, - "outs": {}, - "datas": {} - }, - "aliases": {} -} From fb37c80d36efe6bc1ae611d9b561a8f74f913fcf Mon Sep 17 00:00:00 2001 From: noisehoho Date: Wed, 10 Dec 2025 16:43:42 +0800 Subject: [PATCH 7/9] Delete source/st7735.h --- source/st7735.h | 430 ------------------------------------------------ 1 file changed, 430 deletions(-) delete mode 100644 source/st7735.h diff --git a/source/st7735.h b/source/st7735.h deleted file mode 100644 index e0b446b..0000000 --- a/source/st7735.h +++ /dev/null @@ -1,430 +0,0 @@ -/** - * @file st7735.h - * @brief ST7735 TFT LCD Driver for Daisy - * - * Compatible with OledDisplay template, drop-in replacement for SSD130x - * Supports RGB565 color (65K colors) - * - * Default Wiring (Daisy Seed / Daisy Patch compatible): - * SCL -> D8 (SPI1_SCK / PG11) - * SDA -> D10 (SPI1_MOSI / PB5) - * DC -> D9 (PB4) - * CS -> D7 (PA2) - Software CS - * RES -> D30 (PB15) - */ - -#pragma once -#ifndef DSY_ST7735_H -#define DSY_ST7735_H - -#include "daisy_seed.h" - -namespace daisy -{ - -/** - * 4 Wire SPI Transport for ST7735 TFT display devices - */ -class ST7735_4WireSpiTransport -{ - public: - struct Config - { - struct - { - Pin dc; - Pin reset; - Pin cs; - } pin_config; - - void Defaults() - { - pin_config.dc = seed::D9; - pin_config.reset = seed::D30; - pin_config.cs = seed::D7; - } - }; - - void Init(const Config& config) - { - pin_dc_.Init(config.pin_config.dc, GPIO::Mode::OUTPUT); - pin_cs_.Init(config.pin_config.cs, GPIO::Mode::OUTPUT); - pin_reset_.Init(config.pin_config.reset, GPIO::Mode::OUTPUT); - - pin_dc_.Write(true); - pin_cs_.Write(true); - pin_reset_.Write(true); - - SpiHandle::Config spi_config; - spi_config.periph = SpiHandle::Config::Peripheral::SPI_1; - spi_config.mode = SpiHandle::Config::Mode::MASTER; - spi_config.direction = SpiHandle::Config::Direction::TWO_LINES_TX_ONLY; - spi_config.datasize = 8; - spi_config.clock_polarity = SpiHandle::Config::ClockPolarity::LOW; - spi_config.clock_phase = SpiHandle::Config::ClockPhase::ONE_EDGE; - spi_config.nss = SpiHandle::Config::NSS::SOFT; - spi_config.baud_prescaler = SpiHandle::Config::BaudPrescaler::PS_4; - spi_config.pin_config.sclk = seed::D8; - spi_config.pin_config.mosi = seed::D10; - spi_config.pin_config.miso = Pin(); - spi_config.pin_config.nss = Pin(); - - spi_.Init(spi_config); - - System::Delay(10); - - pin_reset_.Write(true); - System::Delay(10); - pin_reset_.Write(false); - System::Delay(10); - pin_reset_.Write(true); - System::Delay(120); - } - - void SendCommand(uint8_t cmd) - { - pin_dc_.Write(false); - pin_cs_.Write(false); - spi_.BlockingTransmit(&cmd, 1); - pin_cs_.Write(true); - } - - void SendData(uint8_t* buff, size_t size) - { - pin_dc_.Write(true); - pin_cs_.Write(false); - spi_.BlockingTransmit(buff, size); - pin_cs_.Write(true); - } - - private: - SpiHandle spi_; - GPIO pin_reset_; - GPIO pin_dc_; - GPIO pin_cs_; -}; - - -/** - * A driver implementation for the ST7735 TFT LCD - * API compatible with SSD130xDriver, with added color support - */ -template -class ST7735Driver -{ - public: - // RGB565 Color Constants - Rainbow Palette for Colorful UI - static constexpr uint16_t COLOR_BLACK = 0x0000; - static constexpr uint16_t COLOR_WHITE = 0xFFFF; - static constexpr uint16_t COLOR_RED = 0xF800; - static constexpr uint16_t COLOR_GREEN = 0x07E0; - static constexpr uint16_t COLOR_BLUE = 0x001F; - static constexpr uint16_t COLOR_CYAN = 0x07FF; - static constexpr uint16_t COLOR_MAGENTA = 0xF81F; - static constexpr uint16_t COLOR_YELLOW = 0xFFE0; - static constexpr uint16_t COLOR_ORANGE = 0xFC00; - static constexpr uint16_t COLOR_GRAY = 0x8410; - static constexpr uint16_t COLOR_PINK = 0xF81F; - static constexpr uint16_t COLOR_PURPLE = 0x780F; - static constexpr uint16_t COLOR_LIME = 0x87E0; - static constexpr uint16_t COLOR_NAVY = 0x0010; - static constexpr uint16_t COLOR_TEAL = 0x0410; - static constexpr uint16_t COLOR_BROWN = 0x8200; - static constexpr uint16_t COLOR_DARKGREEN = 0x0320; - static constexpr uint16_t COLOR_DARKBLUE = 0x0011; - static constexpr uint16_t COLOR_SKYBLUE = 0x5D1F; - static constexpr uint16_t COLOR_GOLD = 0xFEA0; - - // Convert RGB888 to RGB565 - static uint16_t RGB565(uint8_t r, uint8_t g, uint8_t b) - { - return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); - } - - struct Config - { - typename Transport::Config transport_config; - }; - - void Init(Config config) - { - transport_.Init(config.transport_config); - - // Initialize color palette for themes - foreground_color_ = COLOR_WHITE; - background_color_ = COLOR_BLACK; - accent_color_ = COLOR_CYAN; - - transport_.SendCommand(0x01); // SWRESET - System::Delay(150); - - transport_.SendCommand(0x11); // SLPOUT - System::Delay(120); - - transport_.SendCommand(0xB1); // FRMCTR1 - uint8_t frmctr1[] = {0x01, 0x2C, 0x2D}; - transport_.SendData(frmctr1, 3); - - transport_.SendCommand(0xB2); - transport_.SendData(frmctr1, 3); - - transport_.SendCommand(0xB3); - uint8_t frmctr3[] = {0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D}; - transport_.SendData(frmctr3, 6); - - transport_.SendCommand(0xB4); // INVCTR - uint8_t invctr = 0x07; - transport_.SendData(&invctr, 1); - - transport_.SendCommand(0xC0); // PWCTR1 - uint8_t pwctr1[] = {0xA2, 0x02, 0x84}; - transport_.SendData(pwctr1, 3); - - transport_.SendCommand(0xC1); - uint8_t pwctr2 = 0xC5; - transport_.SendData(&pwctr2, 1); - - transport_.SendCommand(0xC2); - uint8_t pwctr3[] = {0x0A, 0x00}; - transport_.SendData(pwctr3, 2); - - transport_.SendCommand(0xC3); - uint8_t pwctr4[] = {0x8A, 0x2A}; - transport_.SendData(pwctr4, 2); - - transport_.SendCommand(0xC4); - uint8_t pwctr5[] = {0x8A, 0xEE}; - transport_.SendData(pwctr5, 2); - - transport_.SendCommand(0xC5); // VMCTR1 - uint8_t vmctr1 = 0x0E; - transport_.SendData(&vmctr1, 1); - - transport_.SendCommand(0x20); // INVOFF - - transport_.SendCommand(0x36); // MADCTL - uint8_t madctl = 0xC8; - transport_.SendData(&madctl, 1); - - transport_.SendCommand(0x3A); // COLMOD - uint8_t colmod = 0x05; // 16-bit RGB565 - transport_.SendData(&colmod, 1); - - System::Delay(10); - - transport_.SendCommand(0xE0); // GMCTRP1 - uint8_t gmctrp1[] = {0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, - 0x29, 0x25, 0x2B, 0x39, 0x00, 0x01, 0x03, 0x10}; - transport_.SendData(gmctrp1, 16); - - transport_.SendCommand(0xE1); // GMCTRN1 - uint8_t gmctrn1[] = {0x03, 0x1d, 0x07, 0x06, 0x2E, 0x2C, 0x29, 0x2D, - 0x2E, 0x2E, 0x37, 0x3F, 0x00, 0x00, 0x02, 0x10}; - transport_.SendData(gmctrn1, 16); - - transport_.SendCommand(0x13); // NORON - System::Delay(10); - - transport_.SendCommand(0x29); // DISPON - System::Delay(100); - - Fill(false); - Update(); - } - - size_t Width() const { return width; } - size_t Height() const { return height; } - - // ============ Color Theme Functions ============ - - /** Set foreground (text) color */ - void SetForegroundColor(uint16_t color) { foreground_color_ = color; } - - /** Set background color */ - void SetBackgroundColor(uint16_t color) { background_color_ = color; } - - /** Set accent color (for highlights) */ - void SetAccentColor(uint16_t color) { accent_color_ = color; } - - /** Get current foreground color */ - uint16_t GetForegroundColor() const { return foreground_color_; } - - /** Get current background color */ - uint16_t GetBackgroundColor() const { return background_color_; } - - /** Get current accent color */ - uint16_t GetAccentColor() const { return accent_color_; } - - /** Set a complete color theme */ - void SetTheme(uint16_t fg, uint16_t bg, uint16_t accent) - { - foreground_color_ = fg; - background_color_ = bg; - accent_color_ = accent; - } - - /** Pre-defined themes */ - void SetThemeDefault() { SetTheme(COLOR_WHITE, COLOR_BLACK, COLOR_CYAN); } - void SetThemeCyberpunk() { SetTheme(COLOR_CYAN, COLOR_DARKBLUE, COLOR_MAGENTA); } - void SetThemeMatrix() { SetTheme(COLOR_GREEN, COLOR_BLACK, COLOR_LIME); } - void SetThemeSunset() { SetTheme(COLOR_ORANGE, COLOR_PURPLE, COLOR_YELLOW); } - void SetThemeOcean() { SetTheme(COLOR_SKYBLUE, COLOR_NAVY, COLOR_CYAN); } - void SetThemeRetro() { SetTheme(COLOR_YELLOW, COLOR_BROWN, COLOR_ORANGE); } - void SetThemeNeon() { SetTheme(COLOR_MAGENTA, COLOR_BLACK, COLOR_CYAN); } - - // ============ SSD130x Compatible Drawing Functions ============ - - /** Draw a pixel (SSD130x compatible - uses theme colors) */ - void DrawPixel(uint_fast8_t x, uint_fast8_t y, bool on) - { - DrawPixelColor(x, y, on ? foreground_color_ : background_color_); - } - - /** Draw a pixel with RGB565 color */ - void DrawPixelColor(uint_fast8_t x, uint_fast8_t y, uint16_t color) - { - if(x >= width || y >= height) - return; - size_t idx = (y * width + x) * 2; - buffer_[idx] = color >> 8; - buffer_[idx + 1] = color & 0xFF; - } - - /** Draw a pixel with RGB values (0-255) */ - void DrawPixelRGB(uint_fast8_t x, uint_fast8_t y, uint8_t r, uint8_t g, uint8_t b) - { - DrawPixelColor(x, y, RGB565(r, g, b)); - } - - /** Fill entire display (SSD130x compatible - uses theme colors) */ - void Fill(bool on) - { - FillColor(on ? foreground_color_ : background_color_); - } - - /** Fill entire display with RGB565 color */ - void FillColor(uint16_t color) - { - uint8_t hi = color >> 8; - uint8_t lo = color & 0xFF; - for(size_t i = 0; i < sizeof(buffer_); i += 2) - { - buffer_[i] = hi; - buffer_[i + 1] = lo; - } - } - - /** Draw a filled rectangle with color */ - void DrawRectFilled(uint_fast8_t x, uint_fast8_t y, - uint_fast8_t w, uint_fast8_t h, - uint16_t color) - { - for(uint_fast8_t j = y; j < y + h && j < height; j++) - for(uint_fast8_t i = x; i < x + w && i < width; i++) - DrawPixelColor(i, j, color); - } - - /** Draw rectangle outline (SSD130x compatible) */ - void DrawRect(uint_fast8_t x1, uint_fast8_t y1, - uint_fast8_t x2, uint_fast8_t y2, bool on) - { - DrawRectColor(x1, y1, x2, y2, on ? foreground_color_ : background_color_); - } - - /** Draw rectangle outline with color */ - void DrawRectColor(uint_fast8_t x1, uint_fast8_t y1, - uint_fast8_t x2, uint_fast8_t y2, uint16_t color) - { - DrawHLineColor(x1, y1, x2 - x1 + 1, color); - DrawHLineColor(x1, y2, x2 - x1 + 1, color); - DrawVLineColor(x1, y1, y2 - y1 + 1, color); - DrawVLineColor(x2, y1, y2 - y1 + 1, color); - } - - /** Draw a horizontal line (SSD130x compatible) */ - void DrawHLine(uint_fast8_t x, uint_fast8_t y, uint_fast8_t w, bool on) - { - DrawHLineColor(x, y, w, on ? foreground_color_ : background_color_); - } - - /** Draw a horizontal line with color */ - void DrawHLineColor(uint_fast8_t x, uint_fast8_t y, uint_fast8_t w, uint16_t color) - { - for(uint_fast8_t i = x; i < x + w && i < width; i++) - DrawPixelColor(i, y, color); - } - - /** Draw a vertical line (SSD130x compatible) */ - void DrawVLine(uint_fast8_t x, uint_fast8_t y, uint_fast8_t h, bool on) - { - DrawVLineColor(x, y, h, on ? foreground_color_ : background_color_); - } - - /** Draw a vertical line with color */ - void DrawVLineColor(uint_fast8_t x, uint_fast8_t y, uint_fast8_t h, uint16_t color) - { - for(uint_fast8_t j = y; j < y + h && j < height; j++) - DrawPixelColor(x, j, color); - } - - /** Draw a line (SSD130x compatible) */ - void DrawLine(uint_fast8_t x1, uint_fast8_t y1, - uint_fast8_t x2, uint_fast8_t y2, bool on) - { - DrawLineColor(x1, y1, x2, y2, on ? foreground_color_ : background_color_); - } - - /** Draw a line with color */ - void DrawLineColor(uint_fast8_t x1, uint_fast8_t y1, - uint_fast8_t x2, uint_fast8_t y2, uint16_t color) - { - int dx = abs((int)x2 - (int)x1); - int dy = abs((int)y2 - (int)y1); - int sx = (x1 < x2) ? 1 : -1; - int sy = (y1 < y2) ? 1 : -1; - int err = dx - dy; - - while(true) - { - DrawPixelColor(x1, y1, color); - if(x1 == x2 && y1 == y2) break; - int e2 = 2 * err; - if(e2 > -dy) { err -= dy; x1 += sx; } - if(e2 < dx) { err += dx; y1 += sy; } - } - } - - /** Update the display */ - void Update() - { - transport_.SendCommand(0x2A); - uint8_t caset[] = {0x00, 0x00, 0x00, (uint8_t)(width - 1)}; - transport_.SendData(caset, 4); - - transport_.SendCommand(0x2B); - uint8_t raset[] = {0x00, 0x00, 0x00, (uint8_t)(height - 1)}; - transport_.SendData(raset, 4); - - transport_.SendCommand(0x2C); - transport_.SendData(buffer_, sizeof(buffer_)); - } - - private: - Transport transport_; - uint8_t buffer_[width * height * 2]; - - // Theme colors - uint16_t foreground_color_; - uint16_t background_color_; - uint16_t accent_color_; -}; - -// Pre-defined driver types -using ST7735_4WireSpi128x160Driver = ST7735Driver<128, 160, ST7735_4WireSpiTransport>; -using ST7735_4WireSpi128x128Driver = ST7735Driver<128, 128, ST7735_4WireSpiTransport>; -using ST7735_4WireSpi80x160Driver = ST7735Driver<80, 160, ST7735_4WireSpiTransport>; -using ST7735_4WireSpi128x64Driver = ST7735Driver<128, 64, ST7735_4WireSpiTransport>; - -} // namespace daisy - -#endif // DSY_ST7735_H From 370872338398286374bedd603b820d935f07d464 Mon Sep 17 00:00:00 2001 From: noisehoho Date: Wed, 10 Dec 2025 16:43:59 +0800 Subject: [PATCH 8/9] Delete source/seed.st7735_80x160.json --- source/seed.st7735_80x160.json | 43 ---------------------------------- 1 file changed, 43 deletions(-) delete mode 100644 source/seed.st7735_80x160.json diff --git a/source/seed.st7735_80x160.json b/source/seed.st7735_80x160.json deleted file mode 100644 index 6dcbd28..0000000 --- a/source/seed.st7735_80x160.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "seed_st7735_80x160", - "max_apps": 8, - "defines": { - "OOPSY_TARGET_HAS_OLED": 1, - "OOPSY_TARGET_ST7735": 1, - "OOPSY_OLED_DISPLAY_WIDTH": 80, - "OOPSY_OLED_DISPLAY_HEIGHT": 160 - }, - "display": { - "driver": "daisy::ST7735_4WireSpi80x160Driver", - "dim": [80, 160], - "config": [] - }, - "inserts": [], - "components": { - "knob1": { "component": "AnalogControl", "pin": 15 }, - "knob2": { "component": "AnalogControl", "pin": 16 }, - "knob3": { "component": "AnalogControl", "pin": 21 }, - "knob4": { "component": "AnalogControl", "pin": 18 }, - "encoder": { - "component": "Encoder", - "pin": {"a": 12, "b": 11, "click": 0}, - "meta": [ - "menu_hold = ${name}.TimeHeldMs();", - "menu_click = ${name}.FallingEdge();", - "menu_rotate = ${name}.Increment();" - ] - }, - "gate1": { "component": "GateIn", "pin": 20 }, - "gate2": { "component": "GateIn", "pin": 19 } - }, - "labels": { - "params": { - "knob1": "knob1", "knob2": "knob2", "knob3": "knob3", "knob4": "knob4", - "cv1": "knob1", "cv2": "knob2", "cv3": "knob3", "cv4": "knob4", - "gate1": "gate1", "gate2": "gate2", "gate": "gate1" - }, - "outs": {}, - "datas": {} - }, - "aliases": {} -} From 13184063ab1a20e284a24f9cb743597950a98b49 Mon Sep 17 00:00:00 2001 From: noisehoho Date: Wed, 10 Dec 2025 16:44:15 +0800 Subject: [PATCH 9/9] Delete source/seed.st7735_128x64.json --- source/seed.st7735_128x64.json | 43 ---------------------------------- 1 file changed, 43 deletions(-) delete mode 100644 source/seed.st7735_128x64.json diff --git a/source/seed.st7735_128x64.json b/source/seed.st7735_128x64.json deleted file mode 100644 index f34c36b..0000000 --- a/source/seed.st7735_128x64.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "seed_st7735_128x64", - "max_apps": 8, - "defines": { - "OOPSY_TARGET_HAS_OLED": 1, - "OOPSY_TARGET_ST7735": 1, - "OOPSY_OLED_DISPLAY_WIDTH": 128, - "OOPSY_OLED_DISPLAY_HEIGHT": 64 - }, - "display": { - "driver": "daisy::ST7735_4WireSpi128x64Driver", - "dim": [128, 64], - "config": [] - }, - "inserts": [], - "components": { - "knob1": { "component": "AnalogControl", "pin": 15 }, - "knob2": { "component": "AnalogControl", "pin": 16 }, - "knob3": { "component": "AnalogControl", "pin": 21 }, - "knob4": { "component": "AnalogControl", "pin": 18 }, - "encoder": { - "component": "Encoder", - "pin": {"a": 12, "b": 11, "click": 0}, - "meta": [ - "menu_hold = ${name}.TimeHeldMs();", - "menu_click = ${name}.FallingEdge();", - "menu_rotate = ${name}.Increment();" - ] - }, - "gate1": { "component": "GateIn", "pin": 20 }, - "gate2": { "component": "GateIn", "pin": 19 } - }, - "labels": { - "params": { - "knob1": "knob1", "knob2": "knob2", "knob3": "knob3", "knob4": "knob4", - "cv1": "knob1", "cv2": "knob2", "cv3": "knob3", "cv4": "knob4", - "gate1": "gate1", "gate2": "gate2", "gate": "gate1" - }, - "outs": {}, - "datas": {} - }, - "aliases": {} -}