touch with abtraction working, SD is not working

This commit is contained in:
Adolfo Reyna
2026-01-28 23:23:49 -05:00
parent adfbef7228
commit d19a2ca639
13 changed files with 756 additions and 209 deletions

201
basic1 copy.cpp Normal file
View File

@@ -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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#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;
}

View File

@@ -98,9 +98,10 @@ 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");
}
@@ -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,45 +126,48 @@ int main()
printf("Entering main touch loop...\n");
while (1) {
// Always sleep to prevent tight loop and allow other operations
sleep_us(100);
// 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);
// Only process if INT pin indicates touch data available
if (int_pin_low) {
uint32_t now = to_ms_since_boot(get_absolute_time());
// Check if enough time has passed since last touch check
// Check if enough time has passed since last touch check (debounce)
if (now - last_touch_time < debounce_ms) {
sleep_ms(1);
//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;
}
bool is_touched = touch && touch->is_touched();
// 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;
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;
// 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,
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
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) {
@@ -178,18 +182,9 @@ int main()
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);
}
}
} 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;

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -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_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

View File

@@ -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"
PICOTOOL="${HOME}/.pico-sdk/picotool/2.2.0-a4/picotool/picotool"
if [ ! -f "${PICOTOOL}" ]; then
if [ ! -f "${PICOTOOL}" ]; then
echo "❌ picotool not found at: ${PICOTOOL}"
exit 1
fi
fi
# Try to load the UF2
"${PICOTOOL}" load "${UF2_FILE}" -fx
# Try to load the UF2
"${PICOTOOL}" load "${UF2_FILE}" -fx
if [ $? -eq 0 ]; then
if [ $? -eq 0 ]; then
echo ""
echo "✓ Successfully flashed to board!"
echo "✓ Board will automatically reboot and run the program"
else
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
fi
echo ""
echo "=========================================="

View File

@@ -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) {

View File

@@ -7,6 +7,7 @@
#include <string.h>
#include <stdio.h>
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) {
// 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, &reg, 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;
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) {
printf("[FT6336U] I2C read failed: result=%d (expected 1)\n", result);
return false;
}
if (result == 1) {
return true;
}
sleep_us(1000); // 1ms delay before retry
}
return false;
}
// Helper function to read multiple registers
static bool ft6336u_read_regs(uint8_t reg, uint8_t *buf, size_t len) {
// Retry up to 3 times
for (int retry = 0; retry < 3; retry++) {
int result = i2c_write_blocking(g_config->i2c, FT6336U_ADDR, &reg, 1, true);
if (result != 1) return false;
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);
return result == (int)len;
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;
}

296
lib/ft6336u/ft6336u.c.bak Normal file
View File

@@ -0,0 +1,296 @@
/*
* FT6336U Capacitive Touch Screen Driver Implementation
*/
#include "ft6336u.h"
#include "hardware/gpio.h"
#include <string.h>
#include <stdio.h>
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, &reg, 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, &reg, 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;
}

View File

@@ -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

View File

@@ -9,6 +9,7 @@
#include <string.h>
#include <stdio.h>
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)

View File

@@ -112,6 +112,7 @@
// Global state variables
// These hold the current display 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)
@@ -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