
G12 (SDA) and G11 (SCL), and the interrupt pin is G10 (INT).#include <Arduino.h>
#include <M5Faces.h>
#include <M5Unified.h>
namespace {
M5Faces_Gamepad3 gamepad;
void draw_round_button(int x, int y, int w, int h, const char* label, bool pressed)
{
const uint16_t fill = pressed ? TFT_GREEN : TFT_DARKGREY;
const uint16_t text = pressed ? TFT_BLACK : TFT_WHITE;
M5.Display.fillRoundRect(x, y, w, h, 8, fill);
M5.Display.drawRoundRect(x, y, w, h, 8, TFT_WHITE);
M5.Display.setTextColor(text, fill);
M5.Display.drawString(label, x + w / 2, y + h / 2);
}
void draw_circle_button(int x, int y, int radius, const char* label, bool pressed)
{
const uint16_t fill = pressed ? TFT_GREEN : TFT_DARKGREY;
const uint16_t text = pressed ? TFT_BLACK : TFT_WHITE;
M5.Display.fillCircle(x, y, radius, fill);
M5.Display.drawCircle(x, y, radius, TFT_WHITE);
M5.Display.setTextColor(text, fill);
M5.Display.drawString(label, x, y);
}
void draw_gamepad_page()
{
M5.Display.fillScreen(TFT_BLACK);
M5.Display.setTextDatum(middle_center);
M5.Display.setTextColor(TFT_GREEN, TFT_BLACK);
M5.Display.drawString("Faces Gamepad3", M5.Display.width() / 2, 16);
// Symmetric D-pad layout.
draw_round_button(60, 51, 40, 34, "^", gamepad.isButtonPressed(GAMEPAD3_BTN_UP));
draw_round_button(20, 91, 40, 34, "<", gamepad.isButtonPressed(GAMEPAD3_BTN_LEFT));
draw_round_button(100, 91, 40, 34, ">", gamepad.isButtonPressed(GAMEPAD3_BTN_RIGHT));
draw_round_button(60, 131, 40, 34, "v", gamepad.isButtonPressed(GAMEPAD3_BTN_DOWN));
// Action buttons on the right.
draw_circle_button(246, 70, 22, "A", gamepad.isButtonPressed(GAMEPAD3_BTN_A));
draw_circle_button(204, 108, 22, "B", gamepad.isButtonPressed(GAMEPAD3_BTN_B));
// SELECT and START are centered as a pair.
draw_round_button(60, 176, 90, 34, "SELECT", gamepad.isButtonPressed(GAMEPAD3_BTN_SELECT));
draw_round_button(170, 176, 90, 34, "START", gamepad.isButtonPressed(GAMEPAD3_BTN_START));
}
void draw_error()
{
M5.Display.fillScreen(TFT_BLACK);
M5.Display.setTextDatum(middle_center);
M5.Display.setTextColor(TFT_GREEN, TFT_BLACK);
M5.Display.drawString("Faces Gamepad3", M5.Display.width() / 2, 80);
M5.Display.setTextColor(TFT_RED, TFT_BLACK);
M5.Display.drawString("init failed", M5.Display.width() / 2, 120);
}
} // namespace
void setup()
{
Serial.begin(115200);
auto config = M5.config();
config.fallback_board = m5::board_t::board_M5StackCoreS3;
M5.begin(config);
if (!M5.In_I2C.isEnabled()) {
const int sda = M5.getPin(m5::pin_name_t::in_i2c_sda);
const int scl = M5.getPin(m5::pin_name_t::in_i2c_scl);
M5.In_I2C.begin(I2C_NUM_1, sda, scl);
}
M5.Display.setRotation(1);
M5.Display.setTextColor(TFT_GREEN, TFT_BLACK);
M5.Display.setFont(&fonts::FreeMonoBold12pt7b);
M5.Display.setTextSize(1);
M5.Display.setTextWrap(false);
M5.Display.setTextScroll(false);
if (gamepad.begin(&M5.In_I2C) != M5FACES_OK) {
Serial.println("Gamepad3 init failed");
draw_error();
return;
}
Serial.println("Gamepad3 ready");
draw_gamepad_page();
}
void loop()
{
if (gamepad.update()) {
const uint8_t raw = gamepad.getState().raw;
char buttons[64] = {};
M5Faces_Gamepad3::gamepad3_code_parse(raw, buttons, sizeof(buttons));
Serial.printf("Gamepad3 raw=0x%02X buttons=%s\n", raw, buttons[0] ? buttons : "NONE");
draw_gamepad_page();
}
delay(5);
}In Arduino IDE, select the board and port for CoreS3, then click "Verify" to compile the program. After compilation succeeds, click "Upload" to flash it to CoreS3. When the upload is complete, open the Serial Monitor to view the output.