feat: add M5Stack Cardputer ADV board support

Add support for the M5Stack Cardputer ADV hardware variant, which
replaces the original GPIO matrix keyboard with a TCA8418 I2C keypad
controller.

Changes:
- Vendor Adafruit_TCA8418 library for I2C keyboard communication
- Add MARAUDER_CARDPUTER_ADV board target with feature flags in configs.h
- Implement TCA8418 keyboard driver with interrupt-driven FIFO scanning,
  coordinate remapping (verified against M5Cardputer-UserDemo-ADV), and
  persistent key state tracking for compatibility with menu polling
- Extend all MARAUDER_CARDPUTER preprocessor guards to include ADV variant
- Add TFT_eSPI display configuration (same display as original Cardputer)
- Add CI build matrix entries for both parallel and nightly workflows
This commit is contained in:
Adam Benhassen
2026-03-07 21:46:17 +01:00
parent adb4168117
commit 01af8484b1
16 changed files with 1074 additions and 41 deletions

View File

@@ -34,7 +34,8 @@ jobs:
- { name: "Marauder CYD 2432S024 GUITION", flag: "MARAUDER_CYD_GUITION", fbqn: "esp32:esp32:d32:PartitionScheme=min_spiffs", file_name: "cyd_2432S024_guition", tft: true, tft_file: "User_Setup_cyd_guition.h", build_dir: "d32", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" }
- { name: "Marauder CYD 2432S028 2 USB", flag: "MARAUDER_CYD_2USB", fbqn: "esp32:esp32:d32:PartitionScheme=min_spiffs", file_name: "cyd_2432S028_2usb", tft: true, tft_file: "User_Setup_cyd_2usb.h", build_dir: "d32", addr: "0x1000", idf_ver: "3.3.4", nimble_ver: "master", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" }
- { name: "Marauder CYD 3.5inch", flag: "MARAUDER_CYD_3_5_INCH", fbqn: "esp32:esp32:d32:PartitionScheme=min_spiffs", file_name: "cyd_3_5_inch", tft: true, tft_file: "User_Setup_cyd_3_5_inch.h", build_dir: "d32", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" }
- { name: "M5Cardputer", flag: "MARAUDER_CARDPUTER", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer", tft: true, tft_file: "User_Setup_marauder_m5cardputer.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" }
- { name: "M5Cardputer", flag: "MARAUDER_CARDPUTER", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer", tft: true, tft_file: "User_Setup_marauder_m5cardputer.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" }
- { name: "M5Cardputer ADV", flag: "MARAUDER_CARDPUTER_ADV", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer_adv", tft: true, tft_file: "User_Setup_marauder_m5cardputer_adv.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" }
- { name: "ESP32-C5-DevKitC-1", flag: "MARAUDER_C5", fbqn: "esp32:esp32:esp32c5:FlashSize=8M,PartitionScheme=min_spiffs,PSRAM=enabled", file_name: "esp32c5devkitc1", tft: false, tft_file: "", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "master", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" }
steps:
@@ -179,7 +180,10 @@ jobs:
repository: adafruit/Adafruit_MAX1704X
ref: 1.0.2
path: CustomAdafruit_MAX1704X
- name: Install Adafruit_TCA8418
run: cp -r libraries/Adafruit_TCA8418 CustomAdafruit_TCA8418
- name: Show Libraries
run: |
find /home/runner/ -name "Custom*"
@@ -323,6 +327,7 @@ jobs:
| RL Phantom | `_cyd_2432S024_guition.bin` |
| CYD 2432S028 2 USB | `_cyd_2432S028_2usb.bin` |
| M5 Cardputer | `_m5cardputer.bin` (Available on M5 Burner) |
| M5 Cardputer ADV | `_m5cardputer_adv.bin` |
| ESP32-C5 DevKit | [`_esp32c5_devkit.bin`](https://github.com/justcallmekoko/ESP32Marauder/wiki/ESP32%E2%80%90C5%E2%80%90DevKitC%E2%80%901) |
| AWOK V2/V3 screen (white usb) | `_v6_1.bin` |
| AWOK V2 flipper (orange usb) | `_flipper.bin` |

View File

@@ -97,7 +97,8 @@ jobs:
- { name: "Marauder CYD 2432S024 GUITION", flag: "MARAUDER_CYD_GUITION", fbqn: "esp32:esp32:d32:PartitionScheme=min_spiffs", file_name: "cyd_2432S024_guition", tft: true, tft_file: "User_Setup_cyd_guition.h", build_dir: "d32", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" }
- { name: "Marauder CYD 2432S028 2 USB", flag: "MARAUDER_CYD_2USB", fbqn: "esp32:esp32:d32:PartitionScheme=min_spiffs", file_name: "cyd_2432S028_2usb", tft: true, tft_file: "User_Setup_cyd_2usb.h", build_dir: "d32", addr: "0x1000", idf_ver: "3.3.4", nimble_ver: "master", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" }
- { name: "Marauder CYD 3.5inch", flag: "MARAUDER_CYD_3_5_INCH", fbqn: "esp32:esp32:d32:PartitionScheme=min_spiffs", file_name: "cyd_3_5_inch", tft: true, tft_file: "User_Setup_cyd_3_5_inch.h", build_dir: "d32", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" }
- { name: "M5Cardputer", flag: "MARAUDER_CARDPUTER", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer", tft: true, tft_file: "User_Setup_marauder_m5cardputer.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" }
- { name: "M5Cardputer", flag: "MARAUDER_CARDPUTER", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer", tft: true, tft_file: "User_Setup_marauder_m5cardputer.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" }
- { name: "M5Cardputer ADV", flag: "MARAUDER_CARDPUTER_ADV", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer_adv", tft: true, tft_file: "User_Setup_marauder_m5cardputer_adv.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" }
- { name: "ESP32-C5-DevKitC-1", flag: "MARAUDER_C5", fbqn: "esp32:esp32:esp32c5:FlashSize=8M,PartitionScheme=min_spiffs,PSRAM=enabled", file_name: "esp32c5devkitc1", tft: false, tft_file: "", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "master", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" }
steps:
@@ -233,7 +234,10 @@ jobs:
repository: adafruit/Adafruit_MAX1704X
ref: 1.0.2
path: CustomAdafruit_MAX1704X
- name: Install Adafruit_TCA8418
run: cp -r libraries/Adafruit_TCA8418 CustomAdafruit_TCA8418
- name: Show Libraries
run: |
find /home/runner/ -name "Custom*"
@@ -415,6 +419,7 @@ jobs:
| RL Phantom | `_cyd_2432S024_guition.bin` |
| CYD 2432S028 2 USB | `_cyd_2432S028_2usb.bin` |
| M5 Cardputer | `_m5cardputer.bin` (Available on M5 Burner) |
| M5 Cardputer ADV | `_m5cardputer_adv.bin` |
| ESP32-C5 DevKit | [`_esp32c5_devkit.bin`](https://github.com/justcallmekoko/ESP32Marauder/wiki/ESP32%E2%80%90C5%E2%80%90DevKitC%E2%80%901) |
| AWOK V2/V3 screen (white usb) | `_v6_1.bin` |
| AWOK V2 flipper (orange usb) | `_flipper.bin` |

View File

@@ -35,6 +35,7 @@
//#include <User_Setup_cyd_guition.h>
//#include <User_Setup_cyd_2usb.h>
//#include <User_Setup_marauder_m5cardputer.h>
//#include <User_Setup_marauder_m5cardputer_adv.h>
//#include <User_Setup_cyd_3_5_inch.h>
//#include <User_Setups/Setup1_ILI9341.h> // Setup file configured for my ILI9341

View File

@@ -0,0 +1,328 @@
// USER DEFINED SETTINGS
// Set driver type, fonts to be loaded, pins used and SPI control method etc
//
// See the User_Setup_Select.h file if you wish to be able to define multiple
// setups and then easily select which setup file is used by the compiler.
//
// If this file is edited correctly then all the library example sketches should
// run without the need to make any more changes for a particular hardware setup!
// Note that some sketches are designed for a particular TFT pixel width/height
// ##################################################################################
//
// Section 1. Call up the right driver file and any options for it
//
// ##################################################################################
// Display type - only define if RPi display
//#define RPI_DRIVER
#define CGRAM_OFFSET
// Only define one driver, the other ones must be commented out
//#define ILI9341_DRIVER // OG Marauder
//#define ST7735_DRIVER // Marauder Mini // Define additional parameters below for this display
//#define ILI9163_DRIVER // Define additional parameters below for this display
//#define S6D02A1_DRIVER
//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI
//#define HX8357D_DRIVER
//#define ILI9481_DRIVER
//#define ILI9486_DRIVER
//#define ILI9488_DRIVER // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)
//#define ST7789_DRIVER // Full configuration option, define additional parameters below for this display
#define ST7789_2_DRIVER // Minimal configuration option, define additional parameters below for this display
//#define R61581_DRIVER
//#define RM68140_DRIVER
//#define ST7796_DRIVER
// Some displays support SPI reads via the MISO pin, other displays have a single
// bi-directional SDA pin and the library will try to read this via the MOSI line.
// To use the SDA line for reading data from the TFT uncomment the following line:
// #define TFT_SDA_READ // This option is for ESP32 ONLY, tested with ST7789 display only
// For ST7789 and ILI9341 ONLY, define the colour order IF the blue and red are swapped on your display
// Try ONE option at a time to find the correct colour order for your display
#define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue
// #define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red
// For M5Stack ESP32 module with integrated ILI9341 display ONLY, remove // in line below
// #define M5STACK
// For ST7789, ST7735 and ILI9163 ONLY, define the pixel width and height in portrait orientation
// #define TFT_WIDTH 80
#define TFT_WIDTH 135 // Marauder Mini
// #define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320
// #define TFT_HEIGHT 160
#define TFT_HEIGHT 240 // Marauder Mini
// #define TFT_HEIGHT 240 // ST7789 240 x 240
// #define TFT_HEIGHT 320 // ST7789 240 x 320
// For ST7735 ONLY, define the type of display, originally this was based on the
// colour of the tab on the screen protector film but this is not always true, so try
// out the different options below if the screen does not display graphics correctly,
// e.g. colours wrong, mirror images, or tray pixels at the edges.
// Comment out ALL BUT ONE of these options for a ST7735 display driver, save this
// this User_Setup file, then rebuild and upload the sketch to the board again:
// #define ST7735_INITB
// #define ST7735_GREENTAB
// #define ST7735_GREENTAB2
// #define ST7735_GREENTAB3
// #define ST7735_GREENTAB128 // For 128 x 128 display
// #define ST7735_GREENTAB160x80 // For 160 x 80 display (BGR, inverted, 26 offset)
// #define ST7735_REDTAB
// #define ST7735_BLACKTAB
// #define ST7735_REDTAB160x80 // For 160 x 80 display with 24 pixel offset
// If colours are inverted (white shows as black) then uncomment one of the next
// 2 lines try both options, one of the options should correct the inversion.
// #define TFT_INVERSION_ON
// #define TFT_INVERSION_OFF
// If a backlight control signal is available then define the TFT_BL pin in Section 2
// below. The backlight will be turned ON when tft.begin() is called, but the library
// needs to know if the LEDs are ON with the pin HIGH or LOW. If the LEDs are to be
// driven with a PWM signal or turned OFF/ON then this must be handled by the user
// sketch. e.g. with digitalWrite(TFT_BL, LOW);
#define TFT_BACKLIGHT_ON HIGH // HIGH or LOW are options
// ##################################################################################
//
// Section 2. Define the pins that are used to interface with the display here
//
// ##################################################################################
// We must use hardware SPI, a minimum of 3 GPIO pins is needed.
// Typical setup for ESP8266 NodeMCU ESP-12 is :
//
// Display SDO/MISO to NodeMCU pin D6 (or leave disconnected if not reading TFT)
// Display LED to NodeMCU pin VIN (or 5V, see below)
// Display SCK to NodeMCU pin D5
// Display SDI/MOSI to NodeMCU pin D7
// Display DC (RS/AO)to NodeMCU pin D3
// Display RESET to NodeMCU pin D4 (or RST, see below)
// Display CS to NodeMCU pin D8 (or GND, see below)
// Display GND to NodeMCU pin GND (0V)
// Display VCC to NodeMCU 5V or 3.3V
//
// The TFT RESET pin can be connected to the NodeMCU RST pin or 3.3V to free up a control pin
//
// The DC (Data Command) pin may be labeled AO or RS (Register Select)
//
// With some displays such as the ILI9341 the TFT CS pin can be connected to GND if no more
// SPI devices (e.g. an SD Card) are connected, in this case comment out the #define TFT_CS
// line below so it is NOT defined. Other displays such at the ST7735 require the TFT CS pin
// to be toggled during setup, so in these cases the TFT_CS line must be defined and connected.
//
// The NodeMCU D0 pin can be used for RST
//
//
// Note: only some versions of the NodeMCU provide the USB 5V on the VIN pin
// If 5V is not available at a pin you can use 3.3V but backlight brightness
// will be lower.
// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP8266 SETUP ######
// For NodeMCU - use pin numbers in the form PIN_Dx where Dx is the NodeMCU pin designation
//#define TFT_CS PIN_D8 // Chip select control pin D8
//#define TFT_DC PIN_D3 // Data Command control pin
//#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
//#define TFT_BL PIN_D1 // LED back-light (only for ST7789 with backlight control pin)
//#define TOUCH_CS PIN_D2 // Chip select pin (T_CS) of touch screen
//#define TFT_WR PIN_D2 // Write strobe for modified Raspberry Pi TFT only
// ###### FOR ESP8266 OVERLAP MODE EDIT THE PIN NUMBERS IN THE FOLLOWING LINES ######
// Overlap mode shares the ESP8266 FLASH SPI bus with the TFT so has a performance impact
// but saves pins for other functions. It is best not to connect MISO as some displays
// do not tristate that line wjen chip select is high!
// On NodeMCU 1.0 SD0=MISO, SD1=MOSI, CLK=SCLK to connect to TFT in overlap mode
// On NodeMCU V3 S0 =MISO, S1 =MOSI, S2 =SCLK
// In ESP8266 overlap mode the following must be defined
//#define TFT_SPI_OVERLAP
// In ESP8266 overlap mode the TFT chip select MUST connect to pin D3
//#define TFT_CS PIN_D3
//#define TFT_DC PIN_D5 // Data Command control pin
//#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP32 SETUP ######
// For ESP32 Dev board (only tested with ILI9341 display)
// The hardware SPI can be mapped to any pins
// M5 Cardputer ADV
#define TFT_BL 38
#define TFT_RST 33 // Reset pin (could connect to NodeMCU RST, see next line)
#define TFT_DC 34 // Data Command control pin
#define TFT_MOSI 35
#define TFT_SCLK 36
#define TFT_CS 37 // Chip select control pin D8
#define TOUCH_CS -1
// #define TFT_MISO -1
// Display SDO/MISO to NodeMCU pin D6 (or leave disconnected if not reading TFT)
// Display LED to NodeMCU pin VIN (or 5V, see below)
// Display SCK to NodeMCU pin D5
// Display SDI/MOSI to NodeMCU pin D7
// Display DC (RS/AO)to NodeMCU pin D3
// Display RESET to NodeMCU pin D4 (or RST, see below)
// Display CS to NodeMCU pin D8 (or GND, see below)
// Display GND to NodeMCU pin GND (0V)
// Display VCC to NodeMCU 5V or 3.3V
/*
// ESP32 Marauder
#define TFT_MISO 19
#define TFT_MOSI 23
#define TFT_SCLK 18
#define TFT_CS 17 // Chip select control pin
#define TFT_DC 16 // Data Command control pin
#define TFT_RST 5 // Reset pin (could connect to RST pin)
//#define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST
#define TFT_BL 32 // LED back-light (only for ST7789 with backlight control pin)
#define TOUCH_CS 21 // Chip select pin (T_CS) of touch screen
*/
/////////////////////////////
// ESP32 Centauri
/*
#define TFT_MISO 19
#define TFT_MOSI 23
#define TFT_SCLK 18
#define TFT_CS 27 // Chip select control pin
#define TFT_DC 26 // Data Command control pin
#define TFT_RST 5 // Reset pin (could connect to RST pin)
//#define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST
#define TFT_BL 32 // LED back-light (only for ST7789 with backlight control pin)
#define TOUCH_CS 21 // Chip select pin (T_CS) of touch screen
*/
/////////////////////////////
//#define TFT_WR 22 // Write strobe for modified Raspberry Pi TFT only
// For the M5Stack module use these #define lines
//#define TFT_MISO 19
//#define TFT_MOSI 23
//#define TFT_SCLK 18
//#define TFT_CS 14 // Chip select control pin
//#define TFT_DC 27 // Data Command control pin
//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
//#define TFT_BL 32 // LED back-light (required for M5Stack)
// ###### EDIT THE PINs BELOW TO SUIT YOUR ESP32 PARALLEL TFT SETUP ######
// The library supports 8 bit parallel TFTs with the ESP32, the pin
// selection below is compatible with ESP32 boards in UNO format.
// Wemos D32 boards need to be modified, see diagram in Tools folder.
// Only ILI9481 and ILI9341 based displays have been tested!
// Parallel bus is only supported on ESP32
// Uncomment line below to use ESP32 Parallel interface instead of SPI
//#define ESP32_PARALLEL
// The ESP32 and TFT the pins used for testing are:
//#define TFT_CS 33 // Chip select control pin (library pulls permanently low
//#define TFT_DC 15 // Data Command control pin - must use a pin in the range 0-31
//#define TFT_RST 32 // Reset pin, toggles on startup
//#define TFT_WR 4 // Write strobe control pin - must use a pin in the range 0-31
//#define TFT_RD 2 // Read strobe control pin
//#define TFT_D0 12 // Must use pins in the range 0-31 for the data bus
//#define TFT_D1 13 // so a single register write sets/clears all bits.
//#define TFT_D2 26 // Pins can be randomly assigned, this does not affect
//#define TFT_D3 25 // TFT screen update performance.
//#define TFT_D4 17
//#define TFT_D5 16
//#define TFT_D6 27
//#define TFT_D7 14
// ##################################################################################
//
// Section 3. Define the fonts that are to be used here
//
// ##################################################################################
// Comment out the #defines below with // to stop that font being loaded
// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not
// normally necessary. If all fonts are loaded the extra FLASH space required is
// about 17Kbytes. To save FLASH space only enable the fonts you need!
#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
// this will save ~20kbytes of FLASH
#define SMOOTH_FONT
// ##################################################################################
//
// Section 4. Other options
//
// ##################################################################################
// Define the SPI clock frequency, this affects the graphics rendering speed. Too
// fast and the TFT driver will not keep up and display corruption appears.
// With an ILI9341 display 40MHz works OK, 80MHz sometimes fails
// With a ST7735 display more than 27MHz may not work (spurious pixels and lines)
// With an ILI9163 display 27 MHz works OK.
// #define SPI_FREQUENCY 1000000
//#define SPI_FREQUENCY 5000000
// #define SPI_FREQUENCY 10000000
#define SPI_FREQUENCY 20000000
//#define SPI_FREQUENCY 27000000 // Marauder // Actually sets it to 26.67MHz = 80/3
// #define SPI_FREQUENCY 40000000
// #define SPI_FREQUENCY 80000000
// Optional reduced SPI frequency for reading TFT
#define SPI_READ_FREQUENCY 20000000
// The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here:
#define SPI_TOUCH_FREQUENCY 2500000
// The ESP32 has 2 free SPI ports i.e. VSPI and HSPI, the VSPI is the default.
// If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam)
// then uncomment the following line:
//#define USE_HSPI_PORT
// Comment out the following #define if "SPI Transactions" do not need to be
// supported. When commented out the code size will be smaller and sketches will
// run slightly faster, so leave it commented out unless you need it!
// Transaction support is needed to work with SD library but not needed with TFT_SdFat
// Transaction support is required if other SPI devices are connected.
// Transactions are automatically enabled by the library for an ESP32 (to use HAL mutex)
// so changing it here has no effect
// #define SUPPORT_TRANSACTIONS

View File

@@ -1,5 +1,7 @@
#include "Keyboard.h"
#if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
#ifdef MARAUDER_CARDPUTER
#include <driver/gpio.h>
#include <Arduino.h>
@@ -31,9 +33,19 @@ uint8_t Keyboard_Class::_get_input(const std::vector<int> &pinList)
return buffer;
}
#endif
#ifdef MARAUDER_CARDPUTER_ADV
volatile bool Keyboard_Class::_tca_interrupt = false;
void IRAM_ATTR Keyboard_Class::_tca_isr() {
_tca_interrupt = true;
}
#endif
void Keyboard_Class::begin()
{
#ifdef MARAUDER_CARDPUTER
for (auto i : output_list)
{
gpio_reset_pin((gpio_num_t)i);
@@ -50,6 +62,20 @@ void Keyboard_Class::begin()
}
_set_output(output_list, 0);
#elif defined(MARAUDER_CARDPUTER_ADV)
Wire.begin(8, 9); // SDA=GPIO8, SCL=GPIO9
_tca_initialized = _tca8418.begin(TCA8418_DEFAULT_ADDR, &Wire);
if (_tca_initialized) {
_tca8418.matrix(7, 8); // 7 rows x 8 cols
_tca8418.flush();
_tca8418.enableInterrupts();
pinMode(11, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(11), _tca_isr, FALLING);
_tca_interrupt = true; // Force initial scan
} else {
Serial.println("[ERROR] TCA8418 keyboard not found on I2C (addr 0x34)");
}
#endif
}
uint8_t Keyboard_Class::getKey(Point2D_t keyCoor)
@@ -76,6 +102,8 @@ void Keyboard_Class::updateKeyList()
{
_key_list_buffer.clear();
Point2D_t coor;
#ifdef MARAUDER_CARDPUTER
uint8_t input_value = 0;
for (int i = 0; i < 8; i++)
@@ -106,6 +134,63 @@ void Keyboard_Class::updateKeyList()
}
}
}
#elif defined(MARAUDER_CARDPUTER_ADV)
if (!_tca_initialized) return;
// Drain TCA8418 FIFO when interrupt signals new events
if (_tca_interrupt) {
_tca_interrupt = false;
int evt;
while ((evt = _tca8418.getEvent()) != 0) {
// Bit 7 = 1 means key press per TCA8418 datasheet (SCPS162).
// Note: the vendored Adafruit library comments have this backwards.
bool pressed = (evt & 0x80) != 0;
int key = (evt & 0x7F) - 1; // Convert from 1-indexed key code to 0-indexed
if (key < 0 || key >= 70) continue;
// TCA8418 uses 10-column stride internally
int row = key / 10;
int col = key % 10;
if (row >= 7 || col >= 8) continue;
// Remap to match _key_value_map[4][14] coordinate system
coor.x = (row * 2) + (col > 3 ? 1 : 0);
coor.y = col % 4;
if (coor.x >= 14 || coor.y >= 4) continue;
if (pressed) {
// Prevent duplicate tracking (e.g. on missed release event)
bool already = false;
for (auto &k : _tca_pressed_keys) {
if (k.x == coor.x && k.y == coor.y) { already = true; break; }
}
if (!already) _tca_pressed_keys.push_back(coor);
} else {
// Remove released key from tracked state
for (auto it = _tca_pressed_keys.begin(); it != _tca_pressed_keys.end(); ++it) {
if (it->x == coor.x && it->y == coor.y) {
_tca_pressed_keys.erase(it);
break;
}
}
}
}
// Check for FIFO overflow (bit 3) and recover
uint8_t int_stat = _tca8418.readRegister(TCA8418_REG_INT_STAT);
if (int_stat & 0x08) {
_tca8418.flush();
_tca_pressed_keys.clear();
}
// Clear all INT_STAT bits so the INT pin deasserts and can fire again
_tca8418.writeRegister(TCA8418_REG_INT_STAT, 0x0F);
}
// Always populate buffer from currently-held keys
for (auto &k : _tca_pressed_keys) {
_key_list_buffer.push_back(k);
}
#endif
}
uint8_t Keyboard_Class::isPressed()

View File

@@ -5,7 +5,7 @@
#include "configs.h"
#ifdef MARAUDER_CARDPUTER
#if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
/**
* @file keyboard.h
@@ -23,6 +23,11 @@
#include "Keyboard_def.h"
#include "configs.h"
#ifdef MARAUDER_CARDPUTER_ADV
#include <Wire.h>
#include "Adafruit_TCA8418.h"
#endif
struct Chart_t
{
uint8_t value;
@@ -36,10 +41,12 @@ struct Point2D_t
int y;
};
#ifdef MARAUDER_CARDPUTER
const std::vector<int> output_list = {8, 9, 11};
const std::vector<int> input_list = {13, 15, 3, 4, 5, 6, 7};
const Chart_t X_map_chart[7] = {{1, 0, 1}, {2, 2, 3}, {4, 4, 5}, {8, 6, 7}, {16, 8, 9}, {32, 10, 11}, {64, 12, 13}};
#endif
struct KeyValue_t
{
@@ -152,8 +159,17 @@ private:
bool _is_caps_locked;
uint8_t _last_key_size;
#ifdef MARAUDER_CARDPUTER
void _set_output(const std::vector<int> &pinList, uint8_t output);
uint8_t _get_input(const std::vector<int> &pinList);
#endif
#ifdef MARAUDER_CARDPUTER_ADV
Adafruit_TCA8418 _tca8418;
bool _tca_initialized = false;
static volatile bool _tca_interrupt;
static void IRAM_ATTR _tca_isr();
std::vector<Point2D_t> _tca_pressed_keys; // Currently held keys
#endif
public:
const char _ascii_list[95] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p',

View File

@@ -3,7 +3,7 @@
#include "configs.h"
#ifdef MARAUDER_CARDPUTER
#if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
#define SHIFT 0x80

View File

@@ -307,9 +307,9 @@ void MenuFunctions::main(uint32_t currentTime)
#ifdef HAS_BUTTONS
#if (C_BTN >= 0) && !defined(MARAUDER_CARDPUTER)
#if (C_BTN >= 0) && !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV)
bool c_btn_press = c_btn.justPressed();
#elif defined(MARAUDER_CARDPUTER)
#elif defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
bool c_btn_press = this->isKeyPressed('(');
#endif
@@ -651,10 +651,10 @@ void MenuFunctions::main(uint32_t currentTime)
// Don't do this for touch screens
#if !(defined(MARAUDER_V6) || defined(MARAUDER_V6_1) || defined(MARAUDER_CYD_MICRO) || defined(MARAUDER_CYD_GUITION) || defined(MARAUDER_CYD_2USB) || defined(MARAUDER_CYD_3_5_INCH))
#if !defined(MARAUDER_M5STICKC) || defined(MARAUDER_M5STICKCP2)
#if (U_BTN >= 0 || defined(MARAUDER_CARDPUTER))
#if (U_BTN >= 0 || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV))
#if (U_BTN >= 0)
if (u_btn.justPressed()) {
#elif defined(MARAUDER_CARDPUTER)
#elif defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
if (this->isKeyPressed(';')) {
#endif
if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) ||
@@ -722,10 +722,10 @@ void MenuFunctions::main(uint32_t currentTime)
#endif
#endif
#if (D_BTN >= 0 || defined(MARAUDER_CARDPUTER))
#if (D_BTN >= 0 || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV))
#if (D_BTN >= 0)
if (d_btn.justPressed()){
#elif defined(MARAUDER_CARDPUTER)
#elif defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
if (this->isKeyPressed('.')){
#endif
if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) ||
@@ -797,10 +797,10 @@ void MenuFunctions::main(uint32_t currentTime)
}
#endif
#if (R_BTN >= 0 || defined(MARAUDER_CARDPUTER))
#if (R_BTN >= 0 || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV))
#if (R_BTN >= 0)
if (r_btn.justPressed()) {
#elif defined(MARAUDER_CARDPUTER)
#elif defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
if (this->isKeyPressed('/')) {
#endif
if (wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) {
@@ -821,10 +821,10 @@ void MenuFunctions::main(uint32_t currentTime)
}
#endif
#if (L_BTN >= 0 || defined(MARAUDER_CARDPUTER))
#if (L_BTN >= 0 || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV))
#if (L_BTN >= 0)
if (l_btn.justPressed()) {
#elif defined(MARAUDER_CARDPUTER)
#elif defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
if (this->isKeyPressed(',')) {
#endif
if (wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) {
@@ -964,10 +964,10 @@ void MenuFunctions::updateStatusBar()
bool status_changed = false;
#if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER) || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_MINI_V3)
#if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER) || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) || defined(MARAUDER_MINI_V3)
display_obj.tft.setFreeFont(NULL);
#endif
uint16_t the_color;
#ifdef HAS_GPS
@@ -1018,7 +1018,7 @@ void MenuFunctions::updateStatusBar()
if ((current_channel != wifi_scan_obj.old_channel) || (status_changed)) {
wifi_scan_obj.old_channel = current_channel;
#if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER) || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_MINI_V3)
#if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER) || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) || defined(MARAUDER_MINI_V3)
display_obj.tft.fillRect(TFT_WIDTH/4, 0, CHAR_WIDTH * 6, STATUS_BAR_WIDTH, STATUSBAR_COLOR);
#elif defined(HAS_DUAL_BAND)
display_obj.tft.fillRect(50, 0, (CHAR_WIDTH / 2) * 8, STATUS_BAR_WIDTH, STATUSBAR_COLOR);
@@ -1415,7 +1415,7 @@ void MenuFunctions::displaySetting(String key, Menu* menu, int index) {
}
#ifdef MARAUDER_CARDPUTER
#if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
bool MenuFunctions::isKeyPressed(char c)
{
M5CardputerKeyboard.updateKeyList();
@@ -1441,7 +1441,7 @@ void MenuFunctions::RunSetup()
this->disable_touch = false;
#ifdef MARAUDER_CARDPUTER
#if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
M5CardputerKeyboard.begin();
#endif
@@ -2120,7 +2120,7 @@ void MenuFunctions::RunSetup()
//#if (!defined(HAS_ILI9341) && defined(HAS_BUTTONS))
miniKbMenu.parentMenu = &wifiGeneralMenu;
#ifndef MARAUDER_CARDPUTER
#if !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV)
this->addNodes(&miniKbMenu, "a", TFTCYAN, NULL, 0, [this]() {
this->changeMenu(miniKbMenu.parentMenu, true);
});
@@ -3071,7 +3071,7 @@ void MenuFunctions::RunSetup()
#endif
// Add SSID
#ifdef HAS_C && !defined(MARAUDER_CARDPUTER)
#if defined(HAS_C) && !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV)
if (c_btn.justPressed()) {
while (!c_btn.justReleased()) {
c_btn.justPressed(); // Need to continue updating button hold status. My shitty library.
@@ -3097,7 +3097,7 @@ void MenuFunctions::RunSetup()
#endif
#endif
#ifdef MARAUDER_CARDPUTER
#if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
for (int i = 0; i < 95; i++) {
if ((M5CardputerKeyboard._ascii_list[i] != '(') &&
(M5CardputerKeyboard._ascii_list[i] != '`')) {
@@ -3285,12 +3285,12 @@ void MenuFunctions::RunSetup()
display_obj.tft.setTextColor(TFT_ORANGE, TFT_BLACK);
#ifdef HAS_MINI_KB
#ifndef MARAUDER_CARDPUTER
#if !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV)
display_obj.tft.println("U/D - Rem/Add Char");
display_obj.tft.println("L/R - Prev/Nxt Char");
#endif
if (!do_pass) {
#ifdef MARAUDER_CARDPUTER
#if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
display_obj.tft.println("Enter - Save");
display_obj.tft.println("Esc - Exit");
#else
@@ -3299,7 +3299,7 @@ void MenuFunctions::RunSetup()
#endif
}
else {
#ifdef MARAUDER_CARDPUTER
#if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
display_obj.tft.println("Enter - Enter");
#else
display_obj.tft.println("C(Hold) - Enter");

View File

@@ -5,7 +5,7 @@
#include "configs.h"
#ifdef MARAUDER_CARDPUTER
#if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
#include "Keyboard.h"
#endif
@@ -230,7 +230,7 @@ class MenuFunctions
#endif
//#endif
#ifdef MARAUDER_CARDPUTER
#if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
Keyboard_Class M5CardputerKeyboard = Keyboard_Class();
bool isKeyPressed(char c);
#endif

View File

@@ -21,7 +21,7 @@ bool SDInterface::initSD() {
pinMode(SD_CS, OUTPUT);
delay(10);
#if (defined(MARAUDER_M5STICKC)) || (defined(HAS_CYD_TOUCH)) || (defined(MARAUDER_CARDPUTER))
#if (defined(MARAUDER_M5STICKC)) || (defined(HAS_CYD_TOUCH)) || (defined(MARAUDER_CARDPUTER)) || (defined(MARAUDER_CARDPUTER_ADV))
/* Set up SPI SD Card using external pin header
StickCPlus Header - SPI SD Card Reader
3v3 - 3v3
@@ -33,12 +33,12 @@ bool SDInterface::initSD() {
*/
#if defined(MARAUDER_M5STICKC)
enum { SPI_SCK = 0, SPI_MISO = 36, SPI_MOSI = 26 };
#elif defined(HAS_CYD_TOUCH) || defined(MARAUDER_CARDPUTER) || defined(HAS_SEPARATE_SD)
#elif defined(HAS_CYD_TOUCH) || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) || defined(HAS_SEPARATE_SD)
enum { SPI_SCK = SD_SCK, SPI_MISO = SD_MISO, SPI_MOSI = SD_MOSI };
#else
enum { SPI_SCK = 0, SPI_MISO = 36, SPI_MOSI = 26 };
#endif
#ifndef MARAUDER_CARDPUTER
#if !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV)
this->spiExt = new SPIClass();
#else
this->spiExt = new SPIClass(FSPI);

View File

@@ -36,7 +36,7 @@ extern Settings settings_obj;
class SDInterface {
private:
#if (defined(MARAUDER_M5STICKC) || defined(HAS_CYD_TOUCH) || defined(MARAUDER_CARDPUTER))
#if (defined(MARAUDER_M5STICKC) || defined(HAS_CYD_TOUCH) || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV))
SPIClass *spiExt;
#elif defined(HAS_C5_SD)
SPIClass* _spi;

View File

@@ -31,6 +31,7 @@
//#define MARAUDER_CYD_3_5_INCH
//#define MARAUDER_C5
//#define MARAUDER_CARDPUTER
//#define MARAUDER_CARDPUTER_ADV
//#define MARAUDER_V8
//#define MARAUDER_MINI_V3
//#define DUAL_MINI_C5
@@ -61,6 +62,8 @@
#define HARDWARE_NAME "M5Stick-C Plus2"
#elif defined(MARAUDER_CARDPUTER)
#define HARDWARE_NAME "M5 Cardputer"
#elif defined(MARAUDER_CARDPUTER_ADV)
#define HARDWARE_NAME "M5 Cardputer ADV"
#elif defined(MARAUDER_MINI)
#define HARDWARE_NAME "Marauder Mini"
#elif defined(MARAUDER_V7)
@@ -130,7 +133,7 @@
#define HAS_GPS
#endif
#if defined(MARAUDER_CARDPUTER)
#if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
//#define FLIPPER_ZERO_HAT
#define HAS_MINI_KB
//#define HAS_BATTERY
@@ -643,7 +646,7 @@
#define D_PULL true
#endif
#ifdef MARAUDER_CARDPUTER
#if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
#define L_BTN -1
#define C_BTN 0
#define U_BTN -1
@@ -969,7 +972,7 @@
#endif
#ifdef MARAUDER_CARDPUTER
#if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
#define CHAN_PER_PAGE 7
#define SCREEN_CHAR_WIDTH 40
@@ -2230,7 +2233,7 @@
#define BUTTON_PADDING 60
#endif
#ifdef MARAUDER_CARDPUTER
#if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
#define BANNER_TIME 50
#define COMMAND_PREFIX "!"
@@ -2322,7 +2325,7 @@
#define SD_CS -1
#endif
#ifdef MARAUDER_CARDPUTER
#if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
//#define SS 12
#define SD_CS 12
#define SD_SCK 40
@@ -2423,7 +2426,7 @@
// These values are in bytes
#ifdef MARAUDER_M5STICKC
#define MEM_LOWER_LIM 10000
#elif defined(MARAUDER_CARDPUTER)
#elif defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
#define MEM_LOWER_LIM 10000
#elif defined(MARAUDER_MINI)
#define MEM_LOWER_LIM 10000
@@ -2570,7 +2573,7 @@
#define GPS_SERIAL_INDEX 1
#define GPS_TX 33
#define GPS_RX 32
#elif defined(MARAUDER_CARDPUTER)
#elif defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)
#define GPS_SERIAL_INDEX 1
#define GPS_TX 1
#define GPS_RX 2

View File

@@ -314,7 +314,7 @@ void setup()
#endif
#ifdef HAS_SCREEN
#ifndef MARAUDER_CARDPUTER
#if !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV)
display_obj.tft.drawCentreString("ESP32 Marauder", TFT_WIDTH/2, TFT_HEIGHT * 0.33, 1);
display_obj.tft.drawCentreString("JustCallMeKoko", TFT_WIDTH/2, TFT_HEIGHT * 0.5, 1);
display_obj.tft.drawCentreString(display_obj.version_number, TFT_WIDTH/2, TFT_HEIGHT * 0.66, 1);

View File

@@ -0,0 +1,392 @@
/**
* @file Adafruit_TCA8418.cpp
*
* @mainpage I2C Driver for the Adafruit TCA8418 Keypad Matrix / GPIO Expander
* Breakout
*
* @section intro_sec Introduction
*
* I2C Driver for the Adafruit TCA8418 Keypad Matrix / GPIO Expander
* Breakout
*
* This is a library for the Adafruit TCA8418 breakout:
* https://www.adafruit.com/product/XXXX
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing products from
* Adafruit!
*
* @section dependencies Dependencies
* This library depends on the Adafruit BusIO library
*
* @section author Author
*
* Limor Fried (Adafruit Industries)
*
* @section license License
*
* BSD (see license.txt)
*
* @section HISTORY
*
* v1.0 - First release
*/
#include "Arduino.h"
#include "Adafruit_TCA8418.h"
/**
* @brief Instantiates a new TCA8418 class
*/
Adafruit_TCA8418::Adafruit_TCA8418(void) {}
/**
* @brief destructor
*/
Adafruit_TCA8418::~Adafruit_TCA8418(void) {}
/**
* @brief Sets up the hardware and initializes I2C
* @param address The I2C address for the expander
* @param wire The TwoWire object to be used for I2C connections.
* @return True if initialization was successful, otherwise false.
*/
bool Adafruit_TCA8418::begin(uint8_t address, TwoWire *wire) {
if (i2c_dev) {
delete i2c_dev; // remove old interface
}
i2c_dev = new Adafruit_I2CDevice(address, wire);
if (!i2c_dev->begin()) {
return false;
}
// GPIO
// set default all GIO pins to INPUT
writeRegister(TCA8418_REG_GPIO_DIR_1, 0x00);
writeRegister(TCA8418_REG_GPIO_DIR_2, 0x00);
writeRegister(TCA8418_REG_GPIO_DIR_3, 0x00);
// add all pins to key events
writeRegister(TCA8418_REG_GPI_EM_1, 0xFF);
writeRegister(TCA8418_REG_GPI_EM_2, 0xFF);
writeRegister(TCA8418_REG_GPI_EM_3, 0xFF);
// set all pins to FALLING interrupts
writeRegister(TCA8418_REG_GPIO_INT_LVL_1, 0x00);
writeRegister(TCA8418_REG_GPIO_INT_LVL_2, 0x00);
writeRegister(TCA8418_REG_GPIO_INT_LVL_3, 0x00);
// add all pins to interrupts
writeRegister(TCA8418_REG_GPIO_INT_EN_1, 0xFF);
writeRegister(TCA8418_REG_GPIO_INT_EN_2, 0xFF);
writeRegister(TCA8418_REG_GPIO_INT_EN_3, 0xFF);
return true;
}
/**
* @brief configures the size of the keypad matrix.
*
* @param [in] rows number of rows, should be <= 8
* @param [in] columns number of columns, should be <= 10
* @return true is rows and columns have valid values.
*
* @details will always use the lowest pins for rows and columns.
* 0..rows-1 and 0..columns-1
*/
bool Adafruit_TCA8418::matrix(uint8_t rows, uint8_t columns) {
if ((rows > 8) || (columns > 10))
return false;
// MATRIX
// skip zero size matrix
if ((rows != 0) && (columns != 0)) {
// setup the keypad matrix.
uint8_t mask = 0x00;
for (int r = 0; r < rows; r++) {
mask <<= 1;
mask |= 1;
}
writeRegister(TCA8418_REG_KP_GPIO_1, mask);
mask = 0x00;
for (int c = 0; c < columns && c < 8; c++) {
mask <<= 1;
mask |= 1;
}
writeRegister(TCA8418_REG_KP_GPIO_2, mask);
if (columns > 8) {
if (columns == 9)
mask = 0x01;
else
mask = 0x03;
writeRegister(TCA8418_REG_KP_GPIO_3, mask);
}
}
return true;
}
/////////////////////////////////////////////////////////////////////////////
//
// KEY EVENTS
//
/**
* @brief checks if key events are available in the internal buffer
*
* @return number of key events in the buffer
*/
uint8_t Adafruit_TCA8418::available() {
uint8_t eventCount = readRegister(TCA8418_REG_KEY_LCK_EC);
eventCount &= 0x0F; // lower 4 bits only
return eventCount;
}
/**
* @brief gets first event from the internal buffer
*
* @return key event or 0 if none available
*
* @details
* key event 0x00 no event
* 0x01..0x50 key press
* 0x81..0xD0 key release
* 0x5B..0x72 GPIO press
* 0xDB..0xF2 GPIO release
*/
uint8_t Adafruit_TCA8418::getEvent() {
uint8_t event = readRegister(TCA8418_REG_KEY_EVENT_A);
return event;
}
/**
* @brief flushes the internal buffer of key events
* and cleans the GPIO status registers.
*
* @return number of keys flushed.
*/
uint8_t Adafruit_TCA8418::flush() {
// flush key events
uint8_t count = 0;
while (getEvent() != 0)
count++;
// flush gpio events
readRegister(TCA8418_REG_GPIO_INT_STAT_1);
readRegister(TCA8418_REG_GPIO_INT_STAT_2);
readRegister(TCA8418_REG_GPIO_INT_STAT_3);
// clear INT_STAT register
writeRegister(TCA8418_REG_INT_STAT, 3);
return count;
}
/////////////////////////////////////////////////////////////////////////////
//
// GPIO
//
/**
* @brief read GPIO
*
* @param [in] pinnum Pin name between TCA8418_ROW0 and TCA8418_COL9 0..17
* @return 0 = LOW, 1 = HIGH, 0xFF = pinnum out of range
*/
uint8_t Adafruit_TCA8418::digitalRead(uint8_t pinnum) {
if (pinnum > TCA8418_COL9)
return 0xFF;
uint8_t reg = TCA8418_REG_GPIO_DAT_STAT_1 + pinnum / 8;
uint8_t mask = (1 << (pinnum % 8));
// LEVEL 0 = LOW other = HIGH
uint8_t value = readRegister(reg);
if (value & mask)
return HIGH;
return LOW;
}
/**
* @brief set GPIO pin to LOW or HIGH
*
* @param [in] pinnum Pin name between TCA8418_ROW0 and TCA8418_COL9 0..17
* @param [in] level 0 = LOW, all other are HIGH
* @return true if successful
*/
bool Adafruit_TCA8418::digitalWrite(uint8_t pinnum, uint8_t level) {
if (pinnum > TCA8418_COL9)
return false;
uint8_t reg = TCA8418_REG_GPIO_DAT_OUT_1 + pinnum / 8;
uint8_t mask = (1 << (pinnum % 8));
// LEVEL 0 = LOW other = HIGH
uint8_t value = readRegister(reg);
if (level == LOW)
value &= ~mask;
else
value |= mask;
writeRegister(reg, value);
return true;
}
/**
* @brief set mode of GPIO pin to INPUT, INPUT_PULLUP or OUTPUT
*
* @param [in] pinnum Pin name between TCA8418_ROW0 and TCA8418_COL9 0..17
* @param [in] mode INPUT, INPUT_PULLUP or OUTPUT
* @return false if failed.
*/
bool Adafruit_TCA8418::pinMode(uint8_t pinnum, uint8_t mode) {
if (pinnum > TCA8418_COL9)
return false;
// if (mode > INPUT_PULLUP) return false; ?s
uint8_t idx = pinnum / 8;
uint8_t reg = TCA8418_REG_GPIO_DIR_1 + idx;
uint8_t mask = (1 << (pinnum % 8));
// MODE 0 = INPUT 1 = OUTPUT
uint8_t value = readRegister(reg);
if (mode == OUTPUT)
value |= mask;
else
value &= ~mask;
writeRegister(reg, value);
// PULLUP 0 = enabled 1 = disabled
reg = TCA8418_REG_GPIO_PULL_1 + idx;
value = readRegister(reg);
if (mode == INPUT_PULLUP)
value &= ~mask;
else
value |= mask;
writeRegister(reg, value);
return true;
}
/**
* @brief set IRQ mode of GPIO pin to FALLING RISING
*
* @param [in] pinnum Pin name between TCA8418_ROW0 and TCA8418_COL9 0..17
* @param [in] mode IRQ mode FALLING RISING
* @return false if failed.
*/
bool Adafruit_TCA8418::pinIRQMode(uint8_t pinnum, uint8_t mode) {
if (pinnum > TCA8418_COL9)
return false;
if ((mode != RISING) && (mode != FALLING))
return false;
// MODE 0 = FALLING 1 = RISING
uint8_t idx = pinnum / 8;
uint8_t reg = TCA8418_REG_GPIO_INT_LVL_1 + idx;
uint8_t mask = (1 << (pinnum % 8));
uint8_t value = readRegister(reg);
if (mode == RISING)
value |= mask;
else
value &= ~mask;
writeRegister(reg, value);
// ENABLE INTERRUPT
reg = TCA8418_REG_GPIO_INT_EN_1 + idx;
value = readRegister(reg);
value |= mask;
writeRegister(reg, value);
return true;
}
/////////////////////////////////////////////////////////////////////////////
//
// CONFIGURATION
//
/**
* @brief enables key event + GPIO interrupts.
*/
void Adafruit_TCA8418::enableInterrupts() {
uint8_t value = readRegister(TCA8418_REG_CFG);
value |= (TCA8418_REG_CFG_GPI_IEN | TCA8418_REG_CFG_KE_IEN);
writeRegister(TCA8418_REG_CFG, value);
};
/**
* @brief disables key events + GPIO interrupts.
*/
void Adafruit_TCA8418::disableInterrupts() {
uint8_t value = readRegister(TCA8418_REG_CFG);
value &= ~(TCA8418_REG_CFG_GPI_IEN | TCA8418_REG_CFG_KE_IEN);
writeRegister(TCA8418_REG_CFG, value);
};
/**
* @brief enables matrix overflow interrupt.
*/
void Adafruit_TCA8418::enableMatrixOverflow() {
uint8_t value = readRegister(TCA8418_REG_CFG);
value |= TCA8418_REG_CFG_OVR_FLOW_M;
writeRegister(TCA8418_REG_CFG, value);
};
/**
* @brief disables matrix overflow interrupt.
*/
void Adafruit_TCA8418::disableMatrixOverflow() {
uint8_t value = readRegister(TCA8418_REG_CFG);
value &= ~TCA8418_REG_CFG_OVR_FLOW_M;
writeRegister(TCA8418_REG_CFG, value);
};
/**
* @brief enables key debounce.
*/
void Adafruit_TCA8418::enableDebounce() {
writeRegister(TCA8418_REG_DEBOUNCE_DIS_1, 0x00);
writeRegister(TCA8418_REG_DEBOUNCE_DIS_2, 0x00);
writeRegister(TCA8418_REG_DEBOUNCE_DIS_3, 0x00);
}
/**
* @brief disables key debounce.
*/
void Adafruit_TCA8418::disableDebounce() {
writeRegister(TCA8418_REG_DEBOUNCE_DIS_1, 0xFF);
writeRegister(TCA8418_REG_DEBOUNCE_DIS_2, 0xFF);
writeRegister(TCA8418_REG_DEBOUNCE_DIS_3, 0xFF);
}
/////////////////////////////////////////////////////////////////////////////
//
// LOW LEVEL
//
/**
* @brief reads byte value from register
*
* @param [in] reg register address
* @return value from register
*/
uint8_t Adafruit_TCA8418::readRegister(uint8_t reg) {
Adafruit_I2CRegister i2cReg = Adafruit_I2CRegister(i2c_dev, reg);
uint8_t buffer[1] = {0};
i2cReg.read(buffer, 1);
return buffer[0];
}
/**
* @brief write byte value to register
*
* @param [in] reg register address
* @param [in] value
*/
void Adafruit_TCA8418::writeRegister(uint8_t reg, uint8_t value) {
Adafruit_I2CRegister i2cReg = Adafruit_I2CRegister(i2c_dev, reg);
i2cReg.write(value);
}

View File

@@ -0,0 +1,104 @@
/*!
* @file Adafruit_TCA8418.h
*
* I2C Driver for the Adafruit TCA8418 Keypad Matrix / GPIO Expander
*Breakout
*
* This is a library for the Adafruit TCA8418 breakout:
* https://www.adafruit.com/products/4918
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing products from
* Adafruit!
*
*
* BSD license (see license.txt)
*/
#ifndef _ADAFRUIT_TCA8418_H
#define _ADAFRUIT_TCA8418_H
#include "Arduino.h"
#include <Adafruit_I2CDevice.h>
#include <Adafruit_I2CRegister.h>
#include <Adafruit_TCA8418_registers.h>
#define TCA8418_DEFAULT_ADDR 0x34 ///< The default I2C address for our breakout
/** Pin IDs for matrix rows/columns */
enum {
TCA8418_ROW0, // Pin ID for row 0
TCA8418_ROW1, // Pin ID for row 1
TCA8418_ROW2, // Pin ID for row 2
TCA8418_ROW3, // Pin ID for row 3
TCA8418_ROW4, // Pin ID for row 4
TCA8418_ROW5, // Pin ID for row 5
TCA8418_ROW6, // Pin ID for row 6
TCA8418_ROW7, // Pin ID for row 7
TCA8418_COL0, // Pin ID for column 0
TCA8418_COL1, // Pin ID for column 1
TCA8418_COL2, // Pin ID for column 2
TCA8418_COL3, // Pin ID for column 3
TCA8418_COL4, // Pin ID for column 4
TCA8418_COL5, // Pin ID for column 5
TCA8418_COL6, // Pin ID for column 6
TCA8418_COL7, // Pin ID for column 7
TCA8418_COL8, // Pin ID for column 8
TCA8418_COL9 // Pin ID for column 9
};
/*!
* @brief Class that stores state and functions for interacting with
* the TCA8418 I2C GPIO expander
*/
class Adafruit_TCA8418 {
public:
Adafruit_TCA8418();
~Adafruit_TCA8418();
// initialize the TCA8418
bool begin(uint8_t address = TCA8418_DEFAULT_ADDR, TwoWire *wire = &Wire);
// KEY EVENTS
// configure the size of the keypad.
// all other rows and columns are set as inputs.
bool matrix(uint8_t rows, uint8_t columns);
// key events available in the internal FIFO buffer
uint8_t available();
// get one event from the FIFO buffer
// bit 7 indicates press = 0 or release == 1 (mask 0x80)
uint8_t getEvent();
// flush all events in the FIFO buffer + GPIO events
uint8_t flush();
// GPIO
uint8_t digitalRead(uint8_t pinnum);
bool digitalWrite(uint8_t pinnum, uint8_t level);
bool pinMode(uint8_t pinnum, uint8_t mode);
bool pinIRQMode(uint8_t pinnum, uint8_t mode); // MODE FALLING or RISING
// CONFIGURATION
// enable / disable interrupts for matrix and GPI pins
void enableInterrupts();
void disableInterrupts();
// ignore key events when FIFO buffer is full or not.
void enableMatrixOverflow();
void disableMatrixOverflow();
// debounce keys.
void enableDebounce();
void disableDebounce();
// for expert mode
uint8_t readRegister(uint8_t reg);
void writeRegister(uint8_t reg, uint8_t value);
protected:
Adafruit_I2CDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface
};
#endif

View File

@@ -0,0 +1,94 @@
#pragma once
/**
* @file Adafruit_TCA8418_registers.h
*
* I2C Driver for the Adafruit TCA8418 Keypad Matrix / GPIO Expander
*Breakout
*
* This is a library for the Adafruit TCA8418 breakout:
* https://www.adafruit.com/products/4918
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing products from
* Adafruit!
*
*
* BSD license (see license.txt)
*/
// REGISTERS
// #define TCA8418_REG_RESERVED 0x00
#define TCA8418_REG_CFG 0x01 ///< Configuration register
#define TCA8418_REG_INT_STAT 0x02 ///< Interrupt status
#define TCA8418_REG_KEY_LCK_EC 0x03 ///< Key lock and event counter
#define TCA8418_REG_KEY_EVENT_A 0x04 ///< Key event register A
#define TCA8418_REG_KEY_EVENT_B 0x05 ///< Key event register B
#define TCA8418_REG_KEY_EVENT_C 0x06 ///< Key event register C
#define TCA8418_REG_KEY_EVENT_D 0x07 ///< Key event register D
#define TCA8418_REG_KEY_EVENT_E 0x08 ///< Key event register E
#define TCA8418_REG_KEY_EVENT_F 0x09 ///< Key event register F
#define TCA8418_REG_KEY_EVENT_G 0x0A ///< Key event register G
#define TCA8418_REG_KEY_EVENT_H 0x0B ///< Key event register H
#define TCA8418_REG_KEY_EVENT_I 0x0C ///< Key event register I
#define TCA8418_REG_KEY_EVENT_J 0x0D ///< Key event register J
#define TCA8418_REG_KP_LCK_TIMER 0x0E ///< Keypad lock1 to lock2 timer
#define TCA8418_REG_UNLOCK_1 0x0F ///< Unlock register 1
#define TCA8418_REG_UNLOCK_2 0x10 ///< Unlock register 2
#define TCA8418_REG_GPIO_INT_STAT_1 0x11 ///< GPIO interrupt status 1
#define TCA8418_REG_GPIO_INT_STAT_2 0x12 ///< GPIO interrupt status 2
#define TCA8418_REG_GPIO_INT_STAT_3 0x13 ///< GPIO interrupt status 3
#define TCA8418_REG_GPIO_DAT_STAT_1 0x14 ///< GPIO data status 1
#define TCA8418_REG_GPIO_DAT_STAT_2 0x15 ///< GPIO data status 2
#define TCA8418_REG_GPIO_DAT_STAT_3 0x16 ///< GPIO data status 3
#define TCA8418_REG_GPIO_DAT_OUT_1 0x17 ///< GPIO data out 1
#define TCA8418_REG_GPIO_DAT_OUT_2 0x18 ///< GPIO data out 2
#define TCA8418_REG_GPIO_DAT_OUT_3 0x19 ///< GPIO data out 3
#define TCA8418_REG_GPIO_INT_EN_1 0x1A ///< GPIO interrupt enable 1
#define TCA8418_REG_GPIO_INT_EN_2 0x1B ///< GPIO interrupt enable 2
#define TCA8418_REG_GPIO_INT_EN_3 0x1C ///< GPIO interrupt enable 3
#define TCA8418_REG_KP_GPIO_1 0x1D ///< Keypad/GPIO select 1
#define TCA8418_REG_KP_GPIO_2 0x1E ///< Keypad/GPIO select 2
#define TCA8418_REG_KP_GPIO_3 0x1F ///< Keypad/GPIO select 3
#define TCA8418_REG_GPI_EM_1 0x20 ///< GPI event mode 1
#define TCA8418_REG_GPI_EM_2 0x21 ///< GPI event mode 2
#define TCA8418_REG_GPI_EM_3 0x22 ///< GPI event mode 3
#define TCA8418_REG_GPIO_DIR_1 0x23 ///< GPIO data direction 1
#define TCA8418_REG_GPIO_DIR_2 0x24 ///< GPIO data direction 2
#define TCA8418_REG_GPIO_DIR_3 0x25 ///< GPIO data direction 3
#define TCA8418_REG_GPIO_INT_LVL_1 0x26 ///< GPIO edge/level detect 1
#define TCA8418_REG_GPIO_INT_LVL_2 0x27 ///< GPIO edge/level detect 2
#define TCA8418_REG_GPIO_INT_LVL_3 0x28 ///< GPIO edge/level detect 3
#define TCA8418_REG_DEBOUNCE_DIS_1 0x29 ///< Debounce disable 1
#define TCA8418_REG_DEBOUNCE_DIS_2 0x2A ///< Debounce disable 2
#define TCA8418_REG_DEBOUNCE_DIS_3 0x2B ///< Debounce disable 3
#define TCA8418_REG_GPIO_PULL_1 0x2C ///< GPIO pull-up disable 1
#define TCA8418_REG_GPIO_PULL_2 0x2D ///< GPIO pull-up disable 2
#define TCA8418_REG_GPIO_PULL_3 0x2E ///< GPIO pull-up disable 3
// #define TCA8418_REG_RESERVED 0x2F
// FIELDS CONFIG REGISTER 1
#define TCA8418_REG_CFG_AI 0x80 ///< Auto-increment for read/write
#define TCA8418_REG_CFG_GPI_E_CGF 0x40 ///< Event mode config
#define TCA8418_REG_CFG_OVR_FLOW_M 0x20 ///< Overflow mode enable
#define TCA8418_REG_CFG_INT_CFG 0x10 ///< Interrupt config
#define TCA8418_REG_CFG_OVR_FLOW_IEN 0x08 ///< Overflow interrupt enable
#define TCA8418_REG_CFG_K_LCK_IEN 0x04 ///< Keypad lock interrupt enable
#define TCA8418_REG_CFG_GPI_IEN 0x02 ///< GPI interrupt enable
#define TCA8418_REG_CFG_KE_IEN 0x01 ///< Key events interrupt enable
// FIELDS INT_STAT REGISTER 2
#define TCA8418_REG_STAT_CAD_INT 0x10 ///< Ctrl-alt-del seq status
#define TCA8418_REG_STAT_OVR_FLOW_INT 0x08 ///< Overflow interrupt status
#define TCA8418_REG_STAT_K_LCK_INT 0x04 ///< Key lock interrupt status
#define TCA8418_REG_STAT_GPI_INT 0x02 ///< GPI interrupt status
#define TCA8418_REG_STAT_K_INT 0x01 ///< Key events interrupt status
// FIELDS KEY_LCK_EC REGISTER 3
#define TCA8418_REG_LCK_EC_K_LCK_EN 0x40 ///< Key lock enable
#define TCA8418_REG_LCK_EC_LCK_2 0x20 ///< Keypad lock status 2
#define TCA8418_REG_LCK_EC_LCK_1 0x10 ///< Keypad lock status 1
#define TCA8418_REG_LCK_EC_KLEC_3 0x08 ///< Key event count bit 3
#define TCA8418_REG_LCK_EC_KLEC_2 0x04 ///< Key event count bit 2
#define TCA8418_REG_LCK_EC_KLEC_1 0x02 ///< Key event count bit 1
#define TCA8418_REG_LCK_EC_KLEC_0 0x01 ///< Key event count bit 0