Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/PR_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ jobs:
env: "esp32-s3-devkitc-1",
partitions: { bootloader_addr: "0x0" },
}
- {
name: "ESP32-S3 - Freenove FNK0104AB",
env: "Freenove-FNK0104AB",
partitions: { bootloader_addr: "0x0" },
}
- {
name: "CoreS3",
env: "m5stack-cores3",
Expand Down
7 changes: 4 additions & 3 deletions boards/Freenove-FNK0104AB/Freenove-FNK0104AB.ini
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,15 @@ build_flags =

-DDEVICE_NAME='"Freenove FNK0104AB"'

; SD Card via SDIO (not SPI)
; SD Card via SDIO (not SPI) — 4-bit mode (SD_MMC_4BIT)
-DUSE_SD_MMC=1
-DSD_MMC_4BIT=1
-DROTATION=1

; =============================================
; RGB LED (WS2812 NeoPixel)
; =============================================
-DRGB_LED=40
-DRGB_LED=42
-DLED_TYPE=WS2812B
-DLED_ORDER=GRB
-DLED_COUNT=1
Expand All @@ -124,7 +125,7 @@ build_flags =
; =============================================
; Battery ADC
; =============================================
-DANALOG_BAT_PIN=8
-DANALOG_BAT_PIN=9
-DANALOG_BAT_MULTIPLIER=2.0f
-DANALOG_BAT_MIN_MV=2500
-DANALOG_BAT_MAX_MV=4200
Expand Down
4 changes: 2 additions & 2 deletions boards/Freenove-FNK0104AB/connections.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ radios/modules.
| Display (ILI9341, SPI) | SCLK 12, MOSI 11, MISO 13, CS 10, DC 46, RST board-reset, BL 45 |
| Touch (FT6336, I2C @0x38) | SDA 16, SCL 15, INT 17, RST 18 |
| SD card | on-board slot (SDMMC) — just insert a microSD |
| RGB LED (WS2812) | 40 |
| RGB LED (WS2812) | 42 |
| Button (Select) | 0 (BOOT) |
| Battery ADC | 8 (x2 divider) |
| Battery ADC | 9 (x2 divider) |

## Free GPIOs (broken-out headers)

Expand Down
42 changes: 34 additions & 8 deletions boards/Freenove-FNK0104AB/interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* - BOOT button (GPIO0)
*/

#include "core/bus_HAL.h"
#include "core/powerSave.h"
#include "core/utils.h"
#include "hal/bright/bright.h"
Expand All @@ -33,6 +34,9 @@
#define PIN_SD_CLK 38
#define PIN_SD_CMD 40
#define PIN_SD_D0 39
#define PIN_SD_D1 41
#define PIN_SD_D2 48
#define PIN_SD_D3 47
#endif

// =============================================
Expand Down Expand Up @@ -84,6 +88,11 @@ void _setup_gpio() {
// ES8311 ADC: clocked off the speaker BCLK, and its LRCLK doubles as the mic WS
// clk,data,ws,type
bruceConfigPins.mic_bus = {(gpio_num_t)5, (gpio_num_t)6, (gpio_num_t)7, MIC_TYPE_I2S_MSB};
// Touch (FT6336G) and the ES8311 codec share this bus. Marking it as sys_i2c
// makes bus_HAL treat it as the shared system bus: releaseI2CBus() then won't
// Wire.end() it (which silently killed touch until reboot) and the wedged-bus
// watchdog in checkAndRecoverSysI2CBus() becomes active.
bruceConfigPins.sys_i2c = {(gpio_num_t)16, (gpio_num_t)15}; // sda, scl
bruceConfigPins.i2c_bus = {(gpio_num_t)16, (gpio_num_t)15}; // sda, scl (Grove)
bruceConfigPins.rfTx = 16;
bruceConfigPins.rfRx = 15;
Expand All @@ -110,10 +119,13 @@ void _setup_gpio() {
#endif

#ifdef USE_SD_MMC
// ---- SD Card (SDIO mode, 1-bit) ----
SD.setPins(PIN_SD_CLK, PIN_SD_CMD, PIN_SD_D0);
// ---- SD Card (SDIO mode, 4-bit) ----
SD.setPins(PIN_SD_CLK, PIN_SD_CMD, PIN_SD_D0, PIN_SD_D1, PIN_SD_D2, PIN_SD_D3);
#endif

// Initialize I2C bus (shared with audio codec ES8311)
setSysI2CBus(&Wire);

// ---- Touch Screen Init (FT6336G) ----
if (!hal_touch_init(touchCfg(), FNK0104AB_TOUCH_ADDR)) { Serial.println("Touch IC not Started"); }

Expand All @@ -128,14 +140,24 @@ void _setup_gpio() {
Serial.begin(115200);
}

/***************************************************************************************
** Function name: _pre_storage_gpio()
** Description: runs right after the first TFT use (tft.init sets TFT_BL as
** output) and before begin_tft() calls setBrightness() for the
** first time. Attaching the backlight PWM here exactly once
** avoids the LEDC "pin already attached"/"no free timers" errors
** caused by attaching again in _post_setup_gpio().
***************************************************************************************/
void _pre_storage_gpio() { hal_bright_attach(TFT_BL); }

/***************************************************************************************
** Function name: _post_setup_gpio()
** Description: second stage gpio setup after TFT is initialized
***************************************************************************************/
void _post_setup_gpio() {
// Backlight control via PWM (must be after TFT init)
hal_bright_attach(TFT_BL);
hal_bright_set(TFT_BL, 100); // Full brightness initially
// PWM channel is attached in _pre_storage_gpio(), just make sure the panel
// does not stay dark until the stored brightness is re-applied by setup().
hal_bright_set(TFT_BL, 100);
}

/*********************************************************************
Expand Down Expand Up @@ -177,11 +199,15 @@ void InputHandler(void) {
** Turns off the device (deep sleep with BOOT button wakeup)
**********************************************************************/
void powerOff() {
// Turn off backlight
hal_bright_set(TFT_BL, 0);
// hal_bright_set(0) only goes down to HalBrightCurve::pwm_min, so drive the
// pin statically to the "off" level to actually extinguish the backlight.
ledcDetach(TFT_BL);
pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON == HIGH ? LOW : HIGH);
// Turn off amplifier
digitalWrite(FNK0104AB_AMP_EN, HIGH);
// Send display to sleep
// Display off, then sleep in
tft.writecommand(0x28); // DISPOFF
tft.writecommand(0x10); // SLPIN
// Wake on BOOT button press
esp_sleep_enable_ext0_wakeup((gpio_num_t)FNK0104AB_BTN_PIN, FNK0104AB_BTN_ACT);
Expand Down
8 changes: 7 additions & 1 deletion src/core/sd_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,13 @@ bool setupSdCard(uint8_t maxFiles) {
if (sdcardMounted) return true;
bool result = true;
#ifdef USE_SD_MMC
if (!SD.begin("/sdcard", true, false, BOARD_MAX_SDMMC_FREQ, maxFiles)) {
// 4-bit SDIO is opt-in per board (define SD_MMC_4BIT); everything else uses 1-bit.
#ifdef SD_MMC_4BIT
constexpr bool sdmmc1Bit = false;
#else
constexpr bool sdmmc1Bit = true;
#endif
if (!SD.begin("/sdcard", sdmmc1Bit, false, BOARD_MAX_SDMMC_FREQ, maxFiles)) {
sdcardMounted = false;
result = false;
}
Expand Down
18 changes: 15 additions & 3 deletions src/core/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,21 @@ int gsetRotation(bool set) {
void setBrightnessMenu() {
returnToMenu = false;

// The slider sits in the middle of the screen, i.e. inside the touch zone
// that touchHeatMap() maps to SelPress. Without this, grabbing the knob
// would set SelPress and the loop would immediately apply + exit. Disable
// body-zone reading while this menu is open (footer zones still work), same
// as loopOptions() does for tap-to-select menus.
bool prevTouchZoneOutsideFooterEnabled = touchZoneOutsideFooterEnabled;
touchZoneOutsideFooterEnabled = false;

int original = bruceConfig.bright;
int val = (bruceConfig.bright / 5) * 5;
if (val > 100) val = 100;
if (val < 0) val = 0;
// Never let the slider reach 0: a saved 0 leaves the screen (almost) dark
// with no visible UI to raise it again, which looks like a freeze. The
// serial CLI already clamps the same way.
if (val < 1) val = 1;

const int lineHeight = FM * LH;
const int hintHeight = FP * LH;
Expand Down Expand Up @@ -195,7 +206,7 @@ void setBrightnessMenu() {
int newVal = ((clampedX - trackX) * 100 + trackW / 2) / trackW;
newVal = (newVal / 5) * 5;
if (newVal > 100) newVal = 100;
if (newVal < 0) newVal = 0;
if (newVal < 1) newVal = 1;
if (newVal != val) {
val = newVal;
redraw = true;
Expand All @@ -211,7 +222,7 @@ void setBrightnessMenu() {
}
if (check(PrevPress)) {
val -= 5;
if (val < 0) val = 0;
if (val < 1) val = 1;
redraw = true;
}
if (check(SelPress)) {
Expand All @@ -224,6 +235,7 @@ void setBrightnessMenu() {
}
vTaskDelay(pdMS_TO_TICKS(1));
}
touchZoneOutsideFooterEnabled = prevTouchZoneOutsideFooterEnabled;
tft.fillScreen(bruceConfig.bgColor);
}

Expand Down
8 changes: 5 additions & 3 deletions src/hal/inputs/touch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,11 @@ bool hal_touch_read(const DeviceTouch &cfg, BruceTouchPoint &out) {
out.x = x;
out.y = y;
out.pressed = true;
#if !defined(TOUCH_CTRL_XPT2046)
touch.reset();
#endif
// Do NOT touch.reset() here: for FT6X36 it toggles the hardware RST pin
// (30 ms low + 160 ms release) on every read. That makes dragging ~190 ms
// per sample and, under sustained polling, can leave the controller wedged
// (touch stops responding while the rest of the firmware keeps running).
// Reading FT6X36_REG_STATUS already clears the interrupt/point latch.
return true;
#elif defined(TOUCH_CTRL_GT911) || defined(TOUCH_CTRL_CST8XX) || defined(TOUCH_CTRL_GT9895) || \
defined(TOUCH_CTRL_HI8561)
Expand Down