Adding environment setup and instructions

This commit is contained in:
Brent Perteet
2025-07-22 14:04:27 -05:00
parent 311981ceb4
commit dc2885e02e
23 changed files with 3741 additions and 114 deletions

View File

@@ -35,7 +35,8 @@
"semphr.h": "c", "semphr.h": "c",
"lv_spinbox.h": "c", "lv_spinbox.h": "c",
"lv_slider.h": "c", "lv_slider.h": "c",
"lv_menu.h": "c" "lv_menu.h": "c",
"stream_buffer.h": "c"
}, },
"git.ignoreLimitWarning": true "git.ignoreLimitWarning": true
} }

211
README.md Normal file
View File

@@ -0,0 +1,211 @@
## 🐳 ESP-IDF Dockerized Development Environment (Windows)
This project includes a fully containerized [ESP-IDF](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/index.html) development environment using **Docker** and **Visual Studio Code**.
Follow these instructions to set up, build, and flash the firmware inside a VS Code **Dev Container** on **Windows**.
---
### ✅ Prerequisites
Ensure the following are installed on your system:
1. [**Docker Desktop for Windows**](https://www.docker.com/products/docker-desktop)
* Enable **WSL 2 backend** during installation.
2. [**Visual Studio Code**](https://code.visualstudio.com/)
3. [**Dev Containers Extension**](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
* In VS Code: `Extensions → Search "Dev Containers" → Install`
4. [**Espressif IDF Extension** for VS Code](https://marketplace.visualstudio.com/items?itemName=espressif.esp-idf-extension)
* In VS Code: `Extensions → Search "ESP-IDF" → Install`
> 💡 **Optional (recommended):** Install [WSL 2 with Ubuntu](https://learn.microsoft.com/en-us/windows/wsl/install) for improved Linux compatibility inside Docker.
---
### 🚀 Getting Started
#### 1. Clone this repository
```bash
git clone https://git.sparksoftdesign.com/firstpass/soundshot.git
cd soundshot
```
---
You can also clone with TortoiseGit or VS Code directly.
#### 2. Open in Visual Studio Code
From the project root:
```bash
code .
```
> Ensure you're opening the folder that contains `.devcontainer/`.
---
#### 3. Reopen in Dev Container
In VS Code:
* Press `F1` or `Ctrl+Shift+P`
* Run: **Dev Containers: Reopen in Container**
VS Code will:
* Build the Docker image (based on the provided `Dockerfile`)
* Set up the ESP-IDF environment
* Install extensions automatically
---
#### 4. Verify Environment
Once setup is complete:
* A terminal should launch inside the container
* Run:
```bash
idf.py --version
```
to confirm ESP-IDF is active and available.
---
#### 5. Build the Firmware
Inside the containers terminal:
```bash
idf.py build
```
You should see standard ESP-IDF build output and a `.bin` firmware file in the `build/` directory.
---
## 🛠️ ESP32 Programming Setup & Workflow Guide
This project provides a fully portable development and flashing toolchain for ESP32, using Python scripts and configuration-driven workflows.
---
### 📦 1. Environment Setup
> Run once after cloning the repo (Windows only)
```bash
setup-env.bat
```
This:
* Creates a `.venv` virtual environment
* Installs required Python packages (`esptool`, `pyserial`, etc.)
* Prepares the tooling for flashing and monitoring
---
### ⚙️ 2. Configure `settings.json`
Customize `settings.json` in the project root:
```json
{
"project_name": "soundshot",
"chip": "esp32",
"port": "COM3",
"baud": 460800,
"flash_mode": "dio",
"flash_freq": "48m",
"flash_size": "2MB",
"before": "default-reset",
"after": "hard-reset"
}
```
This controls:
* Flashing chip type and parameters
* Serial monitor settings
* Build artifact naming
---
### 🚀 3. Flashing the Firmware
After building your firmware (e.g. via VS Code + Dev Container):
```bash
build/
├── bootloader/bootloader.bin
├── soundshot.bin ← ← ← (project_name)
├── partition_table/partition-table.bin
```
Run the flash tool:
```bash
flash.bat
```
This:
* Loads `settings.json`
* Verifies all required binaries
* Calls `esptool.py` with all correct arguments and offsets
---
### 🛰 4. Monitoring Serial Output
To view device output:
```bash
monitor.bat
```
Features:
* Uses `pyserial`
* Displays real-time output from the ESP32
* Preserves color formatting (if enabled in firmware)
* Cleanly exits with `Ctrl+C` (no "Terminate batch job" prompts)
> Tip: Run `idf.py menuconfig` and enable
> `Component config → Log output → Enable color log output`
---
### ✅ Workflow Summary
| Action | Tool | Command |
| ------------------ | ------------------- | ----------------- |
| Install tooling | `setup-env.bat` | `setup-env.bat` |
| Flash device | `flash.py` script | `flash.bat` |
| Monitor logs | `monitor.py` script | `monitor.bat` |
| Configure behavior | `settings.json` | *(edit manually)* |
---
### 🧰 Notes
* The ESP-IDF version is pinned in the Dockerfile (e.g., `espressif/idf:v5.2.1`)
* The container automatically runs `source $IDF_PATH/export.sh` to prepare the environment.
* VS Code extensions (`.devcontainer.json`) include:
* `ms-vscode.cpptools`
* `ms-vscode.cmake-tools`
* `espressif.esp-idf-extension`
---
### 🛠 Troubleshooting
* If `idf.py` is not found, make sure the container terminal sources `export.sh`

22
flash.bat Normal file
View File

@@ -0,0 +1,22 @@
@echo off
REM =============================================
REM Flash ESP32 using Python script + settings.json
REM =============================================
REM Check for venv
IF NOT EXIST .venv\Scripts\python.exe (
echo [ERROR] Python virtual environment not found at .venv\
echo Run setup-env.bat first.
pause
exit /b 1
)
REM Activate venv and run flash.py
call .venv\Scripts\activate.bat
echo [INFO] Flashing firmware using flash.py and settings.json...
python flash_tool\flash.py
REM Pause to view output
echo.
pause

60
flash_tool/flash.py Normal file
View File

@@ -0,0 +1,60 @@
import json
import subprocess
import sys
from pathlib import Path
def main():
root = Path(__file__).resolve().parent.parent
config_file = root / "settings.json"
if not config_file.exists():
print(f"[ERROR] settings.json not found at {config_file}")
sys.exit(1)
with open(config_file) as f:
cfg = json.load(f)
project = cfg["project_name"]
chip = cfg.get("chip", "esp32")
port = cfg.get("port", "COM3")
baud = cfg.get("flash_baud", 460800)
flash_mode = cfg.get("flash_mode", "dio")
flash_freq = cfg.get("flash_freq", "40m")
flash_size = cfg.get("flash_size", "4MB")
before = cfg.get("before", "default_reset")
after = cfg.get("after", "hard_reset")
# Define binaries and offsets
bootloader = root / "build" / "bootloader" / "bootloader.bin"
firmware = root / "build" / f"{project}.bin"
partition = root / "build" / "partition_table" / "partition-table.bin"
# Verify binaries exist
for f in [bootloader, firmware, partition]:
if not f.exists():
print(f"[ERROR] File not found: {f}")
sys.exit(1)
# Build esptool command
cmd = [
sys.executable, "-m", "esptool",
"--chip", chip,
"--port", port,
"--baud", str(baud),
"--before", before,
"--after", after,
"write-flash", # ✅ hyphenated command
"--flash-mode", flash_mode, # ✅ hyphenated flags
"--flash-freq", flash_freq,
"--flash-size", flash_size,
"0x0", str(bootloader),
"0x10000", str(firmware),
"0x8000", str(partition)
]
print(f"[Flashing] Running: {' '.join(cmd)}")
subprocess.run(cmd, check=True)
if __name__ == "__main__":
main()

45
flash_tool/monitor.py Normal file
View File

@@ -0,0 +1,45 @@
import json
import serial
import sys
import time
from pathlib import Path
# import colorama
# colorama.just_fix_windows_console()
print("\x1b[0;32mThis should be green\x1b[0m")
print("\x1b[0;31mThis should be red\x1b[0m")
def main():
# Load config
root = Path(__file__).resolve().parent.parent
config_file = root / "settings.json"
if not config_file.exists():
print(f"Error: settings.json not found at {config_file}")
sys.exit(1)
with open(config_file) as f:
cfg = json.load(f)
port = cfg.get("port", "COM3")
baud = cfg.get("monitor_baud", 115200)
print(f"[Serial Monitor] Connecting to {port} at {baud} baud...")
try:
with serial.Serial(port, baud, timeout=0.5) as ser:
print("[Serial Monitor] Press Ctrl+C to exit.\n")
while True:
if ser.in_waiting:
line = ser.readline().decode(errors="replace")
if line:
print(line, end="")
time.sleep(0.01)
except KeyboardInterrupt:
print("\n[Serial Monitor] Disconnected.")
except serial.SerialException as e:
print(f"[Error] Could not open serial port {port}: {e}")
sys.exit(1)
if __name__ == "__main__":
main()

14
flashmon.bat Normal file
View File

@@ -0,0 +1,14 @@
@echo off
REM =============================================
REM ESP32 Serial Monitor using settings.json
REM =============================================
IF NOT EXIST .venv\Scripts\python.exe (
echo [ERROR] .venv not found. Run setup-env.bat first.
pause
exit /b 1
)
call .venv\Scripts\activate.bat
python flash_tool\flash.py
python flash_tool\monitor.py

View File

@@ -1,5 +1,5 @@
idf_component_register(SRCS "system.c" "bubble.c" "keypad.c" "main.c" idf_component_register(SRCS "bt_app.c" "system.c" "bubble.c" "keypad.c" "main.c"
"bt_app_core.c"
"gui.c" "gui.c"
"lsm6dsv.c" "lsm6dsv.c"
INCLUDE_DIRS "." INCLUDE_DIRS "."

View File

@@ -12,9 +12,11 @@
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/queue.h" #include "freertos/queue.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "freertos/stream_buffer.h"
#include "esp_log.h" #include "esp_log.h"
#include "bt_app_core.h" #include "bt_app.h"
#include "system.h"
#include "esp_bt.h" #include "esp_bt.h"
#include "esp_bt_main.h" #include "esp_bt_main.h"
@@ -368,18 +370,215 @@ static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
bt_app_work_dispatch(bt_app_av_sm_hdlr, event, param, sizeof(esp_a2d_cb_param_t), NULL); bt_app_work_dispatch(bt_app_av_sm_hdlr, event, param, sizeof(esp_a2d_cb_param_t), NULL);
} }
static uint8_t btData[512];
static void fillBuffer(uint8_t *data, int32_t len)
{
#define SAMPLE_RATE 44100
#define TONE_FREQ 440.0f // A4
#define FADE_FREQ 1.0f // 1 Hz fade L->R
#define STREAM_BUF_SIZE (8192)
#define CHUNK_SIZE (512)
StreamBufferHandle_t audio_stream_buf;
void generate_synth_pcm(uint8_t *buf, int len) {
static float phase = 0.0f;
static float fade_phase = 0.0f;
int16_t *samples = (int16_t *)buf;
int samples_needed = len / 4; // 4 bytes per stereo frame (2 bytes L, 2 bytes R)
for (int i = 0; i < samples_needed; i++) {
// Fade L/R amplitude: 0..1 for L, inverted for R
float fade = (sinf(2 * M_PI * fade_phase) + 1.0f) * 0.5f;
// Sine wave sample
float sample = sinf(2 * M_PI * phase);
int16_t left = (int16_t)(sample * fade * 32767);
int16_t right = (int16_t)(sample * (1.0f - fade) * 32767);
samples[i * 2 + 0] = left;
samples[i * 2 + 1] = right;
// Advance phases
phase += TONE_FREQ / SAMPLE_RATE;
if (phase >= 1.0f) phase -= 1.0f;
fade_phase += FADE_FREQ / SAMPLE_RATE;
if (fade_phase >= 1.0f) fade_phase -= 1.0f;
}
} }
#define MIN_RATE_HZ 1.0f
#define MAX_RATE_HZ 440.0f
#define CLICK_AMPLITUDE 32000 // 16-bit
static float click_timer = 0.0f;
void generate_synth_clicks(uint8_t *buf, int len, float balance) {
int16_t *samples = (int16_t *)buf;
int samples_needed = len / 4;
float abs_balance = fabsf(balance);
float rate_hz = MIN_RATE_HZ * powf(MAX_RATE_HZ / MIN_RATE_HZ, abs_balance);
float samples_per_click = SAMPLE_RATE / rate_hz;
for (int i = 0; i < samples_needed; i++) {
int16_t left = 0;
int16_t right = 0;
if (click_timer <= 0.0f) {
// Insert a short pulse: single sample spike
if (balance < 0) {
left = CLICK_AMPLITUDE;
} else if (balance > 0) {
right = CLICK_AMPLITUDE;
}
click_timer += samples_per_click;
}
click_timer -= 1.0f;
samples[i * 2 + 0] = left;
samples[i * 2 + 1] = right;
}
}
void audio_producer_task(void *pvParameters) {
uint8_t chunk[CHUNK_SIZE];
int core_id = xPortGetCoreID();
ESP_LOGI("Producer", "Running on core %d", core_id);
system_subscribe(xTaskGetCurrentTaskHandle());
#if 0
while (1) {
generate_synth_pcm(chunk, sizeof(chunk));
size_t sent = xStreamBufferSend(audio_stream_buf, chunk, sizeof(chunk), portMAX_DELAY);
if (sent < sizeof(chunk)) {
ESP_LOGW(BT_APP_CORE_TAG, "Dropped %d bytes", sizeof(chunk) - sent);
}
}
#endif
static float phase = 0.0f;
float balance = 0.0f; // -1.0 = left, +1.0 = right
uint32_t raw_value;
uint32_t notifiedBits = 0;
while (1) {
// Non-blocking check for new notification:
// clear on entry (first param), wait for any bit, block forever
xTaskNotifyWait(
0, // clear any old bits on entry
0, // clear bits on exit
&notifiedBits,
0);
if (notifiedBits & EM_EVENT_NEW_DATA)
{
ImuData_t d = system_getImuData();
if (fabs(d.raw[system_getPrimaryAxis()]) > 45.0f)
{
balance = 0.0f;
}
else
{
balance = -d.angle / MAX_INDICATION_ANGLE;
}
}
if (balance > 1.0f)
{
balance = 1.0f;
}
else
if (balance < -1.0f)
{
balance = -1.0f;
}
generate_synth_clicks(chunk, sizeof(chunk), balance);
#if 0
// Synthesize audio using latest balance
int16_t *samples = (int16_t *)chunk;
int samples_needed = CHUNK_SIZE / 4;
for (int i = 0; i < samples_needed; i++) {
float sample = sinf(2 * M_PI * phase);
float left_gain = 0.5f * (1.0f - balance);
float right_gain = 0.5f * (1.0f + balance);
int16_t left = (int16_t)(sample * left_gain * 32767);
int16_t right = (int16_t)(sample * right_gain * 32767);
samples[i * 2 + 0] = left;
samples[i * 2 + 1] = right;
phase += TONE_FREQ / SAMPLE_RATE;
if (phase >= 1.0f) phase -= 1.0f;
}
#endif
// Push chunk to FIFO
xStreamBufferSend(audio_stream_buf, chunk, sizeof(chunk), portMAX_DELAY);
}
}
/* generate some random noise to simulate source audio */
static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
{
size_t bytes_read = xStreamBufferReceive(audio_stream_buf, data, len, 0);
if (bytes_read < len) {
memset(data + bytes_read, 0, len - bytes_read); // fill silence
}
return len;
#if 0
if (data == NULL || len < 0) {
return 0;
}
int16_t *p_buf = (int16_t *)data;
for (int i = 0; i < (len >> 1); i++) {
p_buf[i] = rand() % (1 << 16);
}
return len;
#endif
}
#if 0
/* Generate a continuous 440Hz sine wave */ /* Generate a continuous 440Hz sine wave */
static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len) static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
{ {
static double phase = 0.0;
if (data == NULL || len < 0) {
return 0;
}
int16_t *p_buf = (int16_t *)data;
for (int i = 0; i < (len >> 1); i++) {
p_buf[i] = rand() % (1 << 16);
}
return len;
#if 0
static double phase = 0.0;
const double frequency = 440.0; // A4 tone (440 Hz) const double frequency = 440.0; // A4 tone (440 Hz)
const double sample_rate = 44100.0; // 44.1 kHz sample rate const double sample_rate = 44100.0; // 44.1 kHz sample rate
const double phase_increment = 2.0 * M_PI * frequency / sample_rate; const double phase_increment = 2.0 * M_PI * frequency / sample_rate;
@@ -406,7 +605,9 @@ static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
} }
} }
return len; return len;
#endif
} }
#endif
static void bt_app_a2d_heart_beat(TimerHandle_t arg) static void bt_app_a2d_heart_beat(TimerHandle_t arg)
{ {
@@ -551,6 +752,7 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
} }
case APP_AV_MEDIA_STATE_STARTED: { case APP_AV_MEDIA_STATE_STARTED: {
if (event == BT_APP_HEART_BEAT_EVT) { if (event == BT_APP_HEART_BEAT_EVT) {
#if 0
/* stop media after 10 heart beat intervals */ /* stop media after 10 heart beat intervals */
if (++s_intv_cnt >= 10) { if (++s_intv_cnt >= 10) {
ESP_LOGI(BT_AV_TAG, "a2dp media suspending..."); ESP_LOGI(BT_AV_TAG, "a2dp media suspending...");
@@ -558,6 +760,7 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
s_media_state = APP_AV_MEDIA_STATE_STOPPING; s_media_state = APP_AV_MEDIA_STATE_STOPPING;
s_intv_cnt = 0; s_intv_cnt = 0;
} }
#endif
} }
break; break;
} }
@@ -791,6 +994,10 @@ static void bt_app_task_handler(void *arg)
{ {
bt_app_msg_t msg; bt_app_msg_t msg;
int core_id = xPortGetCoreID();
ESP_LOGI("MY_TASK", "Running on core %d", core_id);
for (;;) { for (;;) {
/* receive message from work queue and handle it */ /* receive message from work queue and handle it */
if (pdTRUE == xQueueReceive(s_bt_app_task_queue, &msg, (TickType_t)portMAX_DELAY)) { if (pdTRUE == xQueueReceive(s_bt_app_task_queue, &msg, (TickType_t)portMAX_DELAY)) {
@@ -846,7 +1053,9 @@ bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, i
void bt_app_task_start_up(void) void bt_app_task_start_up(void)
{ {
s_bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t)); s_bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
xTaskCreate(bt_app_task_handler, "BtAppTask", 4096, NULL, 10, &s_bt_app_task_handle); //xTaskCreate(bt_app_task_handler, "BtAppTask", 8192, NULL, 10, &s_bt_app_task_handle);
xTaskCreatePinnedToCore(bt_app_task_handler, "BtAppTask", 8192, NULL, 10, NULL, 1);
} }
void bt_app_task_shut_down(void) void bt_app_task_shut_down(void)
@@ -867,7 +1076,27 @@ void bt_app_init(void)
esp_err_t ret; esp_err_t ret;
char bda_str[18] = {0}; char bda_str[18] = {0};
fillBuffer(btData, 512);
//esp_err_t esp_bredr_tx_power_get(esp_power_level_t *min_power_level, esp_power_level_t *max_power_level)
esp_power_level_t pmin;
esp_power_level_t pmax;
esp_bredr_tx_power_get(&pmin, &pmax);
ESP_LOGI(BT_APP_CORE_TAG, "BT Power min = %d\nBT Power max = %d", pmin, pmax);
//pmin = ESP_PWR_LVL_P6;
//pmax = ESP_PWR_LVL_P7;
pmin = ESP_PWR_LVL_N12;
pmax = ESP_PWR_LVL_N9;
esp_err_t err = esp_bredr_tx_power_set(pmin, pmax);
if (err != ESP_OK) {
ESP_LOGE(BT_APP_CORE_TAG, "Failed to set TX power: %s", esp_err_to_name(err));
}
esp_bredr_tx_power_get(&pmin, &pmax);
ESP_LOGI(BT_APP_CORE_TAG, "BT Power min = %d\nBT Power max = %d", pmin, pmax);
/* /*
* This example only uses the functions of Classical Bluetooth. * This example only uses the functions of Classical Bluetooth.
@@ -885,6 +1114,10 @@ void bt_app_init(void)
return; return;
} }
err = esp_bredr_tx_power_set(pmin, pmax);
if (err != ESP_OK) {
ESP_LOGE(BT_APP_CORE_TAG, "Failed to set TX power: %s", esp_err_to_name(err));
}
esp_bluedroid_config_t bluedroid_cfg = BT_BLUEDROID_INIT_CONFIG_DEFAULT(); esp_bluedroid_config_t bluedroid_cfg = BT_BLUEDROID_INIT_CONFIG_DEFAULT();
#if (CONFIG_EXAMPLE_SSP_ENABLED == false) #if (CONFIG_EXAMPLE_SSP_ENABLED == false)
bluedroid_cfg.ssp_en = false; bluedroid_cfg.ssp_en = false;
@@ -918,4 +1151,19 @@ void bt_app_init(void)
bt_app_task_start_up(); bt_app_task_start_up();
/* Bluetooth device name, connection mode and profile set up */ /* Bluetooth device name, connection mode and profile set up */
bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_STACK_UP_EVT, NULL, 0, NULL); bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_STACK_UP_EVT, NULL, 0, NULL);
audio_stream_buf = xStreamBufferCreate(STREAM_BUF_SIZE, 1);
assert(audio_stream_buf != NULL);
//xTaskCreate(audio_producer_task, "audio_producer", 4096, NULL, 5, NULL);
xTaskCreatePinnedToCore(audio_producer_task, "audio_producer", 4096, NULL, 5, NULL, 1);
ESP_LOGI(BT_APP_CORE_TAG, "Audio synth producer started");
vTaskDelay(pdMS_TO_TICKS(1000));
} }

View File

@@ -5,6 +5,7 @@
#define PIN_NUM_BUTTON_0 36 #define PIN_NUM_BUTTON_0 36
#define PIN_NUM_BUTTON_1 39 #define PIN_NUM_BUTTON_1 39
#define PIN_NUM_LED_1 32 #define PIN_NUM_LED_1 32
#define PIN_NUM_LED_2 33
#define PIN_NUM_nON 26 #define PIN_NUM_nON 26

View File

@@ -105,9 +105,9 @@ static void create_lvgl_demo(void)
lvgl_port_lock(0); lvgl_port_lock(0);
// Create a screen with black background // Create a screen with black background
lv_obj_t *scr = lv_scr_act(); lv_obj_t *scr = lv_scr_act();
//create_menu(scr);
createBubble(scr); createBubble(scr);
build_scrollable_menu(); //build_scrollable_menu();
lvgl_port_unlock(); lvgl_port_unlock();
@@ -167,8 +167,8 @@ static void lvgl_init(void)
#if 1 #if 1
const lvgl_port_cfg_t lvgl_cfg = { const lvgl_port_cfg_t lvgl_cfg = {
.task_priority = 4, // LVGL task priority .task_priority = 4, // LVGL task priority
.task_stack = 32768, // LVGL task stack size .task_stack = 16384, // LVGL task stack size
.task_affinity = -1, // LVGL task can run on any core .task_affinity = 0, // LVGL task can run on any core
.task_max_sleep_ms = 500, // Maximum sleep in LVGL task .task_max_sleep_ms = 500, // Maximum sleep in LVGL task
.timer_period_ms = 5 // LVGL timer period .timer_period_ms = 5 // LVGL timer period
}; };
@@ -180,7 +180,7 @@ static void lvgl_init(void)
.io_handle = io_handle, .io_handle = io_handle,
.panel_handle = panel_handle, .panel_handle = panel_handle,
.buffer_size = LCD_H_RES * LCD_V_RES * 2, .buffer_size = LCD_H_RES * LCD_V_RES * 2,
.double_buffer = true, .double_buffer = false,
.hres = LCD_H_RES, .hres = LCD_H_RES,
.vres = LCD_V_RES, .vres = LCD_V_RES,
.monochrome = false, .monochrome = false,
@@ -219,15 +219,10 @@ static void createBubble(lv_obj_t * scr)
_bubble = level; _bubble = level;
} }
void ui_test()
{
lv_obj_t *label = lv_label_create(lv_screen_active());
lv_label_set_text(label, "Hello, LVGL 9.2!");
lv_obj_center(label);
}
void gui_start(void) void gui_start(void)
{ {
// Initialize LCD // Initialize LCD
lcd_init(); lcd_init();
@@ -237,7 +232,6 @@ void gui_start(void)
// Create UI // Create UI
create_lvgl_demo(); create_lvgl_demo();
keypad_start(); keypad_start();
gpio_set_level(PIN_NUM_BK_LIGHT, 1); gpio_set_level(PIN_NUM_BK_LIGHT, 1);
@@ -333,21 +327,9 @@ static void refresh_highlight(void) {
next = lv_obj_get_child(page, index); next = lv_obj_get_child(page, index);
} }
// for(int i = 0; i < ITEM_COUNT; i++) {
// if(i == selected_idx) {
// lv_obj_set_style_bg_color(btn_array[i], lv_color_hex(0xFF8800), 0);
// lv_obj_set_style_text_color(lv_obj_get_child(btn_array[i],0),
// lv_color_white(), 0);
// } else {
// lv_obj_set_style_bg_color(btn_array[i], lv_color_white(), 0);
// lv_obj_set_style_text_color(lv_obj_get_child(btn_array[i],0),
// lv_color_black(), 0);
// }
// }
if (selected) if (selected)
{ {
lv_obj_scroll_to_view(selected, LV_ANIM_ON); lv_obj_scroll_to_view(selected, LV_ANIM_ON);
} }
lvgl_port_unlock(); lvgl_port_unlock();
@@ -522,39 +504,6 @@ static void build_scrollable_menu(void) {
_currentPage = main; _currentPage = main;
#if 0
for(int i = 0; i < ITEM_COUNT; i++) {
// create a full-width button in that section
lv_obj_t * btn = lv_btn_create(main);
lv_obj_set_size(btn, LV_PCT(100), ROW_H);
// style it just like your old list
lv_obj_set_style_bg_color(btn, lv_color_white(), 0);
lv_obj_set_style_radius(btn, 0, LV_PART_MAIN);
lv_obj_set_style_border_width(btn, 0, LV_PART_MAIN);
lv_obj_clear_flag(btn, LV_OBJ_FLAG_SCROLLABLE);
// label & center
lv_obj_t * lbl = lv_label_create(btn);
lv_label_set_text(lbl, items[i]);
lv_obj_set_style_radius(lbl, 0, LV_PART_MAIN | LV_STATE_ANY);
lv_obj_set_style_border_width(lbl, 0, LV_PART_MAIN | LV_STATE_ANY);
//lv_obj_center(lbl);
// click callback
lv_obj_add_event_cb(btn, btn_click_cb, LV_EVENT_CLICKED, NULL);
// save for highlight/scroll
btn_array[i] = btn;
}
// lv_obj_t * content = lv_obj_get_child(page, 0);
// lv_obj_set_style_radius(content, 0, LV_PART_MAIN | LV_STATE_ANY);
// lv_obj_set_style_border_width(content, 0, LV_PART_MAIN | LV_STATE_ANY);
#endif
// 6) Initial highlight // 6) Initial highlight
selected_idx = 0; selected_idx = 0;
refresh_highlight(); refresh_highlight();
@@ -563,6 +512,7 @@ static void build_scrollable_menu(void) {
} }
static void gui_task(void) static void gui_task(void)
{ {
system_subscribe(xTaskGetCurrentTaskHandle()); system_subscribe(xTaskGetCurrentTaskHandle());
@@ -571,8 +521,12 @@ static void gui_task(void)
QueueHandle_t q = keypad_getQueue(); QueueHandle_t q = keypad_getQueue();
uint32_t ev = 0; uint32_t ev = 0;
LOCK();
// _mode = GUI_MENU;
// lv_obj_remove_flag(_menu, LV_OBJ_FLAG_HIDDEN);
lv_obj_remove_flag(_bubble, LV_OBJ_FLAG_HIDDEN); lv_obj_remove_flag(_bubble, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(_menu, LV_OBJ_FLAG_HIDDEN); //lv_obj_add_flag(_menu, LV_OBJ_FLAG_HIDDEN);
UNLOCK();
while (1) while (1)
{ {
@@ -581,6 +535,19 @@ static void gui_task(void)
if (xQueueReceive(q, &ev, pdMS_TO_TICKS(10)) == pdTRUE) if (xQueueReceive(q, &ev, pdMS_TO_TICKS(10)) == pdTRUE)
{ {
switch (ev) { switch (ev) {
case (KEY_UP << KEY_LONG_PRESS):
{
system_setZeroAngle();
break;
}
case (KEY_DOWN << KEY_LONG_PRESS):
{
system_clearZeroAngle();
break;
}
#if 0
case (KEY0 << KEY_SHORT_PRESS): case (KEY0 << KEY_SHORT_PRESS):
if (_mode == GUI_MENU) if (_mode == GUI_MENU)
@@ -590,6 +557,8 @@ static void gui_task(void)
ESP_LOGI(TAG, "MAIN: Button 1 SHORT"); ESP_LOGI(TAG, "MAIN: Button 1 SHORT");
break; break;
case (KEY0 << KEY_LONG_PRESS): case (KEY0 << KEY_LONG_PRESS):
{
if (_mode != GUI_MENU) if (_mode != GUI_MENU)
{ {
@@ -605,8 +574,8 @@ static void gui_task(void)
// lv_obj_remove_flag(_bubble, LV_OBJ_FLAG_HIDDEN); // lv_obj_remove_flag(_bubble, LV_OBJ_FLAG_HIDDEN);
// lv_obj_add_flag(_menu, LV_OBJ_FLAG_HIDDEN); // lv_obj_add_flag(_menu, LV_OBJ_FLAG_HIDDEN);
} }
break; break;
}
case (KEY1 << KEY_SHORT_PRESS): case (KEY1 << KEY_SHORT_PRESS):
{ {
if (_mode == GUI_MENU) if (_mode == GUI_MENU)
@@ -619,6 +588,7 @@ static void gui_task(void)
ESP_LOGI(TAG, "MAIN: Button 2 LONG"); ESP_LOGI(TAG, "MAIN: Button 2 LONG");
gpio_set_level(PIN_NUM_nON, 0); gpio_set_level(PIN_NUM_nON, 0);
break; break;
#endif
default: default:
break; break;
} }
@@ -633,7 +603,7 @@ static void gui_task(void)
0xFFFFFFFF, // clear any old bits on entry 0xFFFFFFFF, // clear any old bits on entry
0xFFFFFFFF, // clear bits on exit 0xFFFFFFFF, // clear bits on exit
&notifiedBits, &notifiedBits,
pdMS_TO_TICKS(10)); pdMS_TO_TICKS(100));
if (notifiedBits & EM_EVENT_NEW_DATA) if (notifiedBits & EM_EVENT_NEW_DATA)
{ {

View File

@@ -14,7 +14,8 @@ typedef enum
#define KEY_SHORT_PRESS 0 #define KEY_SHORT_PRESS 0
#define KEY_LONG_PRESS 4 #define KEY_LONG_PRESS 4
#define KEY_UP KEY0
#define KEY_DOWN KEY1
void keypad_start(void); void keypad_start(void);
QueueHandle_t keypad_getQueue(void); QueueHandle_t keypad_getQueue(void);

View File

@@ -21,7 +21,7 @@
#include "nvs_flash.h" #include "nvs_flash.h"
#include "bt_app_core.h" #include "bt_app.h"
#include "lsm6dsv.h" #include "lsm6dsv.h"
#include "gui.h" #include "gui.h"
#include "gpio.h" #include "gpio.h"
@@ -71,8 +71,9 @@ static void init_gpio(void)
// Configure output GPIO // Configure output GPIO
io_conf.pin_bit_mask = (1ULL << PIN_NUM_LED_1); io_conf.pin_bit_mask = (1ULL << PIN_NUM_LED_1) | (1ULL << PIN_NUM_LED_2);
io_conf.mode = GPIO_MODE_OUTPUT; io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE; io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpio_config(&io_conf); gpio_config(&io_conf);
@@ -86,7 +87,8 @@ static void init_gpio(void)
io_conf.pin_bit_mask = (1ULL << PIN_NUM_nON); io_conf.pin_bit_mask = (1ULL << PIN_NUM_nON);
io_conf.mode = GPIO_MODE_OUTPUT; io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE; io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpio_config(&io_conf); gpio_config(&io_conf);
#endif #endif
@@ -95,8 +97,8 @@ static void init_gpio(void)
// Configure LCD Backlight GPIO // Configure LCD Backlight GPIO
io_conf.pin_bit_mask = (1ULL << PIN_NUM_BK_LIGHT); io_conf.pin_bit_mask = (1ULL << PIN_NUM_BK_LIGHT);
io_conf.mode = GPIO_MODE_OUTPUT; io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE; io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpio_config(&io_conf); gpio_config(&io_conf);
@@ -116,7 +118,7 @@ static void imu_task(void *pvParameters) {
ImuData_t imu; ImuData_t imu;
LowPassFilter lpf; LowPassFilter lpf;
LPF_Init(&lpf, 0.2, 0); LPF_Init(&lpf, FILTER_COEFF, 0);
while (1) { while (1) {
@@ -170,20 +172,20 @@ static void imu_task(void *pvParameters) {
float angle; float angle;
if (imu.raw[ANGLE_XY] > MAX_INDICATION_ANGLE)
angle = system_getAngle();
if (angle > MAX_INDICATION_ANGLE)
{ {
angle = MAX_INDICATION_ANGLE; angle = MAX_INDICATION_ANGLE;
} }
else else
if (imu.raw[ANGLE_XY] > MAX_INDICATION_ANGLE) if (angle < -MAX_INDICATION_ANGLE)
{ {
angle = -MAX_INDICATION_ANGLE; angle = -MAX_INDICATION_ANGLE;
} }
else
{
angle = imu.raw[ANGLE_XY];
}
// low pass filter the angle measurement
imu.angle = LPF_Update(&lpf, angle); imu.angle = LPF_Update(&lpf, angle);
//imu.filtered[ANGLE_XY] = LPF_Update(&lpf, imu.raw[ANGLE_XY]); //imu.filtered[ANGLE_XY] = LPF_Update(&lpf, imu.raw[ANGLE_XY]);
@@ -197,7 +199,7 @@ static void imu_task(void *pvParameters) {
#if 0 #if 0
snprintf(data_str, sizeof(data_str), snprintf(data_str, sizeof(data_str),
"(%.1f, %.1f, %.1f) (%.2f, %.2f, %.2f)", "(%.1f, %.1f, %.1f) (%.2f, %.2f, %.2f)",
xz, yz, xy, imu.raw[ANGLE_XZ], imu.raw[ANGLE_YZ], imu.raw[ANGLE_XY],
(float)imu_data.acc_x, (float)imu_data.acc_y, (float)imu_data.acc_z); (float)imu_data.acc_x, (float)imu_data.acc_y, (float)imu_data.acc_z);
ESP_LOGI(TAG, "%s", data_str); ESP_LOGI(TAG, "%s", data_str);
#endif #endif
@@ -218,12 +220,12 @@ void app_main(void)
{ {
/* initialize NVS — it is used to store PHY calibration data */ /* initialize NVS — it is used to store PHY calibration data */
// esp_err_t ret = nvs_flash_init(); esp_err_t ret = nvs_flash_init();
// if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
// ESP_ERROR_CHECK(nvs_flash_erase()); ESP_ERROR_CHECK(nvs_flash_erase());
// ret = nvs_flash_init(); ret = nvs_flash_init();
// } }
// ESP_ERROR_CHECK(ret); ESP_ERROR_CHECK(ret);
init_gpio(); init_gpio();
@@ -241,26 +243,49 @@ void app_main(void)
bt_app_init();
gui_start(); gui_start();
gpio_set_level(PIN_NUM_LED_2, 1);
//bt_app_init(); #if 0
keypad_start();
QueueHandle_t q = keypad_getQueue();
uint32_t ev = 0;
//gpio_set_level(PIN_NUM_LED_1, 1);
gpio_set_level(PIN_NUM_LED_2, 1);
// Main loop - LVGL task will run automatically // Main loop - LVGL task will run automatically
while (1) { while (1) {
// int level = gpio_get_level(PIN_NUM_BUTTON_1); // Read input GPIO if (xQueueReceive(q, &ev, pdMS_TO_TICKS(10)) == pdTRUE)
// gpio_set_level(PIN_NUM_LED_1, level); {
switch (ev)
{
case (KEY_UP << KEY_LONG_PRESS):
{
system_setZeroAngle();
break;
}
//gpio_set_level(PIN_NUM_nON, (level ? 0 : 1)); case (KEY_DOWN << KEY_LONG_PRESS):
{
system_clearZeroAngle();
break;
}
}
vTaskDelay(pdMS_TO_TICKS(100)); }
//gui_service();
} }
#else
while (1)
{
vTaskDelay(pdMS_TO_TICKS(1000));
}
#endif
} }

View File

@@ -8,12 +8,77 @@ static EventManager_t _eventManager;
void system_init(void) void system_init(void)
{ {
_systemState.zeroAngle = 0.0f;
_systemState.primaryAxis = PRIMARY_AXIS;
EventGroupHandle_t evt = xEventGroupCreate(); EventGroupHandle_t evt = xEventGroupCreate();
_eventManager.count = 0; _eventManager.count = 0;
_eventManager.mutex = xSemaphoreCreateMutex(); _eventManager.mutex = xSemaphoreCreateMutex();
} }
int system_getPrimaryAxis(void)
{
int axis;
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
axis = _systemState.primaryAxis;
xSemaphoreGive(_eventManager.mutex);
return axis;
}
float system_getAngle(void)
{
float angle;
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
angle = _systemState.imu.raw[_systemState.primaryAxis] - _systemState.zeroAngle;
xSemaphoreGive(_eventManager.mutex);
return angle;
}
void system_setZeroAngle(void)
{
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
_systemState.zeroAngle = _systemState.imu.raw[_systemState.primaryAxis];
ESP_LOGI("system", "Zero: %.1f", _systemState.zeroAngle);
xSemaphoreGive(_eventManager.mutex);
}
void system_clearZeroAngle(void)
{
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
_systemState.zeroAngle = 0.0f;
ESP_LOGI("system", "Zero: %.1f", _systemState.zeroAngle);
xSemaphoreGive(_eventManager.mutex);
}
float system_getZeroAngle(void)
{
float angle;
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
angle = _systemState.zeroAngle;
xSemaphoreGive(_eventManager.mutex);
return angle;
}
void system_setImuData(ImuData_t imu) void system_setImuData(ImuData_t imu)
{ {
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY); xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);

View File

@@ -5,6 +5,8 @@
#include "freertos/task.h" #include "freertos/task.h"
#include "freertos/semphr.h" #include "freertos/semphr.h"
#define DISABLE_GUI
enum enum
{ {
ANGLE_XY = 0, ANGLE_XY = 0,
@@ -27,11 +29,15 @@ typedef struct SystemState_s
EventGroupHandle_t event; EventGroupHandle_t event;
float zeroAngle;
int primaryAxis;
} SystemState_t; } SystemState_t;
#define MAX_INDICATION_ANGLE 10.0f #define MAX_INDICATION_ANGLE 5.0f
#define FILTER_COEFF 0.2f // 0 to 1 Smaller number is heavier filter
#define PRIMARY_AXIS ANGLE_YZ
#define EM_MAX_SUBSCRIBERS 8 // tweak as needed #define EM_MAX_SUBSCRIBERS 8 // tweak as needed
#define EM_EVENT_NEW_DATA (1UL<<0) #define EM_EVENT_NEW_DATA (1UL<<0)
@@ -49,6 +55,13 @@ void system_setImuData(ImuData_t imu);
ImuData_t system_getImuData(void); ImuData_t system_getImuData(void);
int system_getPrimaryAxis(void);
float system_getAngle(void);
void system_setZeroAngle(void);
void system_clearZeroAngle(void);
float system_getZeroAngle(void);
// Subscribe (register) current task to receive events // Subscribe (register) current task to receive events
BaseType_t system_subscribe(TaskHandle_t task); BaseType_t system_subscribe(TaskHandle_t task);

13
monitor.bat Normal file
View File

@@ -0,0 +1,13 @@
@echo off
REM =============================================
REM ESP32 Serial Monitor using settings.json
REM =============================================
IF NOT EXIST .venv\Scripts\python.exe (
echo [ERROR] .venv not found. Run setup-env.bat first.
pause
exit /b 1
)
call .venv\Scripts\activate.bat
python flash_tool\monitor.py

10
prepare_config.py Normal file
View File

@@ -0,0 +1,10 @@
import json
with open("settings.json") as f:
cfg = json.load(f)
with open("project_settings.cmake", "w") as out:
out.write(f'set(PROJECT_NAME "{cfg["project_name"]}")\n')
out.write(f'set(CHIP "{cfg["chip"]}")\n')
out.write(f'set(PORT "{cfg["port"]}")\n')
out.write(f'set(BAUD "{cfg["baud"]}")\n')

3
requirements.txt Normal file
View File

@@ -0,0 +1,3 @@
esptool
pyserial

View File

@@ -353,14 +353,14 @@ CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set # CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
CONFIG_ESPTOOLPY_FLASHFREQ="40m" CONFIG_ESPTOOLPY_FLASHFREQ="40m"
# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y # CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE="2MB" CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set # CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set
CONFIG_ESPTOOLPY_BEFORE_RESET=y CONFIG_ESPTOOLPY_BEFORE_RESET=y
# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set # CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
@@ -393,8 +393,8 @@ CONFIG_EXAMPLE_SSP_ENABLED=y
# #
# Compiler options # Compiler options
# #
CONFIG_COMPILER_OPTIMIZATION_DEBUG=y # CONFIG_COMPILER_OPTIMIZATION_DEBUG is not set
# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set CONFIG_COMPILER_OPTIMIZATION_SIZE=y
# CONFIG_COMPILER_OPTIMIZATION_PERF is not set # CONFIG_COMPILER_OPTIMIZATION_PERF is not set
# CONFIG_COMPILER_OPTIMIZATION_NONE is not set # CONFIG_COMPILER_OPTIMIZATION_NONE is not set
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
@@ -1448,7 +1448,6 @@ CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=1
# #
# Port # Port
# #
CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y
# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set # CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set
CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS=y CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS=y
# CONFIG_FREERTOS_TASK_PRE_DELETION_HOOK is not set # CONFIG_FREERTOS_TASK_PRE_DELETION_HOOK is not set
@@ -1497,7 +1496,7 @@ CONFIG_HEAP_TRACING_OFF=y
# CONFIG_HEAP_TRACING_TOHOST is not set # CONFIG_HEAP_TRACING_TOHOST is not set
# CONFIG_HEAP_USE_HOOKS is not set # CONFIG_HEAP_USE_HOOKS is not set
# CONFIG_HEAP_TASK_TRACKING is not set # CONFIG_HEAP_TASK_TRACKING is not set
# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS=y
# CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH is not set # CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH is not set
# end of Heap memory debugging # end of Heap memory debugging
@@ -2496,11 +2495,11 @@ CONFIG_LOG_BOOTLOADER_LEVEL=3
CONFIG_FLASHMODE_DIO=y CONFIG_FLASHMODE_DIO=y
# CONFIG_FLASHMODE_DOUT is not set # CONFIG_FLASHMODE_DOUT is not set
CONFIG_MONITOR_BAUD=115200 CONFIG_MONITOR_BAUD=115200
CONFIG_OPTIMIZATION_LEVEL_DEBUG=y # CONFIG_OPTIMIZATION_LEVEL_DEBUG is not set
CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y # CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set
CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y # CONFIG_COMPILER_OPTIMIZATION_DEFAULT is not set
# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set CONFIG_OPTIMIZATION_LEVEL_RELEASE=y
# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y
# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set # CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set
# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set # CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set

9
sdkconfig.defaults Normal file
View File

@@ -0,0 +1,9 @@
# Override some defaults so BT stack is enabled and
# Classic BT is enabled
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=n
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y
CONFIG_BTDM_CTRL_MODE_BTDM=n
CONFIG_BT_BLUEDROID_ENABLED=y
CONFIG_BT_CLASSIC_ENABLED=y
CONFIG_BT_A2DP_ENABLE=y

2888
sdkconfig.old Normal file

File diff suppressed because it is too large Load Diff

12
settings.json Normal file
View File

@@ -0,0 +1,12 @@
{
"project_name": "soundshot",
"chip": "esp32h2",
"port": "COM8",
"monitor_baud": 115200,
"flash_baud": 460800,
"flash_mode": "dio",
"flash_freq": "48m",
"flash_size": "2MB",
"before": "default-reset",
"after": "hard-reset"
}

17
setup-env.bat Normal file
View File

@@ -0,0 +1,17 @@
@echo off
setlocal
echo [ESP32 Setup] Creating Python virtual environment...
python -m venv .venv
echo [ESP32 Setup] Activating environment...
call .venv\Scripts\activate.bat
echo [ESP32 Setup] Installing dependencies...
pip install -r requirements.txt
echo [ESP32 Setup] Done!
echo To activate environment later: call .venv\Scripts\activate.bat
endlocal
pause