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,23 +50,11 @@ fi
echo "UF2 file created: ${UF2_FILE}"
echo ""
# Step 2: Flash to board
echo "Step 2: Flashing to board..."
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..."
# 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 ""
read -p "Press Enter when ready..."
PICOTOOL="${HOME}/.pico-sdk/picotool/2.2.0-a4/picotool/picotool"
@@ -74,37 +76,8 @@ case $choice in
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