diff --git a/README.md b/README.md index 6f90b07..9ae9160 100644 --- a/README.md +++ b/README.md @@ -7,33 +7,90 @@ A modular embedded application for RP2350 microcontrollers featuring display, to - **Display Abstraction Layer** - Support for multiple display types (ST7796, ST7789, E-Paper) - **Touch Abstraction Layer** - Extensible touch controller support (FT6336U) - **SD Card with FatFS** - File system support with board-aware initialization -- **Multi-Board Support** - Automatic pin configuration for different RP2350 boards +- **Multi-Board Support** - Single-file board configuration system for easy board switching - **1-bit Rendering** - Memory-efficient monochrome graphics with GUI widgets -- **Board Configuration** - Single configuration file for all hardware settings +- **Automated Build Scripts** - Build for one board or all boards with single commands +- **Hardware Abstraction** - Factory pattern for displays and touch controllers -## Supported Hardware +## Supported Hardware Configurations -### Boards -1. **Adafruit Feather RP2350** (default) -2. **Raspberry Pi Pico 2** -3. **Raspberry Pi Pico 2 W** +### Available Board Configurations -### Displays -- ST7796 (480x320 TFT LCD) - Fully implemented -- ST7789 - Ready for driver implementation -- E-Paper - Ready for driver implementation +1. **BOARD_FEATHER_TFT** - Adafruit Feather RP2350 with 4.0" TFT ST7796 + - Display: ST7796 (480x320 RGB TFT) + - Touch: FT6336U capacitive touch + - Features: High-speed refresh, backlight control, SD card support -### Touch Controllers -- FT6336U (I2C capacitive touch) - Fully implemented -- Extensible for additional controllers +2. **BOARD_PICO2_TFT** - Raspberry Pi Pico 2 with 4.0" TFT ST7796 + - Display: ST7796 (480x320 RGB TFT) + - Touch: FT6336U capacitive touch + - Features: High-speed refresh, backlight control, SD card support -### Storage -- SD Card via SPI with FatFS file system +3. **BOARD_PICO2_EINK** - Raspberry Pi Pico 2 with E-Ink Display + - Display: E-Paper (400x300 monochrome) + - Touch: None (uses hardware buttons KEY0/KEY1) + - Features: Ultra-low power, partial/full refresh modes -## Quick Start +### Supported Displays +- **ST7796** - 480x320 RGB TFT LCD (Fully implemented) +- **E-Paper** - Various sizes, monochrome (Fully implemented) +- **ST7789** - Ready for driver implementation -### Building for Default Board (Feather RP2350) +### Supported Touch Controllers +- **FT6336U** - I2C capacitive touch with gesture support (Fully implemented) +- Extensible architecture for additional controllers +## Board Configuration System + +### Switching Between Boards + +The project uses a single-file configuration system. To switch boards, simply edit `board_config.h` and uncomment your target board: + +```cpp +// ---- SELECT YOUR BOARD HERE ---- +// #define BOARD_FEATHER_TFT // Feather RP2350 + 4.0" TFT ST7796 +// #define BOARD_PICO2_TFT // Pico 2 + 4.0" TFT ST7796 +#define BOARD_PICO2_EINK // Pico 2 + E-Ink Display +// -------------------------------- +``` + +**Important:** Only one board should be uncommented at a time! + +### What Gets Configured + +Each board configuration includes: +- Display type and resolution +- All pin assignments (SPI, I2C, GPIO) +- Touch controller configuration +- Coordinate transformation (rotation/inversion) +- SD card pins +- Hardware button pins (e-ink boards) +- Communication speeds (SPI/I2C baud rates) + +### Board-Specific Files + +Board configurations are located in `board_configs/`: +- `board_feather_tft.h` - Feather RP2350 + TFT configuration +- `board_pico2_tft.h` - Pico 2 + TFT configuration +- `board_pico2_eink.h` - Pico 2 + E-Ink configuration + +## Building and Flashing + +### Method 1: Build for Currently Selected Board + +The simplest method - builds for whatever board is selected in `board_config.h`: + +```bash +./build_and_flash.sh +``` + +This script will: +1. Detect which board is selected in `board_config.h` +2. Configure CMake if needed +3. Build the project using Ninja +4. Flash to the board using picotool (if board is in BOOTSEL mode) + +To build without flashing: ```bash mkdir -p build cd build @@ -41,35 +98,50 @@ cmake -G Ninja .. ninja ``` -### Building for Specific Board +The output file will be `build/basic1.uf2`. -```bash -cmake -G Ninja -DPICO_BOARD=pico2 .. -ninja -``` +### Method 2: Build for All Boards -Available boards: `adafruit_feather_rp2350`, `pico2`, `pico2_w` - -### Building for All Boards +To create UF2 files for all supported boards in one command: ```bash ./build_all_boards.sh ``` -Generates: -- `basic1_adafruit_feather_rp2350.uf2` -- `basic1_pico2.uf2` -- `basic1_pico2_w.uf2` +This script will: +1. Backup your current `board_config.h` +2. Build each board configuration automatically +3. Generate board-specific output files: + - `basic1_feather_tft.uf2` + - `basic1_pico2_tft.uf2` + - `basic1_pico2_eink.uf2` +4. Restore your original `board_config.h` -### Flashing +This is useful for: +- Creating releases for multiple hardware variants +- Testing code on all board configurations +- Batch building without manual configuration changes -1. Hold BOOTSEL button while connecting USB -2. Copy the `.uf2` file to the mounted drive -3. Device will automatically reboot and run +### Manual Flashing + +1. Hold the **BOOTSEL** button while connecting USB +2. The board appears as a USB drive (e.g., `RPI-RP2`) +3. Copy the appropriate `.uf2` file to the drive: + ```bash + cp basic1.uf2 /Volumes/RPI-RP2/ + ``` +4. The board automatically reboots and runs the program + +### Using picotool + +If picotool is installed at `~/.pico-sdk/picotool/`: -Or use the flash script: ```bash -./build_and_flash.sh +# Load and auto-reboot +picotool load build/basic1.uf2 -fx + +# Or load without auto-reboot +picotool load build/basic1.uf2 ``` ## Project Structure @@ -77,78 +149,128 @@ Or use the flash script: ``` basic1/ ├── basic1.cpp # Main application -├── board_config.h # Board-specific pin configuration -├── CMakeLists.txt # Build configuration -├── build_all_boards.sh # Multi-board build script -├── build_and_flash.sh # Build and flash helper +├── board_config.h # Board selector (edit this to switch boards!) +├── board_configs/ # Board-specific configurations +│ ├── board_feather_tft.h # Feather RP2350 + TFT pin config +│ ├── board_pico2_tft.h # Pico 2 + TFT pin config +│ ├── board_pico2_eink.h # Pico 2 + E-Ink pin config +│ └── README.md # Board config documentation │ -├── display/ # Display and GUI abstraction -│ ├── low_level_display.h # Display interface -│ ├── low_level_display_*.cpp # Display implementations -│ ├── low_level_touch.h # Touch interface -│ ├── low_level_touch_*.cpp # Touch implementations +├── CMakeLists.txt # Build configuration +├── build_all_boards.sh # Build all boards automatically +├── build_and_flash.sh # Build and flash current board +│ +├── display/ # Display and GUI abstraction layer +│ ├── low_level_display.h # Display interface (factory pattern) +│ ├── low_level_display_st7796.cpp # ST7796 TFT implementation +│ ├── low_level_display_epaper.cpp # E-Paper implementation +│ ├── low_level_touch.h # Touch interface (factory pattern) +│ ├── low_level_touch_ft6336u.cpp # FT6336U touch implementation │ ├── low_level_render.h/cpp # 1-bit rendering engine -│ └── low_level_gui.h/cpp # GUI widgets +│ └── low_level_gui.h/cpp # GUI widgets (buttons, gauges, etc.) │ ├── lib/ # Hardware drivers -│ ├── ft6336u/ # FT6336U touch driver -│ ├── st7796/ # ST7796 display driver +│ ├── ft6336u/ # FT6336U capacitive touch driver +│ ├── st7796/ # ST7796 TFT display driver +│ ├── epaper/ # E-Paper display driver │ ├── sd_card/ # SD card driver with FatFS test │ └── fatfs/ # FatFS filesystem │ -├── fonts/ # Bitmap font definitions -└── fatfs_time.c # FatFS timestamp (uses compile time) +├── fonts/ # 25+ bitmap font definitions (5x5 to 8x8) +└── fatfs_time.c # FatFS timestamp support ``` -## Configuration +## Adding a New Board Configuration -### Board Configuration (`board_config.h`) +1. Create a new config file in `board_configs/`: + ```bash + cp board_configs/board_pico2_tft.h board_configs/board_myboard.h + ``` -All hardware settings are defined per board: +2. Edit the new file and update all pin definitions for your hardware -```c -// Display configuration -#define DISPLAY_WIDTH 480 -#define DISPLAY_HEIGHT 320 -#define DISPLAY_TYPE_SELECTED 0 // DISPLAY_TYPE_ST7796 +3. Add your board to `board_config.h`: + ```cpp + // ---- SELECT YOUR BOARD HERE ---- + // #define BOARD_FEATHER_TFT + // #define BOARD_PICO2_TFT + // #define BOARD_PICO2_EINK + #define BOARD_MYBOARD // Your new board + // -------------------------------- + ``` -// Touch configuration -#define TOUCH_TYPE_SELECTED 0 // TOUCH_TYPE_FT6336U -#define TOUCH_SWAP_XY true -#define TOUCH_INVERT_X true -#define TOUCH_INVERT_Y false +4. Add the include section: + ```cpp + #ifdef BOARD_FEATHER_TFT + #include "board_configs/board_feather_tft.h" + // ... other boards ... + #elif defined(BOARD_MYBOARD) + #include "board_configs/board_myboard.h" + #endif + ``` -// SPI pins for display -#define DISPLAY_SPI_PORT spi1 -#define DISPLAY_SCK_PIN 18 -#define DISPLAY_MOSI_PIN 19 -#define DISPLAY_MISO_PIN 20 -#define DISPLAY_CS_PIN 17 -// ... more pins -``` +5. (Optional) Add to `build_all_boards.sh` for automated builds -### Changing Display Type +See `board_configs/README.md` for detailed configuration structure. -Modify `DISPLAY_TYPE_SELECTED` in `board_config.h`: -- `0` = ST7796 (480x320 TFT) -- `1` = ST7789 -- `2` = E-Paper +## Hardware Configuration Details -### Changing Touch Type +### Display Types -Modify `TOUCH_TYPE_SELECTED` in `board_config.h`: -- `0` = FT6336U -- `1` = None (disable touch) +Each board configuration specifies a display type via `DISPLAY_TYPE_SELECTED`: +- `DISPLAY_TYPE_ST7796_VAL` (0) - ST7796 TFT (480x320) +- `DISPLAY_TYPE_ST7789_VAL` (1) - ST7789 TFT (ready for implementation) +- `DISPLAY_TYPE_EPAPER_VAL` (2) - E-Paper displays (various sizes) + +### Touch Controller Types + +Each board configuration specifies a touch type via `TOUCH_TYPE_SELECTED`: +- `TOUCH_TYPE_FT6336U_VAL` (0) - FT6336U capacitive touch with gesture support +- `TOUCH_TYPE_NONE_VAL` (1) - No touch controller (use hardware buttons) ### Touch Coordinate Transformation -Adjust orientation in `board_config.h`: +Touch coordinates can be adjusted for different mounting orientations: ```c -#define TOUCH_SWAP_XY true // Swap X/Y coordinates -#define TOUCH_INVERT_X true // Invert X axis -#define TOUCH_INVERT_Y false // Invert Y axis +#define TOUCH_SWAP_XY true // Swap X/Y coordinates (for 90° rotation) +#define TOUCH_INVERT_X true // Invert X axis (mirror horizontally) +#define TOUCH_INVERT_Y false // Invert Y axis (mirror vertically) ``` +These settings are in each board's config file under `board_configs/`. + +### Pin Assignments + +Each board config file defines all hardware pin connections: + +**Display Pins:** +- `DISPLAY_SPI_PORT` - SPI bus (spi0 or spi1) +- `DISPLAY_SCK_PIN`, `DISPLAY_MOSI_PIN`, `DISPLAY_MISO_PIN` - SPI data lines +- `DISPLAY_CS_PIN` - Chip select (active LOW) +- `DISPLAY_DC_PIN` - Data/Command select +- `DISPLAY_RST_PIN` - Hardware reset +- `DISPLAY_BL_PIN` - Backlight control (TFT only, -1 for e-ink) +- `DISPLAY_BUSY_PIN` - Busy signal (E-Paper only, -1 for TFT) + +**Touch Pins:** +- `TOUCH_I2C_PORT` - I2C bus (i2c0 or i2c1) +- `TOUCH_SDA_PIN`, `TOUCH_SCL_PIN` - I2C data lines +- `TOUCH_INT_PIN` - Interrupt pin (active LOW when touch detected) +- `TOUCH_RST_PIN` - Hardware reset + +**Button Pins (E-Ink boards):** +- `BUTTON_KEY0_PIN` - First hardware button (active LOW) +- `BUTTON_KEY1_PIN` - Second hardware button (active LOW) + +**SD Card Pins (optional):** +- `SD_SPI_PORT`, `SD_CS_PIN`, `SD_MISO_PIN`, `SD_MOSI_PIN`, `SD_SCK_PIN` + +### Communication Speeds + +Configured per board based on display type: +- `SPI_BAUDRATE` - Display SPI speed (32MHz for TFT, 4MHz for e-ink) +- `I2C_BAUDRATE` - Touch controller I2C speed (typically 400kHz) + ## Architecture ### Display Abstraction Layer @@ -226,92 +348,182 @@ The test function: - Creates and reads test file - Safely unmounts filesystem -## Pin Configurations +## Pin Configurations Summary -### Adafruit Feather RP2350 -- **Display (SPI1):** SCK=18, MOSI=19, MISO=20, CS=17, DC=16, RST=15, BL=14 -- **Touch (I2C0):** SDA=4, SCL=5, INT=6, RST=7 +Actual pin assignments are defined in `board_configs/*.h` files. Here's a quick reference: + +### BOARD_FEATHER_TFT (Adafruit Feather RP2350) +- **Display (ST7796, SPI1):** SCK=18, MOSI=19, MISO=20, CS=17, DC=16, RST=15, BL=14 +- **Touch (FT6336U, I2C0):** SDA=4, SCL=5, INT=6, RST=7 - **SD Card (SPI1):** CS=10 (shares SPI with display) -### Raspberry Pi Pico 2 / Pico 2 W -- **Display (SPI0):** SCK=2, MOSI=3, MISO=4, CS=5, DC=6, RST=7, BL=8 -- **Touch (I2C0):** SDA=12, SCL=13, INT=14, RST=15 +### BOARD_PICO2_TFT (Raspberry Pi Pico 2) +- **Display (ST7796, SPI0):** SCK=2, MOSI=3, MISO=4, CS=5, DC=6, RST=7, BL=8 +- **Touch (FT6336U, I2C0):** SDA=12, SCL=13, INT=14, RST=15 - **SD Card (SPI1):** CS=17 -## Adding New Hardware +### BOARD_PICO2_EINK (Raspberry Pi Pico 2 + E-Ink) +- **Display (E-Paper, SPI0):** SCK=10, MOSI=11, MISO=12, CS=9, DC=8, RST=12, BUSY=13 +- **Touch:** None (uses hardware buttons instead) +- **Buttons:** KEY0=GP15 (active LOW), KEY1=GP17 (active LOW) + +See individual board config files in `board_configs/` for complete details. + +## Extending the System ### Adding a New Display Driver 1. Create implementation files: - ```cpp - display/low_level_display_mydriver.h - display/low_level_display_mydriver.cpp + ``` + display/low_level_display_mynewdisplay.h + display/low_level_display_mynewdisplay.cpp ``` -2. Implement the `LowLevelDisplay` interface +2. Inherit from `LowLevelDisplay` base class and implement all virtual methods -3. Add to factory in `low_level_display_factory.cpp`: +3. Add a new constant in `board_config.h`: ```cpp - case DISPLAY_TYPE_MYDRIVER: - display = new LowLevelDisplayMyDriver(width, height); + #define DISPLAY_TYPE_MYNEWDISPLAY_VAL 3 + ``` + +4. Update the factory in `display/low_level_display.cpp`: + ```cpp + case 3: // DISPLAY_TYPE_MYNEWDISPLAY + display = new LowLevelDisplayMyNewDisplay(width, height); break; ``` -4. Update `CMakeLists.txt` to include new files +5. Update `CMakeLists.txt` to compile the new files ### Adding a New Touch Controller 1. Create implementation files: - ```cpp - display/low_level_touch_mydriver.h - display/low_level_touch_mydriver.cpp + ``` + display/low_level_touch_mynewtouch.h + display/low_level_touch_mynewtouch.cpp ``` -2. Implement the `LowLevelTouch` interface +2. Inherit from `LowLevelTouch` base class -3. Add to factory in `low_level_touch_factory.cpp` +3. Add constant and factory case similar to display drivers -4. Update `CMakeLists.txt` +4. Update CMakeLists.txt -### Adding a New Board +### Workflow Summary -Edit `board_config.h`: +The typical development workflow: -```c -#elif defined(PICO_BOARD_MY_CUSTOM_BOARD) - #define BOARD_NAME "My Custom Board" - - // Display configuration - #define DISPLAY_WIDTH 480 - #define DISPLAY_HEIGHT 320 - #define DISPLAY_TYPE_SELECTED 0 - - // Touch configuration - #define TOUCH_TYPE_SELECTED 0 - // ... define all pins -#endif -``` +1. **Select target board:** Edit `board_config.h`, uncomment your board +2. **Build:** Run `./build_and_flash.sh` (builds and flashes current board) +3. **Test:** Connect to USB, monitor via serial terminal +4. **Switch boards:** Edit `board_config.h`, rebuild +5. **Release:** Run `./build_all_boards.sh` to create UF2s for all boards ## Memory Usage -- **1-bit framebuffer:** 480×320÷8 = 19.2 KB -- **Display conversion:** Automatic 1-bit → RGB565/monochrome +- **1-bit framebuffer:** Width×Height÷8 bytes + - 480×320: 19.2 KB + - 400×300: 15.0 KB +- **Display conversion:** Automatic 1-bit → RGB565 (TFT) or native (E-Paper) - **Stack/heap:** Minimal, uses static buffers where possible +- **Code size:** ~100-150 KB depending on features enabled -## Known Issues & Troubleshooting +## Troubleshooting -### Touch Not Working -- **I2C Communication Failure:** Check wiring, pull-up resistors, I2C address -- **Wrong Coordinates:** Adjust `TOUCH_SWAP_XY`, `TOUCH_INVERT_X/Y` settings +### Build Issues -### SD Card Not Detected -- **CMD0 Returns 0x00:** Check card insertion, CS pin, SPI wiring -- **Mount Fails:** Ensure card is formatted as FAT/FAT32 +**Error: "No board selected!"** +- You must uncomment exactly one `BOARD_xxx` define in `board_config.h` -### Display Shows Nothing -- Check SPI wiring and CS/DC/RST pins -- Verify backlight is connected and enabled -- Check voltage levels (3.3V logic) +**CMake configuration errors:** +- Delete `build/` directory and reconfigure: `rm -rf build && mkdir build` + +### Display Issues + +**Display stays blank:** +- Check SPI wiring (especially CS, DC, SCK, MOSI pins) +- Verify power supply (some displays need 5V logic level shifters) +- Check `DISPLAY_TYPE_SELECTED` matches your hardware + +**Wrong colors or garbled display:** +- Verify display driver type (ST7796 vs ST7789) +- Check SPI baud rate (try reducing from 32MHz to 16MHz) + +### Touch Issues + +**Touch not responding:** +- Verify I2C wiring (SDA, SCL, INT, RST pins) +- Check for pull-up resistors on I2C lines (typically 4.7kΩ) +- Confirm touch controller type and I2C address +- Enable debug output to see if touch data is being read + +**Touch coordinates inverted or swapped:** +- Adjust `TOUCH_SWAP_XY`, `TOUCH_INVERT_X`, `TOUCH_INVERT_Y` in board config +- These depend on physical mounting orientation + +**Interrupt not triggering:** +- Verify `TOUCH_INT_PIN` is correctly defined +- Check INT pin is pulled high (internal pull-up or external resistor) +- Confirm touch controller is configured for interrupt mode + +### SD Card Issues + +**SD Card not detected:** +- Verify card is inserted and formatted (FAT32) +- Check SPI wiring and CS pin +- Ensure SD card shares SPI correctly with display (different CS pins) +- Try different SD card (some old/large cards have compatibility issues) + +### E-Paper Display Issues + +**Ghosting or partial images:** +- Use `full_refresh()` periodically to clear ghosting +- E-Paper retains previous image until fully refreshed + +**Slow refresh:** +- Normal for e-paper (several seconds for full refresh) +- Use partial refresh for faster updates (may cause ghosting) + +**BUSY pin timeout:** +- Verify `DISPLAY_BUSY_PIN` is correctly connected +- Increase timeout in e-paper driver if needed + +## Development Tips + +### Serial Debugging + +Connect via USB and monitor serial output: +```bash +# macOS +screen /dev/tty.usbmodem* 115200 + +# Linux +screen /dev/ttyACM0 115200 + +# Exit screen: Ctrl+A, then K +``` + +The code includes `printf()` statements for debugging touch, display, and SD card operations. + +### Power Optimization + +For battery-powered projects: +- E-Paper displays use almost no power when idle +- Use `__wfi()` (Wait For Interrupt) to sleep between inputs +- Disable TFT backlight when idle +- Lower SPI/I2C baud rates to reduce power consumption + +### Performance Tips + +**TFT Displays:** +- Increase SPI baud rate up to 62.5MHz if display supports it +- Minimize full-screen refreshes (use partial updates if possible) +- 1-bit rendering is much faster than RGB565 + +**E-Paper Displays:** +- Use partial refresh for responsive UI (accepts some ghosting) +- Full refresh only when needed (menu changes, game over, etc.) +- Consider caching frequently used graphics ## Features by Component