diff --git a/GUITION_SETUP.md b/GUITION_SETUP.md new file mode 100644 index 00000000..b47b0ac7 --- /dev/null +++ b/GUITION_SETUP.md @@ -0,0 +1,189 @@ +# Guition JC4827W543C Board Setup Guide + +This guide explains how to configure and build squeezelite-esp32 for the Guition JC4827W543C development board. + +## Board Features + +- **Processor**: ESP32-S3-WROOM-1 (dual-core, 240MHz) +- **Display**: 4.3" ILI9488 LCD (480x272 pixels) +- **Touch**: GT911 capacitive touch controller +- **Interface**: QSPI display interface +- **Memory**: 4MB Flash, 4MB PSRAM +- **Connectivity**: WiFi, Bluetooth + +## Hardware Configuration + +### Display Connections (QSPI) +- **CLK**: GPIO47 +- **DATA0**: GPIO21 +- **DATA1**: GPIO48 +- **DATA2**: GPIO40 +- **DATA3**: GPIO39 +- **CS**: GPIO45 +- **DC**: Not used with QSPI +- **RST**: GPIO38 (if available) + +### I2C Connections (Touch) +- **SDA**: GPIO8 +- **SCL**: GPIO4 +- **Touch INT**: GPIO3 +- **Touch RST**: GPIO38 + +### Audio I2S (External DAC Required) +- **BCK**: GPIO15 +- **WS**: GPIO16 +- **DO**: GPIO17 +- **DI**: (not used for output only) + +### Other GPIO +- **Backlight**: GPIO1 (PWM controlled) + +## Software Configuration + +### 1. Build Configuration + +Use the provided build script: + +```bash +# Make the script executable +chmod +x build-guition.sh + +# Configure and build +./build-guition.sh +``` + +Or manually: + +```bash +# Set ESP32-S3 target +export IDF_TARGET=esp32s3 + +# Copy Guition configuration +cp squeezelite-esp32-Guition-sdkconfig.defaults sdkconfig.defaults + +# Configure project +idf.py menuconfig + +# Build +idf.py build +``` + +### 2. Menuconfig Settings + +In `idf.py menuconfig`, select: + +**Target Configuration**: +- `Squeezelite-ESP32` → `Guition JC4827W543C` + +**Audio Settings**: +- Configure I2S GPIO pins for your external DAC +- Default: BCK=15, WS=16, DO=17 + +**Display Settings**: +- Should be automatically configured as: + - Type: QSPI + - Driver: ILI9488 + - Width: 480 + - Height: 272 + - CS: 45 + - Speed: 20MHz + +**I2C Settings**: +- SDA: 8 +- SCL: 4 +- Speed: 400kHz +- Port: 0 + +### 3. External Audio DAC + +The Guition board does not have a built-in audio DAC. You must connect an external I2S DAC such as: + +- PCM5102 +- TAS575x series +- ES8388 +- AC101 + +Connect the DAC to the I2S pins and configure it in the NVS settings or through the web UI. + +## Flashing the Firmware + +```bash +# Flash to the board +idf.py -p /dev/ttyUSB0 flash + +# Monitor output (optional) +idf.py -p /dev/ttyUSB0 monitor +``` + +## First Boot Configuration + +1. Connect to the WiFi AP created by the device (SSID: SqueezeESP32-XXXXXX) +2. Open the web configuration interface +3. Configure your WiFi network +4. Set up your audio DAC if needed +5. Configure LMS server connection + +## Display Features + +The ILI9488 driver supports: +- 16-bit RGB565 color +- Hardware acceleration +- Shadow buffering for performance +- Automatic dirty region tracking +- Rotation and flip options + +## Touch Support + +Touch functionality is planned but not yet implemented. The GT911 touch controller is connected via I2C. + +## Troubleshooting + +### Display Not Working +- Check QSPI GPIO connections +- Verify CS pin is correctly set to GPIO45 +- Ensure proper power supply (3.3V for display logic) + +### Audio Not Working +- Verify external DAC is properly connected +- Check I2S GPIO assignments +- Configure DAC model in web UI if using a supported DAC + +### Build Issues +- Ensure ESP-IDF supports ESP32-S3 +- Check that all required components are included +- Verify GPIO pin assignments don't conflict + +## Performance Notes + +- The 480x272 display requires significant memory bandwidth +- PSRAM is used for display framebuffer (≈260KB) +- Audio performance may be affected at high display refresh rates +- Consider reducing display update rate if audio issues occur + +## GPIO Map Summary + +| GPIO | Function | Direction | +|------|----------|-----------| +| 1 | Backlight PWM | Out | +| 3 | Touch INT | In | +| 4 | I2C SCL | Out | +| 8 | I2C SDA | I/O | +| 15 | I2S BCK | Out | +| 16 | I2S WS | Out | +| 17 | I2S DO | Out | +| 21 | QSPI DATA0 | Out | +| 39 | QSPI DATA3 | Out | +| 40 | QSPI DATA2 | Out | +| 45 | QSPI CS | Out | +| 47 | QSPI CLK | Out | +| 48 | QSPI DATA1 | Out | +| 38 | Touch RST | Out | + +## Support + +For issues specific to the Guition board implementation: +1. Check this README first +2. Review the squeezelite-esp32 documentation +3. Open an issue on the GitHub repository + +For general squeezelite-esp32 questions, refer to the main project documentation and forums. diff --git a/WINDOWS_BUILD_GUIDE.md b/WINDOWS_BUILD_GUIDE.md new file mode 100644 index 00000000..f673d31c --- /dev/null +++ b/WINDOWS_BUILD_GUIDE.md @@ -0,0 +1,216 @@ +# Windows Build Guide for Guition JC4827W543C + +This guide explains how to build squeezelite-esp32 for the Guition board on Windows. + +## Prerequisites + +1. **ESP-IDF for Windows** + - Download and install ESP-IDF from: https://dl.espressif.com/dl/esp-idf/ + - Run the installer and follow the setup instructions + - Make sure to install the required tools (Git, Python, CMake) + +2. **Visual Studio Build Tools** (if not already installed by ESP-IDF) + - Install from Visual Studio Installer + - Select "C++ build tools" + +3. **Hardware** + - Guition JC4827W543C board + - USB cable for power and programming + - External I2S audio DAC (required) + +## Setup Instructions + +### 1. Install ESP-IDF +```cmd +# Run the ESP-IDF installer +# Launch ESP-IDF Command Prompt from Start Menu +``` + +### 2. Initialize ESP-IDF Environment +```cmd +# In ESP-IDF Command Prompt +cd C:\Espressif\esp-idf +export.bat +``` + +### 3. Clone and Setup Project +```cmd +# Navigate to your workspace +cd C:\Users\YourName\Projects + +# Clone the repository (if not already done) +git clone squeezelite-esp32-gronod +cd squeezelite-esp32-gronod +``` + +### 4. Set Environment for Project +```cmd +# Set ESP-IDF environment for this project +C:\Espressif\esp-idf\export.bat +``` + +## Build Methods + +### Method 1: PowerShell Script (Recommended) +```powershell +# Open PowerShell as Administrator +# Navigate to project directory +cd C:\Users\YourName\Projects\squeezelite-esp32-gronod + +# Run the build script +.\build-guition.ps1 + +# For clean build +.\build-guition.ps1 -Clean +``` + +**Note:** If you get execution policy errors, run: +```powershell +Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser +``` + +### Method 2: Batch File (Simple) +```cmd +# Open Command Prompt +# Navigate to project directory +cd C:\Users\YourName\Projects\squeezelite-esp32-gronod + +# Run the build script +build-guition.bat + +# For clean build +build-guition.bat clean +``` + +### Method 3: Manual Commands +```cmd +# Set ESP-IDF environment +C:\Espressif\esp-idf\export.bat + +# Set target +set IDF_TARGET=esp32s3 + +# Copy Guition config +copy /Y squeezelite-esp32-Guition-sdkconfig.defaults sdkconfig.defaults + +# Configure (opens menu interface) +idf.py menuconfig + +# Build +idf.py build +``` + +## Menuconfig Configuration + +When `idf.py menuconfig` runs: + +1. **Select Target Hardware**: + - Navigate to: `Squeezelite-ESP32` → `Guition JC4827W543C` + +2. **Configure Audio** (if needed): + - Navigate to: `Audio settings` → `DAC settings` + - Set I2S GPIO pins for your external DAC + - Default: BCK=15, WS=16, DO=17 + +3. **Save and Exit**: + - Press `S` to save + - Press `Q` to exit + +## Flashing the Firmware + +### Find Your COM Port +```cmd +# List all COM ports +mode + +# Or check Device Manager under "Ports (COM & LPT)" +``` + +### Flash and Monitor +```cmd +# Flash firmware +idf.py -p COM3 flash + +# Flash and monitor (recommended) +idf.py -p COM3 flash monitor + +# Just monitor (if already flashed) +idf.py -p COM3 monitor +``` + +### Using the Scripts +Both PowerShell and batch scripts will ask if you want to flash after building. + +## Troubleshooting + +### Common Issues + +1. **"ESP-IDF environment not found"** + - Make sure you're running from ESP-IDF Command Prompt + - Or run `C:\Espressif\esp-idf\export.bat` first + +2. **"Python not found"** + - ESP-IDF installer should include Python + - Check that Python is in your PATH + +3. **"Build tools not found"** + - Install Visual Studio Build Tools + - Make sure C++ tools are selected + +4. **"Permission denied" (PowerShell)** + - Run PowerShell as Administrator + - Or set execution policy: `Set-ExecutionPolicy RemoteSigned` + +5. **"COM port not found"** + - Check device connections + - Install USB drivers if needed (CH340/CP210x) + - Check Device Manager + +### Clean Build +If you encounter build issues: +```cmd +# Using batch file +build-guition.bat clean + +# Or manually +idf.py fullclean +idf.py build +``` + +### Verifying Installation +```cmd +# Check ESP-IDF version +idf.py --version + +# Check target +echo %IDF_TARGET% + +# List available targets +idf.py --help | findstr target +``` + +## Development Workflow + +1. **Initial Setup**: Run the build script once to configure +2. **Code Changes**: Make your modifications +3. **Build**: Run `.\build-guition.ps1` or `build-guition.bat` +4. **Flash**: Let the script flash automatically, or use `idf.py -p COMX flash` +5. **Monitor**: Use `idf.py -p COMX monitor` to view logs + +## Performance Tips + +- **SSD Storage**: Build on SSD for much faster compilation +- **RAM**: 8GB+ recommended for large projects +- **CPU**: Multi-core CPU helps with parallel compilation +- **Antivirus**: Exclude project directory from real-time scanning + +## Next Steps + +After successful build and flash: + +1. Connect to WiFi AP created by device +2. Configure your network settings +3. Set up audio DAC configuration +4. Connect to your Logitech Media Server + +For more detailed configuration, see `GUITION_SETUP.md`. diff --git a/build-guition.bat b/build-guition.bat new file mode 100644 index 00000000..fe53eda6 --- /dev/null +++ b/build-guition.bat @@ -0,0 +1,80 @@ +@echo off +REM Build script for Guition JC4827W543C board - Batch file version +REM Usage: build-guition.bat [clean] + +echo Building Squeezelite-ESP32 for Guition JC4827W543C + +REM Check if ESP-IDF environment is set up +if "%IDF_PATH%"=="" ( + echo Error: ESP-IDF environment not found! + echo Please run esp-idf\export.bat first + pause + exit /b 1 +) + +REM Set target to ESP32-S3 +set IDF_TARGET=esp32s3 +echo Target set to: %IDF_TARGET% + +REM Copy Guition-specific configuration +if exist "squeezelite-esp32-Guition-sdkconfig.defaults" ( + echo Using Guition configuration... + copy /Y "squeezelite-esp32-Guition-sdkconfig.defaults" "sdkconfig.defaults" +) else ( + echo Warning: Guition configuration file not found +) + +REM Clean if requested +if /i "%1"=="clean" ( + echo Cleaning build... + idf.py fullclean + if errorlevel 1 ( + echo Clean failed! + pause + exit /b 1 + ) +) + +REM Configure the project +echo Configuring project... +echo Running: idf.py menuconfig +echo Select: Squeezelite-ESP32 -^> Guition JC4827W543C +echo. +echo Press any key to continue to menuconfig... +pause > nul + +idf.py menuconfig +if errorlevel 1 ( + echo Configuration failed! + pause + exit /b 1 +) + +REM Build the project +echo Building firmware... +idf.py build +if errorlevel 1 ( + echo Build failed! + pause + exit /b 1 +) + +echo Build complete! +echo Firmware location: build\squeezelite.bin +echo. +echo To flash the firmware: +echo idf.py -p ^ flash +echo. +echo To monitor output: +echo idf.py -p ^ monitor + +REM Ask if user wants to flash +echo. +set /p flash="Do you want to flash the firmware now? (y/n) " +if /i "%flash%"=="y" ( + set /p port="Enter COM port (e.g., COM3): " + echo Flashing to %port%... + idf.py -p %port% flash monitor +) + +pause diff --git a/build-guition.ps1 b/build-guition.ps1 new file mode 100644 index 00000000..ae0b3f85 --- /dev/null +++ b/build-guition.ps1 @@ -0,0 +1,76 @@ +# Build script for Guition JC4827W543C board - PowerShell version +# Usage: .\build-guition.ps1 [-Clean] + +param( + [switch]$Clean +) + +Write-Host "Building Squeezelite-ESP32 for Guition JC4827W543C" -ForegroundColor Green + +# Check if ESP-IDF environment is set up +if (-not $env:IDF_PATH) { + Write-Host "Error: ESP-IDF environment not found!" -ForegroundColor Red + Write-Host "Please run esp-idf/export.bat first" -ForegroundColor Yellow + exit 1 +} + +# Set target to ESP32-S3 +$env:IDF_TARGET = "esp32s3" +Write-Host "Target set to: $env:IDF_TARGET" -ForegroundColor Cyan + +# Copy Guition-specific configuration +if (Test-Path "squeezelite-esp32-Guition-sdkconfig.defaults") { + Write-Host "Using Guition configuration..." -ForegroundColor Cyan + Copy-Item "squeezelite-esp32-Guition-sdkconfig.defaults" "sdkconfig.defaults" -Force +} else { + Write-Host "Warning: Guition configuration file not found" -ForegroundColor Yellow +} + +# Clean if requested +if ($Clean) { + Write-Host "Cleaning build..." -ForegroundColor Cyan + idf.py fullclean + if ($LASTEXITCODE -ne 0) { + Write-Host "Clean failed!" -ForegroundColor Red + exit 1 + } +} + +# Configure the project +Write-Host "Configuring project..." -ForegroundColor Cyan +Write-Host "Running: idf.py menuconfig" -ForegroundColor White +Write-Host "Select: Squeezelite-ESP32 -> Guition JC4827W543C" -ForegroundColor Yellow +Write-Host "Press Enter to continue to menuconfig..." -ForegroundColor White +Read-Host + +idf.py menuconfig +if ($LASTEXITCODE -ne 0) { + Write-Host "Configuration failed!" -ForegroundColor Red + exit 1 +} + +# Build the project +Write-Host "Building firmware..." -ForegroundColor Cyan +idf.py build +if ($LASTEXITCODE -ne 0) { + Write-Host "Build failed!" -ForegroundColor Red + exit 1 +} + +Write-Host "Build complete!" -ForegroundColor Green +Write-Host "Firmware location: build\squeezelite.bin" -ForegroundColor Cyan +Write-Host "" +Write-Host "To flash the firmware:" -ForegroundColor White +Write-Host "idf.py -p flash" -ForegroundColor Yellow +Write-Host "" +Write-Host "To monitor output:" -ForegroundColor White +Write-Host "idf.py -p monitor" -ForegroundColor Yellow + +# Ask if user wants to flash +Write-Host "" +$flash = Read-Host "Do you want to flash the firmware now? (y/n)" +if ($flash -eq 'y' -or $flash -eq 'Y') { + $port = Read-Host "Enter COM port (e.g., COM3)" + Write-Host "Flashing to $port..." -ForegroundColor Cyan + idf.py -p $port flash monitor +} diff --git a/build-guition.sh b/build-guition.sh new file mode 100644 index 00000000..a522ed91 --- /dev/null +++ b/build-guition.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# Build script for Guition JC4827W543C board +# Usage: ./build-guition.sh [clean] + +set -e + +echo "Building Squeezelite-ESP32 for Guition JC4827W543C" + +# Set target to ESP32-S3 +export IDF_TARGET=esp32s3 + +# Copy Guition-specific configuration +if [ -f "squeezelite-esp32-Guition-sdkconfig.defaults" ]; then + echo "Using Guition configuration..." + cp squeezelite-esp32-Guition-sdkconfig.defaults sdkconfig.defaults +fi + +# Clean if requested +if [ "$1" == "clean" ]; then + echo "Cleaning build..." + idf.py fullclean +fi + +# Configure with Guition target +echo "Configuring project..." +idf.py menuconfig + +# Build the project +echo "Building firmware..." +idf.py build + +echo "Build complete!" +echo "Firmware location: build/squeezelite.bin" +echo "" +echo "To flash the firmware:" +echo "idf.py -p flash" +echo "" +echo "To monitor output:" +echo "idf.py -p monitor" diff --git a/components/display/ILI9488.c b/components/display/ILI9488.c new file mode 100644 index 00000000..31c5ec65 --- /dev/null +++ b/components/display/ILI9488.c @@ -0,0 +1,297 @@ +/** + * ILI9488 Display Driver for Guition JC4827W543C + * Supports QSPI interface for 480x272 resolution + * Based on ILI9341 driver adapted for ILI9488 + * + * (c) Guition Support 2026 + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include +#include +#include +#include +#include +#include + +#include "gds.h" +#include "gds_private.h" + +#define SHADOW_BUFFER +#define USE_IRAM +#define PAGE_BLOCK 4096 +#define ENABLE_WRITE 0x2c + +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +static char TAG[] = "ILI9488"; + +struct PrivateSpace { + uint8_t *iRAM, *Shadowbuffer; + struct { + uint16_t Height, Width; + } Offset; + uint8_t MADCtl, PageSize; + uint8_t Model; +}; + +// ILI9488 Commands +static const uint8_t ILI9488_INIT_SEQUENCE[] = { + // Software reset + 0x01, 0x80, 150, // SWRESET, delay 150ms + // Power control + 0xD0, 3, 0x07, 0x42, 0x18, // Power Control + 0xD1, 3, 0x00, 0x07, 0x10, // VCOM Control + 0xD2, 1, 0x01, // Power Control for Normal Mode + 0xC0, 2, 0x10, 0x3B, // Panel Driving Setting + 0xC1, 1, 0x10, // Frame Rate Control + 0xC5, 5, 0x0A, 0x3A, 0x28, 0x28, 0x02, // MCU Control + 0xC6, 1, 0x00, // Frame Rate Control + 0xB1, 2, 0x00, 0x1B, // Display Function Control + 0xB4, 1, 0x02, // Inversion Control + 0xB6, 3, 0x02, 0x02, 0x3B, // Display Function Control + 0xB7, 1, 0xC6, // Entry Mode Set + 0xE0, 16, 0x00, 0x07, 0x10, 0x0E, 0x09, 0x16, 0x06, 0x0A, + 0x0E, 0x09, 0x15, 0x0D, 0x0E, 0x11, 0x0F, 0x12, // Positive Gamma Control + 0xE1, 16, 0x00, 0x17, 0x1A, 0x04, 0x0E, 0x06, 0x2F, 0x24, + 0x1B, 0x1B, 0x22, 0x1F, 0x1E, 0x37, 0x3F, 0x00, // Negative Gamma Control + 0x36, 1, 0xE8, // Memory Access Control (MX, MY, RGB mode) + 0x3A, 1, 0x55, // Interface Pixel Format (16bpp) + 0x11, 0x80, 150, // Sleep Out, delay 150ms + 0x29, 0x80, 50, // Display On, delay 50ms + 0xFF, 0x00 // End of sequence +}; + +static void WriteByte( struct GDS_Device* Device, uint8_t Data ) { + Device->WriteData( Device, &Data, 1 ); +} + +static void SetColumnAddress( struct GDS_Device* Device, uint16_t Start, uint16_t End ) { + uint32_t Addr = __builtin_bswap16(Start) | (__builtin_bswap16(End) << 16); + Device->WriteCommand( Device, 0x2A ); + Device->WriteData( Device, (uint8_t*) &Addr, 4 ); +} + +static void SetRowAddress( struct GDS_Device* Device, uint16_t Start, uint16_t End ) { + uint32_t Addr = __builtin_bswap16(Start) | (__builtin_bswap16(End) << 16); + Device->WriteCommand( Device, 0x2B ); + Device->WriteData( Device, (uint8_t*) &Addr, 4 ); +} + +static void Update16( struct GDS_Device* Device ) { + struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private; + +#ifdef SHADOW_BUFFER + uint32_t *optr = (uint32_t*) Private->Shadowbuffer, *iptr = (uint32_t*) Device->Framebuffer; + int FirstCol = Device->Width / 2, LastCol = 0, FirstRow = -1, LastRow = 0; + + for (int r = 0; r < Device->Height; r++) { + // look for change and update shadow (cheap optimization = width is always a multiple of 2) + for (int c = 0; c < Device->Width / 2; c++, iptr++, optr++) { + if (*optr != *iptr) { + *optr = *iptr; + if (c < FirstCol) FirstCol = c; + if (c > LastCol) LastCol = c; + if (FirstRow < 0) FirstRow = r; + LastRow = r; + } + } + + // wait for a large enough window - careful that window size might increase by more than a line at once ! + if (FirstRow < 0 || ((LastCol - FirstCol + 1) * (r - FirstRow + 1) * 4 < PAGE_BLOCK && r != Device->Height - 1)) continue; + + FirstCol *= 2; + LastCol = LastCol * 2 + 1; + SetRowAddress( Device, FirstRow + Private->Offset.Height, LastRow + Private->Offset.Height); + SetColumnAddress( Device, FirstCol + Private->Offset.Width, LastCol + Private->Offset.Width ); + Device->WriteCommand( Device, ENABLE_WRITE ); + + int ChunkSize = (LastCol - FirstCol + 1) * 2; + + // own use of IRAM has not proven to be much better than letting SPI do its copy + if (Private->iRAM) { + uint8_t *optr = Private->iRAM; + for (int i = FirstRow; i <= LastRow; i++) { + memcpy(optr, Private->Shadowbuffer + (i * Device->Width + FirstCol) * 2, ChunkSize); + optr += ChunkSize; + if (optr - Private->iRAM <= (PAGE_BLOCK - ChunkSize) && i < LastRow) continue; + Device->WriteData(Device, Private->iRAM, optr - Private->iRAM); + optr = Private->iRAM; + } + } else for (int i = FirstRow; i <= LastRow; i++) { + Device->WriteData( Device, Private->Shadowbuffer + (i * Device->Width + FirstCol) * 2, ChunkSize ); + } + + FirstCol = Device->Width / 2; + LastCol = 0; + FirstRow = -1; + } +#endif +} + +static void Clear( struct GDS_Device* Device ) { + memset( Device->Framebuffer, 0, Device->Width * Device->Height * 2 ); + Device->Update( Device); +} + +static void SetPixel( struct GDS_Device* Device, int X, int Y, uint32_t Color ) { + if( X < 0 || X >= Device->Width || Y < 0 || Y >= Device->Height) return; + + *((uint16_t*) Device->Framebuffer + (Y * Device->Width) + X) = (uint16_t) Color; +} + +static uint32_t GetPixel( struct GDS_Device* Device, int X, int Y ) { + if( X < 0 || X >= Device->Width || Y < 0 || Y >= Device->Height) return 0; + + return *((uint16_t*) Device->Framebuffer + (Y * Device->Width) + X); +} + +static void DrawPixel( struct GDS_Device* Device, int X, int Y, uint32_t Color ) { + SetPixel( Device, X, Y, Color ); +} + +static void DrawPixelFast( struct GDS_Device* Device, int X, int Y, uint32_t Color ) { + *((uint16_t*) Device->Framebuffer + (Y * Device->Width) + X) = (uint16_t) Color; +} + +static void DrawCBR( struct GDS_Device* Device, int X, int Y, int Width, int Height, uint32_t Color ) { + uint16_t *fb = (uint16_t*) Device->Framebuffer + Y * Device->Width + X; + + for( int y = 0; y < Height; y++) { + for( int x = 0; x < Width; x++) { + fb[x] = (uint16_t) Color; + } + fb += Device->Width; + } +} + +static void DrawHLine( struct GDS_Device* Device, int X0, int X1, int Y, uint32_t Color ) { + if( Y < 0 || Y >= Device->Height) return; + + if( X0 > X1) { + int Temp = X0; + X0 = X1; + X1 = Temp; + } + + if( X0 < 0) X0 = 0; + if( X1 >= Device->Width) X1 = Device->Width - 1; + + uint16_t *fb = (uint16_t*) Device->Framebuffer + Y * Device->Width + X0; + + for( int x = X0; x <= X1; x++) { + *fb++ = (uint16_t) Color; + } +} + +static void DrawVLine( struct GDS_Device* Device, int X, int Y0, int Y1, uint32_t Color ) { + if( X < 0 || X >= Device->Width) return; + + if( Y0 > Y1) { + int Temp = Y0; + Y0 = Y1; + Y1 = Temp; + } + + if( Y0 < 0) Y0 = 0; + if( Y1 >= Device->Height) Y1 = Device->Height - 1; + + uint16_t *fb = (uint16_t*) Device->Framebuffer + Y0 * Device->Width + X; + + for( int y = Y0; y <= Y1; y++) { + *fb = (uint16_t) Color; + fb += Device->Width; + } +} + +static bool Init( struct GDS_Device* Device ) { + struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private; + const uint8_t *p = ILI9488_INIT_SEQUENCE; + + ESP_LOGI(TAG, "Initializing ILI9488 display %dx%d", Device->Width, Device->Height); + + // Allocate IRAM buffer if available + Private->iRAM = (uint8_t*) heap_caps_malloc(PAGE_BLOCK, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + if (!Private->iRAM) { + ESP_LOGW(TAG, "Could not allocate IRAM buffer, using direct write"); + } + +#ifdef SHADOW_BUFFER + Private->Shadowbuffer = (uint8_t*) heap_caps_malloc(Device->Width * Device->Height * 2, MALLOC_CAP_DMA); + if (!Private->Shadowbuffer) { + ESP_LOGE(TAG, "Could not allocate shadow buffer"); + if (Private->iRAM) free(Private->iRAM); + return false; + } + memset(Private->Shadowbuffer, 0, Device->Width * Device->Height * 2); +#endif + + // Send initialization sequence + while(*p != 0xFF) { + uint8_t cmd = *p++; + uint8_t len = (*p & 0x7F); + bool delay = (*p++ & 0x80); + + Device->WriteCommand(Device, cmd); + if(len) Device->WriteData(Device, (uint8_t*)p, len); + p += len; + + if(delay) { + uint8_t ms = *p++; + vTaskDelay(ms / portTICK_PERIOD_MS); + } + } + + // Set orientation and layout + Private->MADCtl = 0xE8; // MX=1, MY=1, RGB=1, BGR=0 + Device->WriteCommand(Device, 0x36); + Device->WriteData(Device, &Private->MADCtl, 1); + + // Set pixel format to 16-bit + uint8_t fmt = 0x55; + Device->WriteCommand(Device, 0x3A); + Device->WriteData(Device, &fmt, 1); + + // Turn on display + Device->WriteCommand(Device, 0x29); + + ESP_LOGI(TAG, "ILI9488 initialization complete"); + return true; +} + +static void Deinit( struct GDS_Device* Device ) { + struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private; + + if (Private->iRAM) free(Private->iRAM); +#ifdef SHADOW_BUFFER + if (Private->Shadowbuffer) free(Private->Shadowbuffer); +#endif +} + +struct GDS_Device* ILI9488_Detect( char *Driver, struct GDS_Device *Device ) { + if(strcasecmp(Driver, "ILI9488") != 0) return NULL; + + Device->Private = calloc(1, sizeof(struct PrivateSpace)); + if(!Device->Private) { + ESP_LOGE(TAG, "Cannot allocate private data"); + return NULL; + } + + Device->Mode = GDS_RGB565; + Device->Depth = 16; + Device->Update = Update16; + Device->Clear = Clear; + Device->SetPixel = SetPixel; + Device->GetPixel = GetPixel; + Device->DrawPixel = DrawPixel; + Device->DrawPixelFast = DrawPixelFast; + Device->DrawCBR = DrawCBR; + Device->DrawHLine = DrawHLine; + Device->DrawVLine = DrawVLine; + Device->Init = Init; + Device->Deinit = Deinit; + + ESP_LOGI(TAG, "ILI9488 driver loaded"); + return Device; +} \ No newline at end of file diff --git a/components/display/core/gds_default_if.h b/components/display/core/gds_default_if.h index a657d17e..bc9ba7b8 100644 --- a/components/display/core/gds_default_if.h +++ b/components/display/core/gds_default_if.h @@ -13,6 +13,10 @@ bool GDS_I2CAttachDevice( struct GDS_Device* Device, int Width, int Height, int bool GDS_SPIInit( int SPI, int DC ); bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int Speed, int BacklightPin, int Mode ); +bool GDS_QSPIInit( int QSPI, int DC ); +bool GDS_QSPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int Speed, int BacklightPin, int Mode ); +bool GDS_QSPIBusInit( int MOSIPin, int MISOPin, int CLKPin, int Host ); + #ifdef __cplusplus } #endif diff --git a/components/display/core/ifaces/default_if_qspi.c b/components/display/core/ifaces/default_if_qspi.c new file mode 100644 index 00000000..29e73521 --- /dev/null +++ b/components/display/core/ifaces/default_if_qspi.c @@ -0,0 +1,161 @@ +/** + * QSPI Interface for Guition JC4827W543C ILI9488 Display + * Supports ESP32-S3 QSPI peripheral + * + * (c) Guition Support 2026 + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include +#include +#include +#include +#include +#include +#include +#include "gds.h" +#include "gds_err.h" +#include "gds_private.h" +#include "gds_default_if.h" + +static const int GDS_QSPI_Command_Mode = 0; +static const int GDS_QSPI_Data_Mode = 1; + +static spi_host_device_t QSPIHost; +static int DCPin; + +static bool QSPIDefaultWriteBytes( spi_device_handle_t QSPIHandle, int WriteMode, const uint8_t* Data, size_t DataLength ); +static bool QSPIDefaultWriteCommand( struct GDS_Device* Device, uint8_t Command ); +static bool QSPIDefaultWriteData( struct GDS_Device* Device, const uint8_t* Data, size_t DataLength ); + +bool GDS_QSPIInit( int QSPI, int DC ) { + QSPIHost = QSPI; + DCPin = DC; + return true; +} + +bool GDS_QSPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int BackLightPin, int Speed, int Mode ) { + spi_device_interface_config_t QSPIDeviceConfig = { }; + spi_device_handle_t QSPIDevice; + + NullCheck( Device, return false ); + + if (CSPin >= 0) { + ESP_ERROR_CHECK_NONFATAL( gpio_set_direction( CSPin, GPIO_MODE_OUTPUT ), return false ); + ESP_ERROR_CHECK_NONFATAL( gpio_set_level( CSPin, 0 ), return false ); + } + + QSPIDeviceConfig.clock_speed_hz = Speed > 0 ? Speed : SPI_MASTER_FREQ_20M; + QSPIDeviceConfig.spics_io_num = CSPin; + QSPIDeviceConfig.queue_size = 4; + QSPIDeviceConfig.mode = Mode; + QSPIDeviceConfig.flags = SPI_DEVICE_HALFDUPLEX; + QSPIDeviceConfig.duty_cycle_pos = 128; // 50% duty cycle + + // QSPI specific configuration for ESP32-S3 + QSPIDeviceConfig.command_bits = 8; + QSPIDeviceConfig.address_bits = 24; + QSPIDeviceConfig.address_len = 3; + + if( spi_bus_add_device( QSPIHost, &QSPIDeviceConfig, &QSPIDevice ) != ESP_OK ) { + GDS_LOG_ERROR( "Failed to add QSPI device to host" ); + return false; + } + + if( DCPin >= 0 ) { + ESP_ERROR_CHECK_NONFATAL( gpio_set_direction( DCPin, GPIO_MODE_OUTPUT ), return false ); + ESP_ERROR_CHECK_NONFATAL( gpio_set_level( DCPin, 1 ), return false ); + } + + if( RSTPin >= 0 ) { + ESP_ERROR_CHECK_NONFATAL( gpio_set_direction( RSTPin, GPIO_MODE_OUTPUT ), return false ); + ESP_ERROR_CHECK_NONFATAL( gpio_set_level( RSTPin, 1 ), return false ); + } + + if( BackLightPin >= 0 ) { + ESP_ERROR_CHECK_NONFATAL( gpio_set_direction( BackLightPin, GPIO_MODE_OUTPUT ), return false ); + ESP_ERROR_CHECK_NONFATAL( gpio_set_level( BackLightPin, 1 ), return false ); + } + + Device->WriteCommand = QSPIDefaultWriteCommand; + Device->WriteData = QSPIDefaultWriteData; + Device->DeviceHandle = QSPIDevice; + + // Hardware reset if pin is available + if( RSTPin >= 0 ) { + gpio_set_level( RSTPin, 0 ); + vTaskDelay( pdMS_TO_TICKS( 10 ) ); + gpio_set_level( RSTPin, 1 ); + vTaskDelay( pdMS_TO_TICKS( 120 ) ); + } + + return true; +} + +static bool QSPIDefaultWriteCommand( struct GDS_Device* Device, uint8_t Command ) { + return QSPIDefaultWriteBytes( Device->DeviceHandle, GDS_QSPI_Command_Mode, &Command, 1 ); +} + +static bool QSPIDefaultWriteData( struct GDS_Device* Device, const uint8_t* Data, size_t DataLength ) { + if( DCPin >= 0 ) { + gpio_set_level( DCPin, 1 ); + } + + bool Result = QSPIDefaultWriteBytes( Device->DeviceHandle, GDS_QSPI_Data_Mode, Data, DataLength ); + + if( DCPin >= 0 ) { + gpio_set_level( DCPin, 0 ); + } + + return Result; +} + +static bool QSPIDefaultWriteBytes( spi_device_handle_t QSPIHandle, int WriteMode, const uint8_t* Data, size_t DataLength ) { + spi_transaction_ext_t SPITransaction = { }; + SPITransaction.base.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_VARIABLE_DUMMY; + SPITransaction.base.cmd = 0; + SPITransaction.base.addr = 0; + SPITransaction.base.length = DataLength * 8; + SPITransaction.base.tx_buffer = Data; + SPITransaction.base.rx_buffer = NULL; + SPITransaction.command_bits = 8; + SPITransaction.address_bits = 0; + SPITransaction.dummy_bits = 0; + + if( WriteMode == GDS_QSPI_Command_Mode ) { + SPITransaction.command_bits = 8; + SPITransaction.base.cmd = Data[0]; + SPITransaction.base.length = 0; + SPITransaction.base.tx_buffer = NULL; + } + + if( spi_device_transmit( QSPIHandle, (spi_transaction_t*) &SPITransaction ) != ESP_OK ) { + GDS_LOG_ERROR( "QSPI transaction failed" ); + return false; + } + + return true; +} + +bool GDS_QSPIBusInit( int MOSIPin, int MISOPin, int CLKPin, int Host ) { + spi_bus_config_t BusConfig = { }; + + NullCheck( Host >= SPI2_HOST && Host <= SPI3_HOST, return false ); + + // QSPI pin configuration for ESP32-S3 + BusConfig.mosi_io_num = MOSIPin; + BusConfig.miso_io_num = MISOPin; + BusConfig.sclk_io_num = CLKPin; + BusConfig.quadwp_io_num = -1; // Not used for ILI9488 + BusConfig.quadhd_io_num = -1; // Not used for ILI9488 + BusConfig.max_transfer_sz = 65536; + BusConfig.flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_NATIVE_PINS; + + if( spi_bus_initialize( Host, &BusConfig, DMA_CH_AUTO ) != ESP_OK ) { + GDS_LOG_ERROR( "Failed to initialize QSPI bus" ); + return false; + } + + return true; +} diff --git a/components/display/display.c b/components/display/display.c index 1e470518..1a4f1bfb 100644 --- a/components/display/display.c +++ b/components/display/display.c @@ -73,6 +73,7 @@ static const char *known_drivers[] = {"SH1106", "ST7735", "ST7789", "ILI9341", + "ILI9488", NULL }; @@ -80,8 +81,8 @@ static void displayer_task(void *args); static void display_sleep(void); struct GDS_Device *display; -extern GDS_DetectFunc SSD1306_Detect, SSD132x_Detect, SH1106_Detect, SH1122_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, ILI9341_Detect; -GDS_DetectFunc *drivers[] = { SH1106_Detect, SH1122_Detect, SSD1306_Detect, SSD132x_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, ILI9341_Detect, NULL }; +extern GDS_DetectFunc SSD1306_Detect, SSD132x_Detect, SH1106_Detect, SH1122_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, ILI9341_Detect, ILI9488_Detect; +GDS_DetectFunc *drivers[] = { SH1106_Detect, SH1122_Detect, SSD1306_Detect, SSD132x_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, ILI9341_Detect, ILI9488_Detect, NULL }; /**************************************************************************************** * @@ -134,6 +135,31 @@ void display_init(char *welcome) { GDS_SPIAttachDevice( display, width, height, CS_pin, RST_pin, backlight_pin, speed, mode ); ESP_LOGI(TAG, "Display is SPI host %u with cs:%d", spi_system_host, CS_pin); + } else if (strcasestr(config, "QSPI") && spi_system_host != -1) { + int CS_pin = -1, speed = 0, mode = 0; + + PARSE_PARAM(config, "cs", '=', CS_pin); + PARSE_PARAM(config, "speed", '=', speed); + PARSE_PARAM(config, "mode", '=', mode); + + // Parse QSPI data pins + int data_pins[4] = {-1, -1, -1, -1}; + char *data_str = strstr(config, "data="); + if (data_str) { + sscanf(data_str + 5, "%d,%d,%d,%d", &data_pins[0], &data_pins[1], &data_pins[2], &data_pins[3]); + } + + init = true; + + // Initialize QSPI bus with data pins + if (data_pins[0] != -1 && data_pins[1] != -1 && data_pins[2] != -1 && data_pins[3] != -1) { + GDS_QSPIBusInit( data_pins[0], data_pins[1], spi_system_clk_gpio, spi_system_host ); + } + + GDS_QSPIInit( spi_system_host, spi_system_dc_gpio ); + GDS_QSPIAttachDevice( display, width, height, CS_pin, RST_pin, backlight_pin, speed, mode ); + + ESP_LOGI(TAG, "Display is QSPI host %u with cs:%d", spi_system_host, CS_pin); } else { display = NULL; ESP_LOGI(TAG, "Unsupported display interface or serial link not configured"); diff --git a/components/targets/CMakeLists.txt b/components/targets/CMakeLists.txt index 9e97b3ec..9594e08b 100644 --- a/components/targets/CMakeLists.txt +++ b/components/targets/CMakeLists.txt @@ -1,4 +1,4 @@ -idf_component_register( SRC_DIRS . muse +idf_component_register( SRC_DIRS . muse guition INCLUDE_DIRS . PRIV_REQUIRES services ) diff --git a/components/targets/guition/CMakeLists.txt b/components/targets/guition/CMakeLists.txt new file mode 100644 index 00000000..1b791165 --- /dev/null +++ b/components/targets/guition/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRCS "guition.c" + INCLUDE_DIRS "." + REQUIRES driver esp_common +) diff --git a/components/targets/guition/guition.c b/components/targets/guition/guition.c new file mode 100644 index 00000000..81b9d717 --- /dev/null +++ b/components/targets/guition/guition.c @@ -0,0 +1,43 @@ +/* + * Guition JC4827W543C board support for squeezelite-esp32 + * + * (c) Guition Board Support 2026 + * Based on squeezelite-esp32 architecture + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include +#include +#include +#include +#include +#include +#include "globdefs.h" +#include "monitor.h" +#include "targets.h" + +static const char TAG[] = "guition"; + +static bool init(void); + +const struct target_s target_guition = { + .model = "guition", + .init = init +}; + +static bool init(void) { + ESP_LOGI(TAG, "Initializing Guition JC4827W543C board"); + ESP_LOGI(TAG, "Board features:"); + ESP_LOGI(TAG, " - ESP32-S3-WROOM-1 processor"); + ESP_LOGI(TAG, " - 4.3\" ILI9488 display (480x272)"); + ESP_LOGI(TAG, " - GT911 capacitive touch"); + ESP_LOGI(TAG, " - QSPI display interface"); + ESP_LOGI(TAG, " - I2C touch interface (GPIO8/4)"); + + // No board-specific hardware initialization required + // All configuration is handled through NVS parameters + + return true; +} diff --git a/components/targets/targets.c b/components/targets/targets.c index 9f54d364..7b84f05f 100644 --- a/components/targets/targets.c +++ b/components/targets/targets.c @@ -1,7 +1,7 @@ #include "string.h" #include "targets.h" -const struct target_s *target_set[] = { &target_muse, NULL }; +const struct target_s *target_set[] = { &target_muse, &target_guition, NULL }; void target_init(char *target) { for (int i = 0; *target && target_set[i]; i++) if (strcasestr(target_set[i]->model, target)) { diff --git a/components/targets/targets.h b/components/targets/targets.h index c6f870e1..4c6ab604 100644 --- a/components/targets/targets.h +++ b/components/targets/targets.h @@ -20,3 +20,4 @@ struct target_s { }; extern const struct target_s target_muse; +extern const struct target_s target_guition; diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 4ade34a3..d4d4944d 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -73,6 +73,10 @@ menu "Squeezelite-ESP32" bool "T-WATCH2020 by LilyGo" select I2C_LOCKED select TARGET_LOCKED + config GUITION + bool "Guition JC4827W543C" + select I2C_LOCKED + select TARGET_LOCKED endchoice config RELEASE_API string "Software update URL" @@ -91,12 +95,14 @@ menu "Squeezelite-ESP32" default "SqueezeAMP" if SQUEEZEAMP default "Squeezelite-TWATCH" if TWATCH2020 default "Muse" if MUSE + default "Squeezelite-Guition" if GUITION default "Squeezelite-ESP32" config FW_PLATFORM_NAME string default "SqueezeAmp" if SQUEEZEAMP default "TWATCH" if TWATCH2020 default "Muse" if MUSE + default "Guition" if GUITION default "ESP32" # AGGREGATES - begin # these parameters are "aggregates" that take precedence. They must have a default value @@ -105,6 +111,7 @@ menu "Squeezelite-ESP32" default "model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0" if SQUEEZEAMP default "model=I2S,bck=26,ws=25,do=33,i2c=53,sda=21,scl=22" if TWATCH2020 default "model=I2S,bck=5,ws=25,do=26,di=35,i2c=16,sda=18,scl=23,mck" if MUSE + default "model=I2S,bck=15,ws=16,do=17" if GUITION default "" config SPDIF_CONFIG string @@ -117,10 +124,12 @@ menu "Squeezelite-ESP32" string default "dc=27,data=19,clk=18" if TWATCH2020 default "mosi=15,miso=2,clk=14" if MUSE + default "clk=47,data=21,48,40,39,cs=45,host=2" if GUITION default "" config DISPLAY_CONFIG string default "SPI,driver=ST7789,width=240,height=240,cs=5,back=12,speed=16000000,HFlip,VFlip" if TWATCH2020 + default "QSPI,driver=ILI9488,width=480,height=272,cs=45,speed=20000000,invert,rotate" if GUITION default "" config ETH_CONFIG string @@ -143,6 +152,7 @@ menu "Squeezelite-ESP32" config TARGET string default "muse" if MUSE + default "guition" if GUITION default "" config AMP_GPIO int @@ -176,6 +186,7 @@ menu "Squeezelite-ESP32" string default "0=ir" if SQUEEZEAMP default "" if TWATCH2020 + default "1=backlight" if GUITION endmenu menu "Audio settings" @@ -344,6 +355,7 @@ menu "Squeezelite-ESP32" visible if !TWATCH2020 config I2C_CONFIG string "I2C system configuration" + default "sda=8,scl=4,speed=400000,port=0" if GUITION default "" help Set parameters of shared I2C interface diff --git a/squeezelite-esp32-Guition-sdkconfig.defaults b/squeezelite-esp32-Guition-sdkconfig.defaults new file mode 100644 index 00000000..7ba15a00 --- /dev/null +++ b/squeezelite-esp32-Guition-sdkconfig.defaults @@ -0,0 +1,139 @@ +# +# Guition JC4827W543C ESP32-S3 configuration +# Based on I2S-S3-sdkconfig with Guition-specific settings +# + +# ESP32-S3 Target Configuration +CONFIG_IDF_TARGET="esp32s3" +CONFIG_IDF_TARGET_ESP32S3=y +CONFIG_IDF_FIRMWARE_CHIP_ID=0x0009 + +# ESP32-S3 specific settings +CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y +CONFIG_ESP32S3_SPIRAM_SUPPORT=y +CONFIG_SPIRAM_SPEED_80M=y +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_TYPE_AUTO=y +CONFIG_SPIRAM_SIZE_AUTO=y +CONFIG_SPIRAM_USE_MALLOC=y +CONFIG_SPIRAM_USE_CAPS_ALLOC=y +CONFIG_SPIRAM_USE_HEAP=y +CONFIG_SPIRAM_CACHE_WR=y +CONFIG_SPIRAM_CACHE_WR=y + +# PSRAM Configuration +CONFIG_SPIRAM_BOOT_INIT=y +CONFIG_SPIRAM_IGNORE_NOTFOUND=n +CONFIG_SPIRAM_USE_MEMMAP=y +CONFIG_SPIRAM_USE_NOINIT=n +CONFIG_SPIRAM_USE_EMBEDDED_MEM=n +CONFIG_SPIRAM_USE_CAPS_ALLOC=y +CONFIG_SPIRAM_USE_MALLOC=y +CONFIG_SPIRAM_USE_HEAP=y +CONFIG_SPIRAM_MEMTEST=y +CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384 +CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768 +CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y +CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY=y +CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=n + +# Performance Settings +CONFIG_ESP32S3_RTOS_INT_NUM=0 +CONFIG_ESP32S3_TRACEMEM_RESERVE_DRAM=0x0 + +# Flash Configuration +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_ESPTOOLPY_FLASHMODE_DIO=y +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y + +# Partition Table +CONFIG_PARTITION_TABLE_SINGLE_APP=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_single_app.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_single_app.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 + +# UART Configuration +CONFIG_ESP_CONSOLE_UART_DEFAULT=y +CONFIG_ESP_CONSOLE_UART_NUM=0 +CONFIG_ESP_CONSOLE_UART_TX_GPIO=43 +CONFIG_ESP_CONSOLE_UART_RX_GPIO=44 + +# GPIO Configuration +CONFIG_GPIO_CTRL_FUNC_IN_IRAM=y + +# FreeRTOS Configuration +CONFIG_FREERTOS_HZ=1000 + +# Log Configuration +CONFIG_LOG_DEFAULT_LEVEL_INFO=y +CONFIG_LOG_MAXIMUM_LEVEL=3 + +# Component Configuration +CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32 +CONFIG_LWIP_UDP_RECVMBOX_SIZE=6 +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072 + +# WiFi Configuration +CONFIG_ESP32_WIFI_ENABLED=y +CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y +CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 + +# Bluetooth Configuration (ESP32-S3 doesn't have Bluetooth Audio) +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=y +CONFIG_BT_CLASSIC_ENABLED=y +CONFIG_BT_SCO_ENABLED=y +CONFIG_BT_A2DP_ENABLE=y +CONFIG_BT_BLE_ENABLED=y + +# ADC Configuration +CONFIG_ADC_CAL_EFUSE_TP_ENABLE=n +CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=n +CONFIG_ADC_CAL_LUT_ENABLE=n + +# I2C Configuration +CONFIG_I2C_ENABLE_DEBUG_LOG=n + +# SPI Configuration +CONFIG_SPI_MASTER_IN_IRAM=y +CONFIG_SPI_SLAVE_IN_IRAM=y + +# Touch Configuration +CONFIG_TOUCH_PAD_SLEEP_CYCLE=2000 + +# FAT Filesystem +CONFIG_FATFS_LAZY_LOCK=y +CONFIG_FATFS_API_IN_IRAM=y + +# Event Loop Library +CONFIG_EVENT_LOOP_PROFILING=n + +# Ethernet +CONFIG_ETH_USE_ESP32_EMAC=n + +# HTTP Server +CONFIG_HTTPD_WS_SUPPORT=y + +# JSON Parser +CONFIG_JSON_ENABLE_DEBUG=n + +# MDNS +CONFIG_MDNS_ENABLE_DEBUG=n + +# MQTT +CONFIG_MQTT_PROTOCOL_311=y +CONFIG_MQTT_TRANSPORT_SSL=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET=y + +# OpenSSL +CONFIG_OPENSSL_DEBUG=n + +# Protobuf-c +CONFIG_PROTOBUF_C_ENABLE_DEBUG=n + +# WebSockets +CONFIG_WS_BUFFER_SIZE=1024 + +# NVS +CONFIG_NVS_ENCRYPTION=n +CONFIG_NVS_ASSERT_ERROR_CHECK=n