Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 047c7c87d7 | |||
| 94b5cdbfc4 |
@@ -2,12 +2,95 @@
|
||||
#include "devices/Display.h"
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <tactility/log.h>
|
||||
#include <tactility/error.h>
|
||||
#include <tactility/freertos/freertos.h>
|
||||
|
||||
#include <Tactility/hal/Configuration.h>
|
||||
|
||||
using namespace tt::hal;
|
||||
|
||||
static constexpr auto* TAG = "ES3C28P";
|
||||
static constexpr uint8_t ES8311_I2C_ADDR = 0x18;
|
||||
|
||||
static error_t initSound(::Device* i2c_controller) {
|
||||
static constexpr uint8_t ENABLED_BULK_DATA[] = {
|
||||
0x00, 0x80, // RESET/CSM POWER ON
|
||||
0x01, 0x3F, // CLOCK_MANAGER/ use MCLK pin (external), all clocks on
|
||||
0x02, 0x00, // CLOCK_MANAGER/ pre_div=1 pre_multi=1 (256x MCLK is correct ratio)
|
||||
0x0D, 0x01, // SYSTEM/ Power up analog circuitry
|
||||
0x12, 0x00, // SYSTEM/ power-up DAC
|
||||
0x13, 0x10, // SYSTEM/ Enable output to HP drive
|
||||
0x32, 0xBF, // DAC/ DAC volume (0xBF == ±0 dB)
|
||||
0x37, 0x08, // DAC/ Bypass DAC equalizer
|
||||
};
|
||||
|
||||
return i2c_controller_write_register_array(
|
||||
i2c_controller,
|
||||
ES8311_I2C_ADDR,
|
||||
ENABLED_BULK_DATA,
|
||||
sizeof(ENABLED_BULK_DATA),
|
||||
pdMS_TO_TICKS(1000)
|
||||
);
|
||||
}
|
||||
|
||||
static error_t initMicrophone(::Device* i2c_controller) {
|
||||
static constexpr uint8_t ENABLED_BULK_DATA[] = {
|
||||
0x00, 0x80, // RESET/CSM POWER ON
|
||||
0x01, 0x3F, // CLOCK_MANAGER/ use MCLK pin (external), all clocks on
|
||||
0x02, 0x00, // CLOCK_MANAGER/ pre_div=1 pre_multi=1
|
||||
0x0D, 0x01, // SYSTEM/ Power up analog circuitry
|
||||
0x0E, 0x02, // SYSTEM/ Enable analog PGA, enable ADC modulator
|
||||
0x14, 0x10, // ADC_REG14: select Mic1p-Mic1n / PGA GAIN (minimum)
|
||||
0x17, 0xFF, // ADC_REG17: ADC_VOLUME (MAXGAIN)
|
||||
0x1C, 0x6A, // ADC_REG1C: ADC Equalizer bypass, cancel DC offset
|
||||
};
|
||||
|
||||
return i2c_controller_write_register_array(
|
||||
i2c_controller,
|
||||
ES8311_I2C_ADDR,
|
||||
ENABLED_BULK_DATA,
|
||||
sizeof(ENABLED_BULK_DATA),
|
||||
pdMS_TO_TICKS(1000)
|
||||
);
|
||||
}
|
||||
|
||||
static bool initBoot() {
|
||||
return driver::pwmbacklight::init(LCD_PIN_BACKLIGHT);
|
||||
// 1. Initialize display backlight
|
||||
if (!driver::pwmbacklight::init(LCD_PIN_BACKLIGHT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. Initialize and power on the FM8002E Audio Amplifier (GPIO 1, Active LOW)
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << GPIO_NUM_1);
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
gpio_config(&io_conf);
|
||||
|
||||
// Drive LOW to enable the speaker amplifier
|
||||
gpio_set_level(GPIO_NUM_1, 0);
|
||||
|
||||
// 3. Configure the ES8311 Codec over the I2C bus
|
||||
auto* i2c_bus = device_find_by_name("i2c0");
|
||||
if (i2c_bus != nullptr) {
|
||||
error_t error = initSound(i2c_bus);
|
||||
if (error != ERROR_NONE) {
|
||||
LOG_E(TAG, "Failed to enable ES8311 speaker: %s", error_to_string(error));
|
||||
}
|
||||
error = initMicrophone(i2c_bus);
|
||||
if (error != ERROR_NONE) {
|
||||
LOG_E(TAG, "Failed to enable ES8311 microphone: %s", error_to_string(error));
|
||||
}
|
||||
} else {
|
||||
LOG_E(TAG, "i2c0 bus not found, skipping ES8311 initialization");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static DeviceVector createDevices() {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <tactility/bindings/esp32_i2c.h>
|
||||
#include <tactility/bindings/esp32_sdmmc.h>
|
||||
#include <tactility/bindings/esp32_spi.h>
|
||||
#include <tactility/bindings/esp32_i2s.h>
|
||||
|
||||
/ {
|
||||
compatible = "root";
|
||||
@@ -28,6 +29,16 @@
|
||||
pin-scl = <&gpio0 15 GPIO_FLAG_NONE>;
|
||||
};
|
||||
|
||||
i2s0 {
|
||||
compatible = "espressif,esp32-i2s";
|
||||
port = <I2S_NUM_0>;
|
||||
pin-bclk = <&gpio0 5 GPIO_FLAG_NONE>;
|
||||
pin-ws = <&gpio0 7 GPIO_FLAG_NONE>;
|
||||
pin-data-out = <&gpio0 6 GPIO_FLAG_NONE>;
|
||||
pin-data-in = <&gpio0 8 GPIO_FLAG_NONE>;
|
||||
pin-mclk = <&gpio0 4 GPIO_FLAG_NONE>;
|
||||
};
|
||||
|
||||
display_spi: spi0 {
|
||||
compatible = "espressif,esp32-spi";
|
||||
host = <SPI2_HOST>;
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
# GameBoy side-loaded ELF support notes
|
||||
|
||||
This branch records the firmware-side changes used to make the Tactility GameBoy emulator prototype load past the generic `missing symbol` failure on an ESP32-S3 ES3C28P board.
|
||||
|
||||
## Problem
|
||||
|
||||
Side-loaded `.app` packages are relocated by the firmware ELF loader. The app can build successfully against the local SDK but still fail at runtime if the board firmware does not export every dynamic symbol used by the app.
|
||||
|
||||
For the GameBoy prototype, USB serial logs showed the emulator app was being found and started, but firmware without the needed LVGL exports showed missing-symbol failures for the canvas path.
|
||||
|
||||
## Firmware changes in this branch
|
||||
|
||||
`TactilityC/Source/tt_init.cpp` now includes LVGL and exports the core LVGL canvas/display functions the GameBoy app needs:
|
||||
|
||||
- `lv_canvas_create`
|
||||
- `lv_canvas_set_buffer`
|
||||
- `lv_obj_invalidate`
|
||||
- `lv_display_get_horizontal_resolution`
|
||||
- `lv_display_get_vertical_resolution`
|
||||
|
||||
These are exported through the existing `main_symbols[]` table with `ESP_ELFSYM_EXPORT(...)`, making them visible to side-loaded ESP32-S3 app ELFs.
|
||||
|
||||
The branch also removes the `AlwaysRun` devicetree delete target from `Firmware/CMakeLists.txt`. During iterative firmware builds this target deleted `Generated/devicetree.c` while compile rules still depended on it, causing intermittent build failures. The devicetree generation rule now depends directly on the source YAML.
|
||||
|
||||
## Verification performed
|
||||
|
||||
On the iMac build host:
|
||||
|
||||
```bash
|
||||
cd ~/Projects/gitea/tactility
|
||||
. ~/esp/esp-idf/export.sh
|
||||
python3 device.py es3c28p
|
||||
idf.py build
|
||||
idf.py -p /dev/ttyACM0 flash
|
||||
```
|
||||
|
||||
Build result:
|
||||
|
||||
```text
|
||||
Tactility.bin binary size 0x2b82b0 bytes
|
||||
Smallest app partition is 0x400000 bytes
|
||||
0x147d50 bytes (32%) free
|
||||
```
|
||||
|
||||
Flash target:
|
||||
|
||||
```text
|
||||
ESP32-S3 ES3C28P
|
||||
USB serial: /dev/ttyACM0
|
||||
MAC: 14:c1:9f:d0:5c:5c
|
||||
```
|
||||
|
||||
Runtime serial showed the GameBoy core loop running and reporting approximately 49-50 FPS:
|
||||
|
||||
```text
|
||||
GAMEBOY_FPS 50
|
||||
GAMEBOY_FPS 49
|
||||
GAMEBOY_FPS 49
|
||||
```
|
||||
|
||||
## Current caveat
|
||||
|
||||
The app loop/FPS is running, but the photographed device showed the GameBoy framebuffer was not visibly rendering yet. That remaining issue is in the app/UI canvas presentation path, not the firmware missing-symbol issue addressed by this branch.
|
||||
|
||||
## Related app work
|
||||
|
||||
The app-side prototype lives in the separate Gitea repo:
|
||||
|
||||
```text
|
||||
https://git.reynafamily.com/adolforeyna/tactility_apps.git
|
||||
```
|
||||
|
||||
The app branch changes include restoring the LVGL canvas path, using `/data/roms/gb/default.gb` for the flashed data-image test, and printing `GAMEBOY_FPS` markers over USB serial.
|
||||
@@ -100,17 +100,13 @@ endif ()
|
||||
#
|
||||
# Devicetree code generation
|
||||
#
|
||||
|
||||
add_custom_target(AlwaysRun
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -f "${GENERATED_DIR}/devicetree.c"
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT "${GENERATED_DIR}/devicetree.c"
|
||||
"${GENERATED_DIR}/devicetree.h"
|
||||
COMMAND python "${CMAKE_SOURCE_DIR}/Buildscripts/DevicetreeCompiler/compile.py"
|
||||
"${DEVICETREE_LOCATION}" "${GENERATED_DIR}"
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
DEPENDS AlwaysRun "${DEVICETREE_LOCATION}/devicetree.yaml" # AlwaysRun ensures it always gets built
|
||||
DEPENDS "${DEVICETREE_LOCATION}/devicetree.yaml"
|
||||
COMMENT "Generating devicetree source files..."
|
||||
)
|
||||
add_custom_target(Generated DEPENDS "${GENERATED_DIR}/devicetree.c")
|
||||
|
||||
@@ -36,9 +36,7 @@ static bool untarFile(minitar* mp, const minitar_entry* entry, const std::string
|
||||
}
|
||||
|
||||
// Note: fchmod() doesn't exist on ESP-IDF and chmod() does nothing on that platform
|
||||
if (chmod(absolute_path.c_str(), entry->metadata.mode) < 0) {
|
||||
return false;
|
||||
}
|
||||
chmod(absolute_path.c_str(), entry->metadata.mode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <esp_netif.h>
|
||||
#include <esp_heap_caps.h>
|
||||
#include <esp_timer.h>
|
||||
#include <lvgl.h>
|
||||
#include <fcntl.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include <lwip/netdb.h>
|
||||
@@ -376,6 +377,13 @@ const esp_elfsym main_symbols[] {
|
||||
// tt::lvgl
|
||||
ESP_ELFSYM_EXPORT(tt_lvgl_spinner_create),
|
||||
|
||||
// LVGL APIs needed by side-loaded apps that render into canvases.
|
||||
ESP_ELFSYM_EXPORT(lv_canvas_create),
|
||||
ESP_ELFSYM_EXPORT(lv_canvas_set_buffer),
|
||||
ESP_ELFSYM_EXPORT(lv_obj_invalidate),
|
||||
ESP_ELFSYM_EXPORT(lv_display_get_horizontal_resolution),
|
||||
ESP_ELFSYM_EXPORT(lv_display_get_vertical_resolution),
|
||||
|
||||
// stdio.h
|
||||
ESP_ELFSYM_EXPORT(rename),
|
||||
ESP_ELFSYM_EXPORT(rewind),
|
||||
|
||||
Reference in New Issue
Block a user