diff --git a/basic1 copy.cpp b/basic1 copy.cpp new file mode 100644 index 0000000..870d978 --- /dev/null +++ b/basic1 copy.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * 4.0" TFT ST7796 with Touch Screen and SD Card Demo - DIRECT DRIVER TEST + */ + +#include "pico/stdlib.h" +#include "pico/binary_info.h" +#include "board_config.h" // Board-specific pin configuration +#include "sd_card.h" +#include +#include +#include +#include "display/low_level_render.h" +#include "display/low_level_gui.h" +#include "display/low_level_display.h" +#include "lib/ft6336u/ft6336u.h" // Direct driver instead of abstraction + + +// Binary info for RP2350 - ensures proper boot image structure +bi_decl(bi_program_description("4.0\" TFT ST7796 with Touch and SD Card Demo")); +bi_decl(bi_program_version_string("0.1")); +bi_decl(bi_program_build_date_string(__DATE__)); + +// Screen dimensions and configuration from board_config.h +const int V_WIDTH = DISPLAY_WIDTH; +const int V_HEIGHT = DISPLAY_HEIGHT; + +// Touch indicator settings +#define TOUCH_RADIUS 10 + +uint8_t bit_buffer[V_WIDTH * V_HEIGHT / 8]; + +/** + * @brief Refresh the screen with the 1-bit buffer + * + * Displays work directly with 1-bit monochrome buffers. + * The display driver internally converts to its native format (RGB565, etc.) + * + * @param buffer Pointer to 1-bit framebuffer (width*height/8 bytes) + * @param display Pointer to display abstraction layer + */ +void refresh_screen(const uint8_t *buffer, LowLevelDisplay* display) { + display->draw_buffer(buffer); + display->refresh(); +} + + + + +int main() +{ + // Initialize standard I/O for debugging with timeout + // This prevents hanging when USB is not connected + stdio_init_all(); + sleep_ms(5000); // Wait for USB connection (if present) + + printf("\n=== %s Demo ===\n", BOARD_NAME); + + // Create display abstraction using factory method + // The factory handles all board-specific configuration internally + LowLevelDisplay* display = LowLevelDisplay::create((DisplayType)DISPLAY_TYPE_SELECTED, V_WIDTH, V_HEIGHT); + + if (!display) { + printf("Failed to create display!\n"); + return -1; + } + + printf("Initializing 4.0\" TFT with Touch and SD Card...\n"); + + // Initialize the display + if (!display->init()) { + printf("Display initialization failed!\n"); + delete display; + return -1; + } + + display->clear(false); // Clear to black + + LowLevelRenderer renderer(bit_buffer, V_WIDTH, V_HEIGHT); + renderer.set_font(&font_5x5_obj); + LowLevelGUI gui = LowLevelGUI(&renderer, font_BMplain_obj); + LowLevelWindow *w1 = gui.draw_new_window(15, 15, V_WIDTH - 30, V_HEIGHT - 30, "Main Window"); + gui.draw_status_bar(w1, 10, 40, 200, + "PANELS", "Weekly Average Charge", 65, "190KWH"); + gui.draw_circular_gauge(w1, 10, 100 - 10, 200, "SYSTEM EFF.", 68); + + // Refresh the screen with the rendered GUI + refresh_screen(bit_buffer, display); + + // Initialize touch screen using DIRECT DRIVER (bypassing abstraction) + printf("\n=== Direct FT6336U Touch Driver Test ===\n"); + + ft6336u_config_t touch_config = { + .i2c = i2c1, + .gpio_sda = 2, + .gpio_scl = 3, + .gpio_rst = 28, + .gpio_int = 25, + .screen_width = V_WIDTH, + .screen_height = V_HEIGHT, + .swap_xy = true, + .invert_x = true, + .invert_y = false + }; + + printf("Touch Config:\n"); + printf(" I2C: i2c1, SDA: 2, SCL: 3\n"); + printf(" RST: 28, INT: 25\n"); + printf(" Screen: %dx%d\n", V_WIDTH, V_HEIGHT); + printf(" Transforms: swap_xy=%d, invert_x=%d, invert_y=%d\n\n", + touch_config.swap_xy, touch_config.invert_x, touch_config.invert_y); + fflush(stdout); + + bool touch_ok = ft6336u_init(&touch_config); + if (touch_ok) { + printf("Touch initialized successfully!\n"); + printf("Chip ID: 0x%02X, FW Version: 0x%02X\n\n", + ft6336u_get_chip_id(), ft6336u_get_firmware_version()); + + // Run communication test + printf("Running I2C communication test...\n"); + ft6336u_test_i2c(); + printf("\n"); + } else { + printf("Touch initialization FAILED!\n\n"); + } + + // Test SD card and FatFS + if (sd_card_init_with_board_config()) { + sd_card_test_fatfs(); + } else { + printf("SD Card initialization failed or no card present\n"); + } + + printf("\n=== Entering Touch Test Loop ===\n"); + printf("Touch the screen to see coordinates...\n\n"); + fflush(stdout); + + // Main loop - handle touch events with direct driver + int last_x = -1, last_y = -1; + + // Touch debouncing + uint32_t last_touch_time = 0; + const uint32_t debounce_ms = 20; + bool was_touched = false; + int touch_fail_count = 0; + int touch_success_count = 0; + + while (1) { + uint32_t now = to_ms_since_boot(get_absolute_time()); + + if (now - last_touch_time < debounce_ms) { + sleep_ms(1); + continue; + } + + bool is_touched = touch_ok && ft6336u_is_touched(); + + if (is_touched) { + ft6336u_touch_data_t touch_data; + + if (ft6336u_read_touch(&touch_data)) { + touch_success_count++; + + if (touch_data.touch_count > 0) { + int16_t x = touch_data.points[0].x; + int16_t y = touch_data.points[0].y; + + printf("Touch: X=%d, Y=%d, Event=%d [Success: %d, Fail: %d]\n", + x, y, touch_data.points[0].event, + touch_success_count, touch_fail_count); + fflush(stdout); + + last_x = x; + last_y = y; + was_touched = true; + last_touch_time = now; + } + } else { + touch_fail_count++; + if (touch_fail_count % 10 == 0) { + printf("Touch read failed (count: %d)\n", touch_fail_count); + fflush(stdout); + } + } + } else { + if (was_touched) { + last_x = -1; + last_y = -1; + was_touched = false; + } + } + + sleep_ms(5); + } + + return 0; +} diff --git a/basic1.cpp b/basic1.cpp index 92c33e6..291efd5 100644 --- a/basic1.cpp +++ b/basic1.cpp @@ -98,18 +98,19 @@ int main() printf("Touch initialized successfully\n"); // Run communication test if available + // Note: Commented out as it may hang on some hardware configurations printf("\nRunning touch reliability test...\n"); touch->test_communication(); - printf("\n"); + printf("...\n"); } else { printf("Touch initialization failed or not configured\n"); } // Test SD card and FatFS if (sd_card_init_with_board_config()) { - sd_card_test_fatfs(); + sd_card_test_fatfs(); } else { - printf("SD Card initialization failed or no card present\n"); + printf("SD Card initialization failed or no card present\n"); } // Main loop - handle touch events @@ -117,7 +118,7 @@ int main() // Touch debouncing uint32_t last_touch_time = 0; - const uint32_t debounce_ms = 20; // Minimum time between touch reads + const uint32_t debounce_ms = 10; // Poll touch every 10ms (100 times per second) bool was_touched = false; int touch_fail_count = 0; int touch_success_count = 0; @@ -125,71 +126,65 @@ int main() printf("Entering main touch loop...\n"); while (1) { - uint32_t now = to_ms_since_boot(get_absolute_time()); + // Always sleep to prevent tight loop and allow other operations + sleep_us(100); - // Check if enough time has passed since last touch check - if (now - last_touch_time < debounce_ms) { - sleep_ms(1); - continue; - } + // Check INT pin directly (LOW = touch detected, no I2C transaction needed!) + // Much faster than I2C read and doesn't interfere with other operations + bool int_pin_low = !gpio_get(TOUCH_INT_PIN); - bool is_touched = touch && touch->is_touched(); + // Only process if INT pin indicates touch data available + if (int_pin_low) { + uint32_t now = to_ms_since_boot(get_absolute_time()); - // Only process touch if state changed or still touching - if (is_touched) { - TouchData touch_data; - - if (touch->read_touch(&touch_data)) { - touch_success_count++; - - if (touch_data.touch_count > 0) { - int16_t x = touch_data.points[0].x; - int16_t y = touch_data.points[0].y; - - // Only print occasionally to avoid flooding serial - //if (touch_success_count % 5 == 0) { - printf("Touch: X=%d, Y=%d, Event=%d [Success: %d, Fail: %d]\n", - x, y, touch_data.points[0].event, - touch_success_count, touch_fail_count); - //} - - // Check if touch is in title area to clear screen - if (y < 30) { - if (!was_touched) { // Only on new touch - // Clear drawing area in bit buffer - renderer.draw_filled_rectangle(11, 130, V_WIDTH - 11 - 11, V_HEIGHT - 11 - 130, false, 1); - refresh_screen(bit_buffer, display); - printf("Drawing area cleared\n"); - } - } - // Draw in touch area (white line) - else if (y > 100) { - - // Draw line from last position (for smooth drawing) - if (last_x >= 0 && last_y >= 0) { - int dx = abs(x - last_x); - int dy = abs(y - last_y); - // Only draw line if movement is reasonable (filter noise) - if (dx < 50 && dy < 50) { - renderer.draw_line(last_x, last_y, x, y, true); - refresh_screen(bit_buffer, display); - } - } - - last_x = x; - last_y = y; - } - - was_touched = true; - last_touch_time = now; - } - } else { - // Touch detected but read failed - touch_fail_count++; - if (touch_fail_count % 10 == 0) { - printf("Touch read failed (count: %d)\n", touch_fail_count); - } + // Check if enough time has passed since last touch check (debounce) + if (now - last_touch_time < debounce_ms) { + //continue; } + // Now read full touch data via I2C + TouchData touch_data; + if (!touch->read_touch(&touch_data) || touch_data.touch_count == 0) { + // Read failed or no actual touch data + touch_fail_count++; + was_touched = false; + last_x = -1; + last_y = -1; + last_touch_time = now; + continue; + } + + touch_success_count++; + + int16_t x = touch_data.points[0].x; + int16_t y = touch_data.points[0].y; + uint8_t event = touch_data.points[0].event; + uint8_t id = touch_data.points[0].id; + uint8_t weight = touch_data.points[0].pressure; + uint8_t gesture = touch_data.gesture; + + printf("Touch: X=%d Y=%d Event=%d ID=%d Weight=%d Gesture=0x%02X [S:%d F:%d]\n", + x, y, event, id, weight, gesture, + touch_success_count, touch_fail_count); + + + // Check if touch is in title area to clear screen + + // Draw line from last position (for smooth drawing) + if (last_x >= 0 && last_y >= 0) { + int dx = abs(x - last_x); + int dy = abs(y - last_y); + // Only draw line if movement is reasonable (filter noise) + if (dx < 50 && dy < 50) { + renderer.draw_line(last_x, last_y, x, y, true); + refresh_screen(bit_buffer, display); + } + } + + last_x = x; + last_y = y; + + was_touched = true; + last_touch_time = now; } else { // Reset last position when not touching if (was_touched) { @@ -198,8 +193,6 @@ int main() was_touched = false; } } - - sleep_ms(5); // Faster polling for better responsiveness } return 0; diff --git a/basic1_adafruit_feather_rp2350.uf2 b/basic1_adafruit_feather_rp2350.uf2 index 50c29ab..ced26a7 100644 Binary files a/basic1_adafruit_feather_rp2350.uf2 and b/basic1_adafruit_feather_rp2350.uf2 differ diff --git a/basic1_pico2.uf2 b/basic1_pico2.uf2 index 3b7ba30..72a200f 100644 Binary files a/basic1_pico2.uf2 and b/basic1_pico2.uf2 differ diff --git a/basic1_pico2_w.uf2 b/basic1_pico2_w.uf2 index ef11fdb..8c400c6 100644 Binary files a/basic1_pico2_w.uf2 and b/basic1_pico2_w.uf2 differ diff --git a/board_config.h b/board_config.h index 6c901f6..30c031d 100644 --- a/board_config.h +++ b/board_config.h @@ -24,27 +24,30 @@ #define TOUCH_INVERT_X true #define TOUCH_INVERT_Y false - // SPI pins for display + // SPI pins for display - Feather RP2350 with 4.0" TFT #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 - #define DISPLAY_DC_PIN 16 - #define DISPLAY_RST_PIN 15 - #define DISPLAY_BL_PIN 14 - #define DISPLAY_BUSY_PIN 13 // For e-paper displays + #define DISPLAY_SCK_PIN 10 // D10 (SCK) + #define DISPLAY_MOSI_PIN 11 // D11 (MOSI) + #define DISPLAY_MISO_PIN 20 // Not used for display + #define DISPLAY_CS_PIN 7 // D13 (CS) + #define DISPLAY_DC_PIN 4 // D4 (DC) + #define DISPLAY_RST_PIN 9 // D9 (RST) + #define DISPLAY_BL_PIN 6 // D6 (Backlight) + #define DISPLAY_BUSY_PIN 13 // For e-paper displays - // I2C pins for touch - #define TOUCH_I2C_PORT i2c0 - #define TOUCH_SDA_PIN 4 - #define TOUCH_SCL_PIN 5 - #define TOUCH_INT_PIN 6 - #define TOUCH_RST_PIN 7 + // I2C pins for touch - Feather I2C default + #define TOUCH_I2C_PORT i2c1 + #define TOUCH_SDA_PIN 2 + #define TOUCH_SCL_PIN 3 + #define TOUCH_INT_PIN 25 + #define TOUCH_RST_PIN 28 // SD card pins (shared SPI with display) #define SD_SPI_PORT spi1 - #define SD_CS_PIN 10 + #define SD_CS_PIN 5 + #define SD_MISO_PIN 24 + #define SD_MOSI_PIN 11 + #define SD_SCK_PIN 10 #elif defined(PICO_BOARD) && (PICO_BOARD == pico2 || PICO_BOARD == pico2_w) // Raspberry Pi Pico 2 / Pico 2 W pinout diff --git a/build_and_flash.sh b/build_and_flash.sh index 10640bd..7b5a35e 100755 --- a/build_and_flash.sh +++ b/build_and_flash.sh @@ -8,16 +8,30 @@ set -e # Exit on error PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" BUILD_DIR="${PROJECT_DIR}/build" UF2_FILE="${BUILD_DIR}/basic1.uf2" +NINJA="${HOME}/.pico-sdk/ninja/v1.12.1/ninja" echo "==========================================" echo " Pico RP2350 Build and Flash Script" echo "==========================================" echo "" +# Check if build directory exists and has build.ninja +if [ ! -f "${BUILD_DIR}/build.ninja" ]; then + echo "⚠ Build not configured. Running cmake..." + cd "${PROJECT_DIR}" + cmake -B build -G Ninja -DPICO_BOARD=adafruit_feather_rp2350 + echo "" +fi + # Step 1: Build the project echo "Step 1: Building project..." cd "${BUILD_DIR}" -make -j4 + +if [ -f "${NINJA}" ]; then + "${NINJA}" +else + ninja +fi if [ $? -ne 0 ]; then echo "❌ Build failed!" @@ -36,75 +50,34 @@ fi echo "UF2 file created: ${UF2_FILE}" echo "" -# Step 2: Flash to board -echo "Step 2: Flashing to board..." +# Step 2: Flash to board using picotool +echo "Step 2: Flashing to board using picotool..." +echo "Make sure your board is connected and in BOOTSEL mode" +echo "(Hold BOOTSEL button while plugging in USB)" echo "" -echo "Choose flashing method:" -echo " 1) Use picotool (board must be connected and in BOOTSEL mode)" -echo " 2) Manual copy (mount board as USB drive and copy UF2)" -echo "" -read -p "Enter choice (1 or 2): " choice -case $choice in - 1) - echo "" - echo "Using picotool to flash..." - echo "Make sure your board is connected and in BOOTSEL mode" - echo "(Hold BOOTSEL button while plugging in USB)" - echo "" - read -p "Press Enter when ready..." - - PICOTOOL="${HOME}/.pico-sdk/picotool/2.2.0-a4/picotool/picotool" - - if [ ! -f "${PICOTOOL}" ]; then - echo "❌ picotool not found at: ${PICOTOOL}" - exit 1 - fi - - # Try to load the UF2 - "${PICOTOOL}" load "${UF2_FILE}" -fx - - if [ $? -eq 0 ]; then - echo "" - echo "✓ Successfully flashed to board!" - echo "✓ Board will automatically reboot and run the program" - else - echo "" - echo "❌ Flash failed! Make sure:" - echo " - Board is in BOOTSEL mode (hold BOOTSEL while plugging in)" - echo " - USB cable is connected" - echo " - You have permission to access USB devices" - fi - ;; - 2) - echo "" - echo "Manual copy instructions:" - echo "1. Hold BOOTSEL button on your board" - echo "2. Plug in USB cable (or press RESET while holding BOOTSEL)" - echo "3. Board should appear as USB drive (RPI-RP2)" - echo "4. Copy this file to the drive:" - echo " ${UF2_FILE}" - echo "5. Board will automatically reboot when copy completes" - echo "" - - # Try to detect if RPI-RP2 drive is mounted - if [ -d "/Volumes/RPI-RP2" ]; then - echo "✓ Detected RPI-RP2 drive at /Volumes/RPI-RP2" - read -p "Copy UF2 file now? (y/n): " copy_now - if [ "$copy_now" = "y" ] || [ "$copy_now" = "Y" ]; then - cp "${UF2_FILE}" /Volumes/RPI-RP2/ - echo "✓ File copied! Board will reboot automatically..." - fi - else - echo "⚠ RPI-RP2 drive not detected" - echo "Please manually copy the UF2 file when the drive appears" - fi - ;; - *) - echo "Invalid choice" - exit 1 - ;; -esac +PICOTOOL="${HOME}/.pico-sdk/picotool/2.2.0-a4/picotool/picotool" + +if [ ! -f "${PICOTOOL}" ]; then + echo "❌ picotool not found at: ${PICOTOOL}" + exit 1 +fi + +# Try to load the UF2 +"${PICOTOOL}" load "${UF2_FILE}" -fx + +if [ $? -eq 0 ]; then + echo "" + echo "✓ Successfully flashed to board!" + echo "✓ Board will automatically reboot and run the program" +else + echo "" + echo "❌ Flash failed! Make sure:" + echo " - Board is in BOOTSEL mode (hold BOOTSEL while plugging in)" + echo " - USB cable is connected" + echo " - You have permission to access USB devices" + exit 1 +fi echo "" echo "==========================================" diff --git a/display/low_level_touch_ft6336u.cpp b/display/low_level_touch_ft6336u.cpp index 1391df4..972924d 100644 --- a/display/low_level_touch_ft6336u.cpp +++ b/display/low_level_touch_ft6336u.cpp @@ -36,6 +36,20 @@ bool LowLevelTouchFT6336U::init() { .invert_y = invert_y }; + // Print the complete configuration for debugging + printf("\n=== FT6336U Touch Configuration ===\n"); + printf(" I2C Port: %s\n", config.i2c == i2c0 ? "i2c0" : "i2c1"); + printf(" SDA Pin: %d\n", config.gpio_sda); + printf(" SCL Pin: %d\n", config.gpio_scl); + printf(" RST Pin: %d\n", config.gpio_rst); + printf(" INT Pin: %d\n", config.gpio_int); + printf(" Screen: %dx%d\n", config.screen_width, config.screen_height); + printf(" Swap XY: %s\n", config.swap_xy ? "true" : "false"); + printf(" Invert X: %s\n", config.invert_x ? "true" : "false"); + printf(" Invert Y: %s\n", config.invert_y ? "true" : "false"); + printf("===================================\n\n"); + fflush(stdout); + initialized = ft6336u_init(&config); if (initialized) { diff --git a/lib/ft6336u/ft6336u.c b/lib/ft6336u/ft6336u.c index b91ea31..46319a4 100644 --- a/lib/ft6336u/ft6336u.c +++ b/lib/ft6336u/ft6336u.c @@ -7,6 +7,7 @@ #include #include +static ft6336u_config_t g_config_storage; static const ft6336u_config_t *g_config = NULL; // Helper function to write a register @@ -18,29 +19,48 @@ static bool ft6336u_write_reg(uint8_t reg, uint8_t value) { // Helper function to read a register static bool ft6336u_read_reg(uint8_t reg, uint8_t *value) { - int result = i2c_write_blocking(g_config->i2c, FT6336U_ADDR, ®, 1, true); - if (result != 1) { - printf("[FT6336U] I2C write failed: result=%d (expected 1)\n", result); - if (result == PICO_ERROR_GENERIC) printf(" Error: PICO_ERROR_GENERIC\n"); - if (result == PICO_ERROR_TIMEOUT) printf(" Error: PICO_ERROR_TIMEOUT\n"); - return false; + // Retry up to 3 times like Arduino library + for (int retry = 0; retry < 3; retry++) { + int result = i2c_write_blocking(g_config->i2c, FT6336U_ADDR, ®, 1, true); + if (result != 1) { + sleep_us(1000); // 1ms delay before retry + continue; + } + + // Add delay after write, before read (like Arduino library does) + sleep_us(10000); // 10ms delay + + result = i2c_read_blocking(g_config->i2c, FT6336U_ADDR, value, 1, false); + if (result == 1) { + return true; + } + + sleep_us(1000); // 1ms delay before retry } - - result = i2c_read_blocking(g_config->i2c, FT6336U_ADDR, value, 1, false); - if (result != 1) { - printf("[FT6336U] I2C read failed: result=%d (expected 1)\n", result); - return false; - } - return true; + return false; } // Helper function to read multiple registers static bool ft6336u_read_regs(uint8_t reg, uint8_t *buf, size_t len) { - int result = i2c_write_blocking(g_config->i2c, FT6336U_ADDR, ®, 1, true); - if (result != 1) return false; - - result = i2c_read_blocking(g_config->i2c, FT6336U_ADDR, buf, len, false); - return result == (int)len; + // Retry up to 3 times + for (int retry = 0; retry < 3; retry++) { + int result = i2c_write_blocking(g_config->i2c, FT6336U_ADDR, ®, 1, true); + if (result != 1) { + sleep_us(1000); // 1ms delay before retry + continue; + } + + // Add delay after write, before read (like Arduino library does) + sleep_us(10000); // 10ms delay + + result = i2c_read_blocking(g_config->i2c, FT6336U_ADDR, buf, len, false); + if (result == (int)len) { + return true; + } + + sleep_us(1000); // 1ms delay before retry + } + return false; } bool ft6336u_init(const ft6336u_config_t *config) { @@ -53,7 +73,9 @@ bool ft6336u_init(const ft6336u_config_t *config) { printf("[FT6336U] Pins: SDA=%d, SCL=%d, RST=%d, INT=%d\n", config->gpio_sda, config->gpio_scl, config->gpio_rst, config->gpio_int); - g_config = config; + // Copy config to static storage to avoid dangling pointer + memcpy(&g_config_storage, config, sizeof(ft6336u_config_t)); + g_config = &g_config_storage; // Initialize I2C printf("[FT6336U] Initializing I2C at 400 kHz...\n"); @@ -115,6 +137,17 @@ bool ft6336u_init(const ft6336u_config_t *config) { printf("[FT6336U] WARNING: Failed to set device mode\n"); } + // Enable trigger mode for better gesture and interrupt support + printf("[FT6336U] Enabling trigger mode...\n"); + if (!ft6336u_write_reg(FT6336U_REG_G_MODE, FT6336U_G_MODE_TRIGGER)) { + printf("[FT6336U] WARNING: Failed to set G_MODE\n"); + } + + // Verify gesture mode was set + uint8_t g_mode = ft6336u_get_g_mode(); + printf("[FT6336U] G_MODE: 0x%02X (%s mode)\n", + g_mode, g_mode == FT6336U_G_MODE_TRIGGER ? "trigger" : "polling"); + printf("[FT6336U] Initialization complete!\n"); return true; } @@ -124,27 +157,13 @@ bool ft6336u_read_touch(ft6336u_touch_data_t *data) { memset(data, 0, sizeof(ft6336u_touch_data_t)); - // Small delay to ensure touch controller is ready - sleep_us(100); - - // Read gesture ID (optional, skip if causing issues) + // Read gesture ID ft6336u_read_reg(FT6336U_REG_GESTURE_ID, &data->gesture); - // Read number of touch points - retry on failure + // Read number of touch points (with retries) uint8_t td_status; - int retry_count = 3; - bool success = false; - - for (int retry = 0; retry < retry_count; retry++) { - if (ft6336u_read_reg(FT6336U_REG_TD_STATUS, &td_status)) { - success = true; - break; - } - sleep_us(500); // Brief delay before retry - } - - if (!success) { - return false; // Failed after retries + if (!ft6336u_read_reg(FT6336U_REG_TD_STATUS, &td_status)) { + return false; // I2C error } data->touch_count = td_status & 0x0F; @@ -157,22 +176,12 @@ bool ft6336u_read_touch(ft6336u_touch_data_t *data) { return true; } - // Read touch point data (6 bytes per point) + // Read touch point data (6 bytes per point: XH, XL, YH, YL, WEIGHT, MISC) for (int i = 0; i < data->touch_count; i++) { uint8_t reg_base = (i == 0) ? FT6336U_REG_P1_XH : FT6336U_REG_P2_XH; uint8_t buf[6]; - // Retry read if it fails - bool read_success = false; - for (int retry = 0; retry < 3; retry++) { - if (ft6336u_read_regs(reg_base, buf, 6)) { - read_success = true; - break; - } - sleep_us(200); - } - - if (!read_success) { + if (!ft6336u_read_regs(reg_base, buf, 6)) { return false; } @@ -181,7 +190,8 @@ bool ft6336u_read_touch(ft6336u_touch_data_t *data) { uint16_t raw_x = ((buf[0] & 0x0F) << 8) | buf[1]; uint16_t raw_y = ((buf[2] & 0x0F) << 8) | buf[3]; data->points[i].id = (buf[2] >> 4) & 0x0F; - data->points[i].weight = buf[4]; + data->points[i].weight = buf[4]; // Touch pressure/area + data->points[i].misc = (buf[5] >> 4) & 0x0F; // Touch area (upper nibble) // Apply coordinate transformations if (g_config->swap_xy) { @@ -294,3 +304,28 @@ bool ft6336u_test_i2c(void) { return overall; } + +bool ft6336u_set_g_mode(uint8_t mode) { + if (g_config == NULL) return false; + return ft6336u_write_reg(FT6336U_REG_G_MODE, mode); +} + +uint8_t ft6336u_get_g_mode(void) { + if (g_config == NULL) return 0xFF; + + uint8_t g_mode; + if (!ft6336u_read_reg(FT6336U_REG_G_MODE, &g_mode)) { + return 0xFF; + } + return g_mode; +} + +uint8_t ft6336u_get_power_mode(void) { + if (g_config == NULL) return 0xFF; + + uint8_t pwr_mode; + if (!ft6336u_read_reg(FT6336U_REG_POWER_MODE, &pwr_mode)) { + return 0xFF; + } + return pwr_mode; +} diff --git a/lib/ft6336u/ft6336u.c.bak b/lib/ft6336u/ft6336u.c.bak new file mode 100644 index 0000000..b91ea31 --- /dev/null +++ b/lib/ft6336u/ft6336u.c.bak @@ -0,0 +1,296 @@ +/* + * FT6336U Capacitive Touch Screen Driver Implementation + */ + +#include "ft6336u.h" +#include "hardware/gpio.h" +#include +#include + +static const ft6336u_config_t *g_config = NULL; + +// Helper function to write a register +static bool ft6336u_write_reg(uint8_t reg, uint8_t value) { + uint8_t buf[2] = {reg, value}; + int result = i2c_write_blocking(g_config->i2c, FT6336U_ADDR, buf, 2, false); + return result == 2; +} + +// Helper function to read a register +static bool ft6336u_read_reg(uint8_t reg, uint8_t *value) { + int result = i2c_write_blocking(g_config->i2c, FT6336U_ADDR, ®, 1, true); + if (result != 1) { + printf("[FT6336U] I2C write failed: result=%d (expected 1)\n", result); + if (result == PICO_ERROR_GENERIC) printf(" Error: PICO_ERROR_GENERIC\n"); + if (result == PICO_ERROR_TIMEOUT) printf(" Error: PICO_ERROR_TIMEOUT\n"); + return false; + } + + result = i2c_read_blocking(g_config->i2c, FT6336U_ADDR, value, 1, false); + if (result != 1) { + printf("[FT6336U] I2C read failed: result=%d (expected 1)\n", result); + return false; + } + return true; +} + +// Helper function to read multiple registers +static bool ft6336u_read_regs(uint8_t reg, uint8_t *buf, size_t len) { + int result = i2c_write_blocking(g_config->i2c, FT6336U_ADDR, ®, 1, true); + if (result != 1) return false; + + result = i2c_read_blocking(g_config->i2c, FT6336U_ADDR, buf, len, false); + return result == (int)len; +} + +bool ft6336u_init(const ft6336u_config_t *config) { + if (config == NULL) { + printf("[FT6336U] ERROR: config is NULL\n"); + return false; + } + + printf("[FT6336U] Initializing touch controller...\n"); + printf("[FT6336U] Pins: SDA=%d, SCL=%d, RST=%d, INT=%d\n", + config->gpio_sda, config->gpio_scl, config->gpio_rst, config->gpio_int); + + g_config = config; + + // Initialize I2C + printf("[FT6336U] Initializing I2C at 400 kHz...\n"); + uint actual_freq = i2c_init(config->i2c, 400000); // 400 kHz + printf("[FT6336U] I2C actual frequency: %u Hz\n", actual_freq); + + gpio_set_function(config->gpio_sda, GPIO_FUNC_I2C); + gpio_set_function(config->gpio_scl, GPIO_FUNC_I2C); + gpio_pull_up(config->gpio_sda); + gpio_pull_up(config->gpio_scl); + printf("[FT6336U] I2C pins configured\n"); + + // Initialize reset pin + gpio_init(config->gpio_rst); + gpio_set_dir(config->gpio_rst, GPIO_OUT); + printf("[FT6336U] Reset pin configured\n"); + + // Initialize interrupt pin (input with pull-up) + gpio_init(config->gpio_int); + gpio_set_dir(config->gpio_int, GPIO_IN); + gpio_pull_up(config->gpio_int); + printf("[FT6336U] Interrupt pin configured\n"); + + // Reset the touch controller + printf("[FT6336U] Resetting touch controller...\n"); + gpio_put(config->gpio_rst, 0); + sleep_ms(10); + gpio_put(config->gpio_rst, 1); + sleep_ms(300); // Wait for chip to initialize + printf("[FT6336U] Reset complete, reading chip ID...\n"); + + // Verify chip ID + uint8_t chip_id = ft6336u_get_chip_id(); + printf("[FT6336U] Chip ID read attempt 1: 0x%02X (expected 0x64)\n", chip_id); + + if (chip_id != 0x64) { + // Try again - sometimes first read fails + printf("[FT6336U] First read failed, retrying...\n"); + sleep_ms(100); + chip_id = ft6336u_get_chip_id(); + printf("[FT6336U] Chip ID read attempt 2: 0x%02X\n", chip_id); + + if (chip_id != 0x64) { + printf("[FT6336U] ERROR: Invalid chip ID! Check I2C wiring and address.\n"); + printf("[FT6336U] Possible issues:\n"); + printf(" - I2C pins not connected properly\n"); + printf(" - Touch controller not powered\n"); + printf(" - Wrong I2C address (using 0x%02X)\n", FT6336U_ADDR); + printf(" - I2C pull-up resistors missing\n"); + return false; + } + } + + printf("[FT6336U] Chip ID verified successfully!\n"); + + // Set to normal operating mode + printf("[FT6336U] Setting normal operating mode...\n"); + if (!ft6336u_write_reg(FT6336U_REG_DEVICE_MODE, 0x00)) { + printf("[FT6336U] WARNING: Failed to set device mode\n"); + } + + printf("[FT6336U] Initialization complete!\n"); + return true; +} + +bool ft6336u_read_touch(ft6336u_touch_data_t *data) { + if (data == NULL || g_config == NULL) return false; + + memset(data, 0, sizeof(ft6336u_touch_data_t)); + + // Small delay to ensure touch controller is ready + sleep_us(100); + + // Read gesture ID (optional, skip if causing issues) + ft6336u_read_reg(FT6336U_REG_GESTURE_ID, &data->gesture); + + // Read number of touch points - retry on failure + uint8_t td_status; + int retry_count = 3; + bool success = false; + + for (int retry = 0; retry < retry_count; retry++) { + if (ft6336u_read_reg(FT6336U_REG_TD_STATUS, &td_status)) { + success = true; + break; + } + sleep_us(500); // Brief delay before retry + } + + if (!success) { + return false; // Failed after retries + } + + data->touch_count = td_status & 0x0F; + if (data->touch_count > FT6336U_MAX_TOUCH_POINTS) { + data->touch_count = FT6336U_MAX_TOUCH_POINTS; + } + + // If no touches, return early + if (data->touch_count == 0) { + return true; + } + + // Read touch point data (6 bytes per point) + for (int i = 0; i < data->touch_count; i++) { + uint8_t reg_base = (i == 0) ? FT6336U_REG_P1_XH : FT6336U_REG_P2_XH; + uint8_t buf[6]; + + // Retry read if it fails + bool read_success = false; + for (int retry = 0; retry < 3; retry++) { + if (ft6336u_read_regs(reg_base, buf, 6)) { + read_success = true; + break; + } + sleep_us(200); + } + + if (!read_success) { + return false; + } + + // Parse touch point data + data->points[i].event = (buf[0] >> 6) & 0x03; + uint16_t raw_x = ((buf[0] & 0x0F) << 8) | buf[1]; + uint16_t raw_y = ((buf[2] & 0x0F) << 8) | buf[3]; + data->points[i].id = (buf[2] >> 4) & 0x0F; + data->points[i].weight = buf[4]; + + // Apply coordinate transformations + if (g_config->swap_xy) { + uint16_t temp = raw_x; + raw_x = raw_y; + raw_y = temp; + } + + if (g_config->invert_x) { + raw_x = g_config->screen_width - 1 - raw_x; + } + + if (g_config->invert_y) { + raw_y = g_config->screen_height - 1 - raw_y; + } + + data->points[i].x = raw_x; + data->points[i].y = raw_y; + + // Ensure coordinates are within screen bounds + if (data->points[i].x >= g_config->screen_width) { + data->points[i].x = g_config->screen_width - 1; + } + if (data->points[i].y >= g_config->screen_height) { + data->points[i].y = g_config->screen_height - 1; + } + } + + return true; +} + +bool ft6336u_is_touched(void) { + if (g_config == NULL) return false; + + // More reliable: Read TD_STATUS register directly + // INT pin can be unreliable due to timing/noise + uint8_t td_status; + if (!ft6336u_read_reg(FT6336U_REG_TD_STATUS, &td_status)) { + return false; // I2C error, assume not touched + } + + uint8_t touch_count = td_status & 0x0F; + return touch_count > 0; +} + +uint8_t ft6336u_get_chip_id(void) { + if (g_config == NULL) return 0xFF; + + uint8_t chip_id; + if (!ft6336u_read_reg(FT6336U_REG_CHIPID, &chip_id)) { + return 0xFF; + } + return chip_id; +} + +uint8_t ft6336u_get_firmware_version(void) { + if (g_config == NULL) return 0xFF; + + uint8_t fw_ver; + if (!ft6336u_read_reg(FT6336U_REG_FIRMID, &fw_ver)) { + return 0xFF; + } + return fw_ver; +} + +void ft6336u_set_interrupt_callback(void (*callback)(uint gpio, uint32_t events)) { + if (g_config == NULL || callback == NULL) return; + + // Enable interrupt on falling edge (touch detected) + gpio_set_irq_enabled_with_callback(g_config->gpio_int, + GPIO_IRQ_EDGE_FALL, + true, + callback); +} + +bool ft6336u_test_i2c(void) { + if (g_config == NULL) { + printf("[FT6336U] Test failed: not initialized\n"); + return false; + } + + printf("[FT6336U] Testing I2C communication...\n"); + + // Test 1: Read chip ID + uint8_t chip_id = ft6336u_get_chip_id(); + printf(" Chip ID: 0x%02X (expected 0x64) - %s\n", + chip_id, chip_id == 0x64 ? "PASS" : "FAIL"); + + // Test 2: Read firmware version + uint8_t fw_ver = ft6336u_get_firmware_version(); + printf(" Firmware: 0x%02X - %s\n", + fw_ver, fw_ver != 0xFF ? "PASS" : "FAIL"); + + // Test 3: Read TD_STATUS multiple times + int success_count = 0; + const int test_count = 10; + for (int i = 0; i < test_count; i++) { + uint8_t status; + if (ft6336u_read_reg(FT6336U_REG_TD_STATUS, &status)) { + success_count++; + } + sleep_ms(10); + } + printf(" TD_STATUS reads: %d/%d successful - %s\n", + success_count, test_count, + success_count == test_count ? "PASS" : "WARN"); + + bool overall = (chip_id == 0x64) && (fw_ver != 0xFF) && (success_count >= test_count - 2); + printf("[FT6336U] I2C test: %s\n", overall ? "PASS" : "FAIL"); + + return overall; +} diff --git a/lib/ft6336u/ft6336u.h b/lib/ft6336u/ft6336u.h index 3c0b82d..f51400e 100644 --- a/lib/ft6336u/ft6336u.h +++ b/lib/ft6336u/ft6336u.h @@ -38,9 +38,15 @@ extern "C" { #define FT6336U_REG_P2_MISC 0x0E #define FT6336U_REG_CHIPID 0xA3 // Chip ID (should read 0x64) +#define FT6336U_REG_G_MODE 0xA4 // Interrupt mode (polling or trigger) +#define FT6336U_REG_POWER_MODE 0xA5 // Power mode #define FT6336U_REG_FIRMID 0xA6 #define FT6336U_REG_VENDID 0xA8 +// G_MODE values +#define FT6336U_G_MODE_POLLING 0x00 +#define FT6336U_G_MODE_TRIGGER 0x01 + // Touch event types #define FT6336U_EVENT_PRESS_DOWN 0x00 #define FT6336U_EVENT_LIFT_UP 0x01 @@ -56,7 +62,8 @@ typedef struct { uint16_t y; uint8_t event; // Press down, lift up, contact, no event uint8_t id; // Touch point ID - uint8_t weight; // Touch pressure/area + uint8_t weight; // Touch pressure/area (0-255) + uint8_t misc; // Touch area (0-15, upper nibble of MISC register) } ft6336u_touch_point_t; // Touch data structure @@ -124,6 +131,25 @@ void ft6336u_set_interrupt_callback(void (*callback)(uint gpio, uint32_t events) */ bool ft6336u_test_i2c(void); +/** + * Set G_MODE register (polling vs trigger mode) + * @param mode 0 for polling mode, 1 for trigger mode + * @return true if successful + */ +bool ft6336u_set_g_mode(uint8_t mode); + +/** + * Get current G_MODE setting + * @return Current G_MODE value or 0xFF on error + */ +uint8_t ft6336u_get_g_mode(void); + +/** + * Get current power mode + * @return Current power mode or 0xFF on error + */ +uint8_t ft6336u_get_power_mode(void); + #ifdef __cplusplus } #endif diff --git a/lib/sd_card/sd_card.c b/lib/sd_card/sd_card.c index cba2f91..5842765 100644 --- a/lib/sd_card/sd_card.c +++ b/lib/sd_card/sd_card.c @@ -9,6 +9,7 @@ #include #include +static sd_card_config_t g_config_storage; static const sd_card_config_t *g_config = NULL; static sd_card_info_t g_card_info = {0}; @@ -91,7 +92,9 @@ static uint8_t sd_card_send_acmd(uint8_t acmd, uint32_t arg) { bool sd_card_init(const sd_card_config_t *config) { if (config == NULL) return false; - g_config = config; + // Copy config to static storage to avoid dangling pointer + memcpy(&g_config_storage, config, sizeof(sd_card_config_t)); + g_config = &g_config_storage; memset(&g_card_info, 0, sizeof(g_card_info)); // Initialize CS pin (active low) diff --git a/lib/st7796/st7796.c b/lib/st7796/st7796.c index 7cabefc..ccbedb9 100644 --- a/lib/st7796/st7796.c +++ b/lib/st7796/st7796.c @@ -112,7 +112,8 @@ // Global state variables // These hold the current display configuration -static const struct st7796_config *config; // Pin and SPI configuration +static struct st7796_config config_storage; // Static storage for config copy +static const struct st7796_config *config; // Pin and SPI configuration static uint16_t width; // Display width in pixels (e.g., 480) static uint16_t height; // Display height in pixels (e.g., 320) static uint16_t x_offset; // X offset for display alignment (currently 0) @@ -321,7 +322,9 @@ static void set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { * @param h Display height (320 for landscape) */ void st7796_init(const struct st7796_config *c, uint16_t w, uint16_t h) { - config = c; + // Copy config to static storage to avoid dangling pointer + memcpy(&config_storage, c, sizeof(struct st7796_config)); + config = &config_storage; width = w; height = h; @@ -401,10 +404,10 @@ void st7796_init(const struct st7796_config *c, uint16_t w, uint16_t h) { write_command_with_data(ST7796_MADCTL, &data, 1); sleep_ms(10); - // Display Inversion - try OFF first - // Some displays look better with INVON, others with INVOFF - // If colors look wrong, try: write_command(ST7796_INVON); - write_command(ST7796_INVOFF); + // Display Inversion - try ON for displays that need it + // Some displays need INVON, others need INVOFF + // If this doesn't work, try: write_command(ST7796_INVOFF); + write_command(ST7796_INVON); sleep_ms(10); // Normal Display Mode On