hardware button support

This commit is contained in:
Adolfo Reyna
2026-01-29 15:23:03 -05:00
parent 1684eb0198
commit 8d0bca691a
7 changed files with 204 additions and 40 deletions

View File

@@ -57,6 +57,8 @@ add_executable(basic1
lib/fatfs/source/ff.c
lib/fatfs/source/ffsystem.c
lib/fatfs/source/ffunicode.c
lib/Pico_ePaper_Code/c/lib/Config/DEV_Config.c
lib/Pico_ePaper_Code/c/lib/e-Paper/EPD_4in2_V2.c
)
pico_set_program_name(basic1 "basic1")
@@ -78,6 +80,8 @@ target_include_directories(basic1 PRIVATE
${CMAKE_CURRENT_LIST_DIR}/lib/ft6336u
${CMAKE_CURRENT_LIST_DIR}/lib/sd_card
${CMAKE_CURRENT_LIST_DIR}/display
${CMAKE_CURRENT_LIST_DIR}/lib/Pico_ePaper_Code/c/lib/Config
${CMAKE_CURRENT_LIST_DIR}/lib/Pico_ePaper_Code/c/lib/e-Paper
)
# Add any user requested libraries

View File

@@ -17,6 +17,7 @@
#include "display/low_level_render.h"
#include "display/low_level_gui.h"
#include "display/low_level_display.h"
#include "display/low_level_display_epaper.h"
#include "display/low_level_touch.h"
@@ -30,6 +31,12 @@ volatile bool touch_interrupt_flag = false;
volatile bool touch_event_down = false;
LowLevelTouch* touch = nullptr;
// Button interrupt handling
#ifdef BUTTON_KEY0_PIN
volatile bool button_key0_pressed = false;
volatile bool button_key1_pressed = false;
#endif
/**
* @brief Touch interrupt callback handler
*
@@ -86,6 +93,35 @@ void touch_interrupt_handler(uint gpio, uint32_t events) {
}
}
#ifdef BUTTON_KEY0_PIN
/**
* @brief Button interrupt callback handler
*
* Called automatically by hardware when button pins change state.
* Buttons are active LOW (pressed = 0, released = 1) with pull-ups.
*
* This runs in interrupt context, so keep it fast - just set flags.
*
* @param gpio GPIO pin number that triggered the interrupt
* @param events Event mask (GPIO_IRQ_EDGE_FALL and/or GPIO_IRQ_EDGE_RISE)
*/
void button_interrupt_handler(uint gpio, uint32_t events) {
// Only respond to falling edge (button press)
if (events & GPIO_IRQ_EDGE_FALL) {
if (gpio == BUTTON_KEY0_PIN) {
button_key0_pressed = true;
printf("Button KEY0 pressed\n");
}
#ifdef BUTTON_KEY1_PIN
else if (gpio == BUTTON_KEY1_PIN) {
button_key1_pressed = true;
printf("Button KEY1 pressed\n");
}
#endif
}
}
#endif
// Screen dimensions and configuration from board_config.h
const int V_WIDTH = DISPLAY_WIDTH;
const int V_HEIGHT = DISPLAY_HEIGHT;
@@ -139,6 +175,20 @@ int main()
return -1;
}
// Do a full refresh with white screen first (removes ghosting on e-paper)
printf("Performing initial full refresh to white...\n");
display->clear(true); // Clear to white
// For e-paper, do a full refresh to ensure clean display
if (display->get_type() == DISPLAY_TYPE_EPAPER) {
LowLevelDisplayEPaper* epaper = static_cast<LowLevelDisplayEPaper*>(display);
epaper->full_refresh(); // Full refresh removes ghosting
printf("Full refresh complete\n");
} else {
refresh_screen(bit_buffer, display); // For TFT, just refresh normally
}
// Now clear to black for drawing
display->clear(false); // Clear to black
LowLevelRenderer renderer(bit_buffer, V_WIDTH, V_HEIGHT);
@@ -173,6 +223,36 @@ int main()
printf("Touch initialization failed or not configured\n");
}
#ifdef BUTTON_KEY0_PIN
// Initialize hardware buttons (e-ink board only)
printf("\nInitializing hardware buttons...\n");
// Initialize KEY0 button
gpio_init(BUTTON_KEY0_PIN);
gpio_set_dir(BUTTON_KEY0_PIN, GPIO_IN);
gpio_pull_up(BUTTON_KEY0_PIN); // Active LOW with pull-up
printf(" KEY0 initialized on GP%d (active LOW)\n", BUTTON_KEY0_PIN);
#ifdef BUTTON_KEY1_PIN
// Initialize KEY1 button
gpio_init(BUTTON_KEY1_PIN);
gpio_set_dir(BUTTON_KEY1_PIN, GPIO_IN);
gpio_pull_up(BUTTON_KEY1_PIN); // Active LOW with pull-up
printf(" KEY1 initialized on GP%d (active LOW)\n", BUTTON_KEY1_PIN);
#endif
// Enable interrupts on falling edge (button press)
gpio_set_irq_enabled_with_callback(BUTTON_KEY0_PIN,
GPIO_IRQ_EDGE_FALL,
true,
&button_interrupt_handler);
#ifdef BUTTON_KEY1_PIN
gpio_set_irq_enabled(BUTTON_KEY1_PIN, GPIO_IRQ_EDGE_FALL, true);
#endif
printf("Button interrupts enabled (falling edge = press)\n");
#endif
// Test SD card and FatFS
// if (sd_card_init_with_board_config()) {
// sd_card_test_fatfs();
@@ -203,6 +283,27 @@ int main()
// Te(); // Wait For Event - CPU sleeps until interrupt or evenurs
__wfi(); // Wait For Interrupt - CPU sleeps until any interrupt
#ifdef BUTTON_KEY0_PIN
// Handle button presses with debouncing
if (button_key0_pressed) {
button_key0_pressed = false;
sleep_ms(50); // Debounce delay
if (gpio_get(BUTTON_KEY0_PIN) == 0) { // Verify button still pressed
printf("Button KEY0 action triggered\n");
// TODO: Add your KEY0 action here (e.g., focus next widget)
}
}
if (button_key1_pressed) {
button_key1_pressed = false;
sleep_ms(50); // Debounce delay
if (gpio_get(BUTTON_KEY1_PIN) == 0) { // Verify button still pressed
printf("Button KEY1 action triggered\n");
// TODO: Add your KEY1 action here (e.g., activate focused widget)
}
}
#endif
// Check if our touch interrupt flag was set
if (!touch_interrupt_flag) {
continue; // Woken by different interrupt, go back to sleep

View File

@@ -16,9 +16,9 @@
// ============================================================================
// ---- SELECT YOUR BOARD HERE ----
#define BOARD_FEATHER_TFT // Feather RP2350 + 4.0" TFT ST7796
// #define BOARD_FEATHER_TFT // Feather RP2350 + 4.0" TFT ST7796
// #define BOARD_PICO2_TFT // Pico 2 + 4.0" TFT ST7796
// #define BOARD_PICO2_EINK // Pico 2 + E-Ink Display
#define BOARD_PICO2_EINK // Pico 2 + E-Ink Display
// --------------------------------
// ============================================================================

View File

@@ -20,33 +20,38 @@
#define TOUCH_INVERT_X false
#define TOUCH_INVERT_Y false
// SPI pins for E-Ink display (using SPI0)
#define DISPLAY_SPI_PORT spi0
#define DISPLAY_SCK_PIN 2 // GP2
#define DISPLAY_MOSI_PIN 3 // GP3
#define DISPLAY_MISO_PIN 4 // GP4 (often not used by e-paper)
#define DISPLAY_CS_PIN 5 // GP5
#define DISPLAY_DC_PIN 6 // GP6 (Data/Command)
#define DISPLAY_RST_PIN 7 // GP7 (Reset)
// SPI pins for E-Ink display (using SPI1)
#define DISPLAY_SPI_PORT spi1
#define DISPLAY_SCK_PIN 10 // GP10
#define DISPLAY_MOSI_PIN 11 // GP11
#define DISPLAY_MISO_PIN 12 // GP12 (often not used by e-paper)
#define DISPLAY_CS_PIN 9 // GP9
#define DISPLAY_DC_PIN 8 // GP8 (Data/Command)
#define DISPLAY_RST_PIN 12 // GP12 (Reset)
#define DISPLAY_BL_PIN 8 // GP8 - Not used for e-ink, but needs valid pin number
#define DISPLAY_BUSY_PIN 9 // GP9 - E-paper BUSY pin (critical!)
#define DISPLAY_BUSY_PIN 13 // GP13 - E-paper BUSY pin (critical!)
// I2C pins for touch (if using touch-enabled e-ink)
// I2C pins for touch (not used - this board has no touch)
// Dummy values to satisfy compilation, but TOUCH_TYPE_NONE means they won't be used
#define TOUCH_I2C_PORT i2c0
#define TOUCH_SDA_PIN 12 // GP12
#define TOUCH_SCL_PIN 13 // GP13
#define TOUCH_INT_PIN 14 // GP14
#define TOUCH_RST_PIN 15 // GP15
// SD card pins (separate SPI1) - optional
// SD card pins (not used - this board has no SD card slot)
// Dummy values to satisfy compilation, but won't be initialized
#define SD_SPI_PORT spi1
#define SD_CS_PIN 17 // GP17
#define SD_CS_PIN 22 // GP22 - dummy value
#define SD_MISO_PIN 16 // GP16
#define SD_MOSI_PIN 19 // GP19
#define SD_SCK_PIN 18 // GP18
// Button pins (Waveshare e-Paper has 2 user buttons)
#define BUTTON_KEY0_PIN 15 // GP15 - User key 0
#define BUTTON_KEY1_PIN 17 // GP17 - User key 1
// Common configuration
#define SPI_BAUDRATE (4 * 1000 * 1000) // 4 MHz for e-paper (slower than TFT)
#define I2C_BAUDRATE (400 * 1000) // 400 kHz for touch
#endif // BOARD_PICO2_EINK_H

View File

@@ -3,8 +3,13 @@
#include <stdlib.h>
#include <string.h>
// Note: This is a placeholder implementation
// You'll need to add the actual e-paper driver code to lib/epaper/
// Waveshare 4.2" e-Paper monochrome driver (supports partial refresh)
extern "C" {
#include "EPD_4in2_V2.h"
#include "DEV_Config.h"
}
// Note: EPD_4IN2_V2 is monochrome (black/white) and supports fast partial refresh
LowLevelDisplayEPaper::LowLevelDisplayEPaper(const epaper_config* cfg, int w, int h)
: config(cfg), width(w), height(h), initialized(false), framebuffer(nullptr), dirty(false) {
@@ -33,11 +38,15 @@ bool LowLevelDisplayEPaper::init() {
return false;
}
// TODO: Implement e-paper initialization
// epaper_init(config, width, height);
printf("E-paper display initialized: %dx%d (stub)\n", width, height);
printf("Initializing Waveshare 4.2\" e-Paper display (%dx%d)...\n", width, height);
// Initialize Waveshare driver (handles GPIO and SPI setup)
DEV_Module_Init();
EPD_4IN2_V2_Init();
printf("E-paper display initialized successfully (partial refresh enabled)\n");
initialized = true;
return false; // Return false until actual driver is implemented
return true;
}
void LowLevelDisplayEPaper::clear(bool white) {
@@ -79,19 +88,56 @@ void LowLevelDisplayEPaper::refresh() {
return;
}
// TODO: Implement actual e-paper refresh
// epaper_update(framebuffer);
printf("E-paper refresh (stub)\n");
if (!initialized) {
printf("E-paper not initialized, cannot refresh\n");
return;
}
printf("Refreshing e-paper display (partial refresh)...\n");
// Use partial refresh for fast updates (~1 second instead of ~15 seconds)
// Partial refresh updates only the changed pixels
EPD_4IN2_V2_PartialDisplay(framebuffer, 0, 0, EPD_4IN2_V2_WIDTH, EPD_4IN2_V2_HEIGHT);
printf("E-paper partial refresh complete\n");
dirty = false;
}
void LowLevelDisplayEPaper::clear_display() {
clear(true); // Fill with white
refresh();
if (!initialized) {
printf("E-paper not initialized, cannot clear\n");
return;
}
printf("Clearing e-paper display...\n");
EPD_4IN2_V2_Clear();
// Also clear framebuffer
clear(true);
dirty = false; // Already refreshed by EPD_4IN2_V2_Clear
}
void LowLevelDisplayEPaper::full_refresh() {
if (!framebuffer || !initialized) {
printf("E-paper not initialized or no framebuffer\n");
return;
}
printf("Performing full refresh (removes ghosting, ~15 seconds)...\n");
// Full refresh uses EPD_4IN2_V2_Display for complete screen update
// This is slower but removes any ghosting from partial refreshes
EPD_4IN2_V2_Display(framebuffer);
printf("Full refresh complete\n");
dirty = false;
}
void LowLevelDisplayEPaper::sleep() {
// TODO: Implement e-paper sleep mode
// epaper_sleep();
if (!initialized) {
return;
}
printf("Putting e-paper display to sleep...\n");
EPD_4IN2_V2_Sleep();
}

View File

@@ -41,8 +41,9 @@ public:
bool is_color() const override { return false; } // Most e-paper is monochrome
// E-paper specific
void clear_display();
void sleep(); // Put display in low power mode
void clear_display(); // Full clear with refresh
void full_refresh(); // Force full screen refresh (slower but removes ghosting)
void sleep(); // Put display in low power mode
};
#endif // LOW_LEVEL_DISPLAY_EPAPER_H

View File

@@ -28,8 +28,10 @@
#
******************************************************************************/
#include "DEV_Config.h"
#include "board_config.h" // Use our board configuration
#define SPI_PORT spi1
// Use SPI port from board config
#define SPI_PORT DISPLAY_SPI_PORT
/**
* GPIO
@@ -90,14 +92,16 @@ void DEV_Delay_ms(UDOUBLE xms)
void DEV_GPIO_Init(void)
{
// Use pin definitions from board_config.h
EPD_RST_PIN = DISPLAY_RST_PIN;
EPD_DC_PIN = DISPLAY_DC_PIN;
EPD_BUSY_PIN = DISPLAY_BUSY_PIN;
EPD_CS_PIN = DISPLAY_CS_PIN;
EPD_CLK_PIN = DISPLAY_SCK_PIN;
EPD_MOSI_PIN = DISPLAY_MOSI_PIN;
EPD_RST_PIN = 12;
EPD_DC_PIN = 8;
EPD_BUSY_PIN = 13;
EPD_CS_PIN = 9;
EPD_CLK_PIN = 10;
EPD_MOSI_PIN = 11;
printf("E-Paper pins: RST=%d, DC=%d, CS=%d, BUSY=%d, CLK=%d, MOSI=%d\r\n",
EPD_RST_PIN, EPD_DC_PIN, EPD_CS_PIN, EPD_BUSY_PIN, EPD_CLK_PIN, EPD_MOSI_PIN);
DEV_GPIO_Mode(EPD_RST_PIN, 1);
DEV_GPIO_Mode(EPD_DC_PIN, 1);
@@ -118,9 +122,12 @@ UBYTE DEV_Module_Init(void)
// GPIO Config
DEV_GPIO_Init();
// Initialize SPI at 4MHz
spi_init(SPI_PORT, 4000 * 1000);
gpio_set_function(EPD_CLK_PIN, GPIO_OUT);
gpio_set_function(EPD_MOSI_PIN, GPIO_OUT);
// Configure SPI pins to use hardware SPI function
gpio_set_function(EPD_CLK_PIN, GPIO_FUNC_SPI);
gpio_set_function(EPD_MOSI_PIN, GPIO_FUNC_SPI);
printf("DEV_Module_Init OK \r\n");
return 0;