touch & sd working
This commit is contained in:
394
basic1.cpp
Normal file
394
basic1.cpp
Normal file
@@ -0,0 +1,394 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/binary_info.h"
|
||||
#include "st7796.h"
|
||||
#include "ft6336u.h"
|
||||
#include "sd_card.h"
|
||||
#include "hardware/spi.h"
|
||||
#include "hardware/i2c.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "low_level_render.h"
|
||||
#include "low_level_gui.h"
|
||||
#include "ff.h" // FatFS
|
||||
|
||||
|
||||
// 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__));
|
||||
|
||||
const int V_WIDTH = 480;
|
||||
const int V_HEIGHT = 320;
|
||||
|
||||
// Feather RP2350 with 4.0" TFT (480x320) ST7796 configuration
|
||||
const struct st7796_config lcd_config = {
|
||||
.spi = spi1,
|
||||
.gpio_din = 11, // MOSI (D11)
|
||||
.gpio_clk = 10, // SCK (D10)
|
||||
.gpio_cs = 7, // CS (D13)
|
||||
.gpio_dc = 4, // DC (D4)
|
||||
.gpio_rst = 9, // RST (D9)
|
||||
.gpio_bl = 6, // Backlight (D6)
|
||||
};
|
||||
|
||||
// Touch screen configuration (adjust pins based on your wiring)
|
||||
// Feather RP2350 I2C pin options:
|
||||
// - I2C0: SDA can be GPIO0,4,8,12,16,20,24,28 / SCL can be GPIO1,5,9,13,17,21,25,29
|
||||
// - I2C1: SDA can be GPIO2,6,10,14,18,22,26 / SCL can be GPIO3,7,11,15,19,23,27
|
||||
// Note: GPIO2/3 are the Feather's default I2C pins (STEMMA QT connector)
|
||||
// Using I2C1 to match GPIO2/3 pins
|
||||
//
|
||||
// Coordinate transformation options - adjust based on your screen orientation:
|
||||
// Try different combinations if touch doesn't align:
|
||||
// swap_xy=false, invert_x=false, invert_y=false (default)
|
||||
// swap_xy=true, invert_x=false, invert_y=false (90° rotation)
|
||||
// swap_xy=false, invert_x=true, invert_y=true (180° rotation)
|
||||
// swap_xy=true, invert_x=true, invert_y=true (270° rotation)
|
||||
const ft6336u_config_t touch_config = {
|
||||
.i2c = i2c1, // Changed to i2c1 to match GPIO2/3
|
||||
.gpio_sda = 2, // SDA (Feather I2C default, valid for I2C1)
|
||||
.gpio_scl = 3, // SCL (Feather I2C default, valid for I2C1)
|
||||
.gpio_rst = 28, // Touch RST (can use any free GPIO)
|
||||
.gpio_int = 25, // Touch INT (can use any free GPIO)
|
||||
.screen_width = V_WIDTH,
|
||||
.screen_height = V_HEIGHT,
|
||||
.swap_xy = true, // Try this first for landscape mode
|
||||
.invert_x = true, // Adjust if X is backwards
|
||||
.invert_y = false // Adjust if Y is backwards
|
||||
};
|
||||
|
||||
// SD Card configuration (shares SPI with display)
|
||||
const sd_card_config_t sd_config = {
|
||||
.spi = spi1, // Same SPI as display
|
||||
.gpio_cs = 5, // SD CS (adjust to your setup)
|
||||
.gpio_miso = 24, // MISO (adjust to your setup)
|
||||
.gpio_mosi = 11, // Same as display MOSI
|
||||
.gpio_sck = 10 // Same as display SCK
|
||||
};
|
||||
|
||||
const int lcd_width = V_WIDTH;
|
||||
const int lcd_height = V_HEIGHT;
|
||||
|
||||
// RGB565 color definitions
|
||||
#define COLOR_BLACK 0x0000
|
||||
#define COLOR_WHITE 0xFFFF
|
||||
#define COLOR_RED 0xF800
|
||||
#define COLOR_GREEN 0x07E0
|
||||
#define COLOR_BLUE 0x001F
|
||||
#define COLOR_YELLOW 0xFFE0
|
||||
#define COLOR_CYAN 0x07FF
|
||||
#define COLOR_MAGENTA 0xF81F
|
||||
#define COLOR_ORANGE 0xFC00
|
||||
#define COLOR_PURPLE 0x8010
|
||||
|
||||
// Touch indicator settings
|
||||
#define TOUCH_RADIUS 10
|
||||
|
||||
uint8_t bit_buffer[V_WIDTH * V_HEIGHT / 8];
|
||||
|
||||
/**
|
||||
* @brief Convert 1-bit buffer to RGB565 and refresh the screen
|
||||
*
|
||||
* Efficiently updates the entire display by:
|
||||
* 1. Converting the 1-bit buffer to RGB565 format
|
||||
* 2. Sending the entire frame in one bulk write operation
|
||||
*
|
||||
* @param buffer Pointer to 1-bit framebuffer (width*height/8 bytes)
|
||||
*/
|
||||
void refresh_screen(const uint8_t *buffer) {
|
||||
// Allocate RGB565 buffer (2 bytes per pixel)
|
||||
uint16_t *rgb_buffer = (uint16_t *)malloc(V_WIDTH * V_HEIGHT * sizeof(uint16_t));
|
||||
if (!rgb_buffer) {
|
||||
printf("Error: Failed to allocate RGB buffer for screen refresh\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert bit buffer to RGB565
|
||||
for (int y = 0; y < V_HEIGHT; y++) {
|
||||
for (int x = 0; x < V_WIDTH; x++) {
|
||||
int byte_index = (y * V_WIDTH + x) / 8;
|
||||
int bit_index = 7 - (x % 8);
|
||||
bool pixel_on = (buffer[byte_index] >> bit_index) & 0x01;
|
||||
rgb_buffer[y * V_WIDTH + x] = pixel_on ? COLOR_WHITE : COLOR_BLACK;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw entire buffer at once - MUCH faster than pixel-by-pixel!
|
||||
st7796_set_cursor(0, 0);
|
||||
st7796_write(rgb_buffer, V_WIDTH * V_HEIGHT);
|
||||
|
||||
free(rgb_buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test SD card and FatFS functionality
|
||||
*
|
||||
* Initializes SD card, mounts FatFS, performs read/write tests,
|
||||
* and safely unmounts the filesystem.
|
||||
*/
|
||||
void test_sd_card_and_fatfs(void) {
|
||||
// Initialize SD card
|
||||
bool sd_ok = sd_card_init(&sd_config);
|
||||
if (!sd_ok) {
|
||||
printf("SD Card initialization failed or no card present\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sd_card_info_t sd_info;
|
||||
sd_card_get_info(&sd_info);
|
||||
printf("SD Card initialized: Type=%d\n", sd_info.type);
|
||||
|
||||
// Try to read first block
|
||||
uint8_t buffer[512];
|
||||
if (sd_card_read_block(0, buffer)) {
|
||||
printf("Read block 0: ");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("%02X ", buffer[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Test FatFS filesystem
|
||||
printf("\n=== FatFS Test ===\n");
|
||||
FATFS fs;
|
||||
FRESULT res = f_mount(&fs, "0:", 1); // Mount drive 0
|
||||
|
||||
if (res != FR_OK) {
|
||||
printf("✗ FatFS mount failed (error: %d)\n", res);
|
||||
printf(" Make sure SD card is formatted as FAT/FAT32\n");
|
||||
printf("==================\n\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("✓ FatFS mounted successfully\n");
|
||||
|
||||
// Get volume information
|
||||
DWORD fre_clust, fre_sect, tot_sect;
|
||||
FATFS *fs_ptr;
|
||||
res = f_getfree("0:", &fre_clust, &fs_ptr);
|
||||
if (res == FR_OK) {
|
||||
tot_sect = (fs_ptr->n_fatent - 2) * fs_ptr->csize;
|
||||
fre_sect = fre_clust * fs_ptr->csize;
|
||||
printf(" Total: %lu KB, Free: %lu KB\n",
|
||||
tot_sect / 2, fre_sect / 2);
|
||||
}
|
||||
|
||||
// List root directory
|
||||
printf("\nRoot directory contents:\n");
|
||||
DIR dir;
|
||||
FILINFO fno;
|
||||
res = f_opendir(&dir, "/");
|
||||
if (res == FR_OK) {
|
||||
int file_count = 0;
|
||||
while (1) {
|
||||
res = f_readdir(&dir, &fno);
|
||||
if (res != FR_OK || fno.fname[0] == 0) break;
|
||||
|
||||
printf(" %s %s (%lu bytes)\n",
|
||||
(fno.fattrib & AM_DIR) ? "[DIR]" : "[FILE]",
|
||||
fno.fname, fno.fsize);
|
||||
file_count++;
|
||||
|
||||
if (file_count >= 10) {
|
||||
printf(" ... (showing first 10 entries)\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
f_closedir(&dir);
|
||||
|
||||
if (file_count == 0) {
|
||||
printf(" (empty)\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Test file write
|
||||
printf("\nTesting file write...\n");
|
||||
FIL fil;
|
||||
res = f_open(&fil, "test.txt", FA_CREATE_ALWAYS | FA_WRITE);
|
||||
if (res == FR_OK) {
|
||||
const char *test_str = "Hello from RP2350 with FatFS!\n";
|
||||
UINT bytes_written;
|
||||
res = f_write(&fil, test_str, strlen(test_str), &bytes_written);
|
||||
f_close(&fil);
|
||||
|
||||
if (res == FR_OK) {
|
||||
printf("✓ Wrote %u bytes to test.txt\n", bytes_written);
|
||||
|
||||
// Read it back
|
||||
res = f_open(&fil, "test.txt", FA_READ);
|
||||
if (res == FR_OK) {
|
||||
char read_buffer[64];
|
||||
UINT bytes_read;
|
||||
res = f_read(&fil, read_buffer, sizeof(read_buffer)-1, &bytes_read);
|
||||
f_close(&fil);
|
||||
|
||||
if (res == FR_OK) {
|
||||
read_buffer[bytes_read] = '\0';
|
||||
printf("✓ Read back: %s", read_buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("✗ Failed to create test.txt (error: %d)\n", res);
|
||||
}
|
||||
|
||||
// Safely unmount filesystem
|
||||
printf("\nUnmounting filesystem...\n");
|
||||
res = f_unmount("0:");
|
||||
if (res == FR_OK) {
|
||||
printf("✓ Filesystem unmounted successfully\n");
|
||||
} else {
|
||||
printf("✗ Unmount failed (error: %d)\n", res);
|
||||
}
|
||||
|
||||
printf("==================\n\n");
|
||||
}
|
||||
|
||||
|
||||
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("Initializing 4.0\" TFT with Touch and SD Card...\n");
|
||||
|
||||
// Initialize the LCD
|
||||
st7796_init(&lcd_config, lcd_width, lcd_height);
|
||||
st7796_fill(COLOR_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);
|
||||
|
||||
// Initialize touch screen
|
||||
bool touch_ok = ft6336u_init(&touch_config);
|
||||
if (touch_ok) {
|
||||
uint8_t chip_id = ft6336u_get_chip_id();
|
||||
uint8_t fw_ver = ft6336u_get_firmware_version();
|
||||
printf("Touch initialized: Chip ID=0x%02X, FW Ver=0x%02X\n", chip_id, fw_ver);
|
||||
|
||||
// Run I2C communication test
|
||||
printf("\nRunning I2C reliability test...\n");
|
||||
ft6336u_test_i2c();
|
||||
printf("\n");
|
||||
} else {
|
||||
printf("Touch initialization failed!\n");
|
||||
}
|
||||
|
||||
// Test SD card and FatFS
|
||||
test_sd_card_and_fatfs();
|
||||
|
||||
// Main loop - handle touch events
|
||||
int last_x = -1, last_y = -1;
|
||||
uint16_t current_color = COLOR_CYAN;
|
||||
int color_index = 0;
|
||||
uint16_t colors[] = {COLOR_CYAN, COLOR_YELLOW, COLOR_MAGENTA, COLOR_GREEN, COLOR_RED};
|
||||
|
||||
// Touch debouncing
|
||||
uint32_t last_touch_time = 0;
|
||||
const uint32_t debounce_ms = 20; // Minimum time between touch reads
|
||||
bool was_touched = false;
|
||||
int touch_fail_count = 0;
|
||||
int touch_success_count = 0;
|
||||
|
||||
printf("Entering main touch loop...\n");
|
||||
|
||||
while (1) {
|
||||
uint32_t now = to_ms_since_boot(get_absolute_time());
|
||||
|
||||
// Check if enough time has passed since last touch check
|
||||
if (now - last_touch_time < debounce_ms) {
|
||||
sleep_ms(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool is_touched = touch_ok && ft6336u_is_touched();
|
||||
|
||||
// Only process touch if state changed or still touching
|
||||
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;
|
||||
|
||||
// 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 change color
|
||||
if (y < 30) {
|
||||
if (!was_touched) { // Only on new touch
|
||||
color_index = (color_index + 1) % 5;
|
||||
current_color = colors[color_index];
|
||||
|
||||
// Clear drawing area
|
||||
st7796_fill_rect(11, 130, lcd_width - 11, lcd_height - 11, COLOR_BLACK);
|
||||
printf("Color changed to index %d\n", color_index);
|
||||
}
|
||||
}
|
||||
// Draw in touch area
|
||||
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) {
|
||||
st7796_draw_line(last_x, last_y, x, y, current_color);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
last_x = -1;
|
||||
last_y = -1;
|
||||
was_touched = false;
|
||||
}
|
||||
}
|
||||
|
||||
sleep_ms(5); // Faster polling for better responsiveness
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user