diff --git a/README.md b/README.md index 26abcb4..a67df97 100644 --- a/README.md +++ b/README.md @@ -60,24 +60,24 @@ ```mermaid flowchart LR subgraph TX["Node 1: Handheld Controller (ESP32-S3-N16R8)"] - MCU["ESP32-S3-N16R8
(FreeRTOS Dual-Core)"] - HALL["2x K-Silver PS5
Hall-Effect Joysticks"] -->|ADC1| MCU - MIC["MAX4466 Electret
Mic Pre-Amp"] -->|ADC1| MCU + MCU["ESP32-S3-N16R8 (FreeRTOS Dual-Core)"] + HALL["2x K-Silver PS5 Hall-Effect Joysticks"] -->|ADC1| MCU + MIC["MAX4466 Electret Mic Pre-Amp"] -->|ADC1| MCU ENC["KY-040 Rotary Encoder"] -->|Hardware PCNT| MCU - MCU -->|SPI2_HOST + CS GPIO10| TFT["1.8" ST7789 Color TFT"] - MCU -->|SPI2_HOST + CS| SD["MicroSD Card (FAT32)"] + MCU -->|SPI2_HOST + CS GPIO10| TFT["1.8-inch ST7789 Color TFT"] + MCU -->|SPI2_HOST + CS GPIO18| SD["MicroSD Card (FAT32)"] MCU -->|2N2222 NPN Drivers| BUZ["1x Passive + 2x Active Buzzers"] MCU -->|SPI2_HOST + CSN GPIO14| NRF_TX["nRF24L01+ 2.4GHz TX"] end subgraph RX["Node 2: 4WD RC Vehicle (GD32F103C8T6)"] - NRF_RX["nRF24L01+ PA+LNA
(1km SMA Antenna)"] -->|SPI| GD32["GD32F103C8T6
(ARM Cortex-M3)"] + NRF_RX["nRF24L01+ PA+LNA (1km SMA Antenna)"] -->|SPI| GD32["GD32F103C8T6 (ARM Cortex-M3)"] IMU["MPU9250 9-DOF IMU"] -->|I2C| GD32 TOF["VL53L0X ToF / HC-SR04"] -->|I2C / Divider| GD32 - GD32 -->|Closed-Loop PID PWM| MOT["4x JGB37-520 12V
333RPM Encoder Motors"] + GD32 -->|Closed-Loop PID PWM| MOT["4x JGB37-520 12V 333RPM Encoder Motors"] end - NRF_TX <==>|"2.4 GHz RF Link (Ch 0-125)"| NRF_RX + NRF_TX <-->|"2.4 GHz RF Link (Ch 0-125)"| NRF_RX ``` ### 3.1 Handheld Controller (MFC — Transmitter Node) @@ -168,8 +168,6 @@ To avoid ESP32-S3 Octal Flash/PSRAM pins (`GPIO 26–37`), USB-OTG pins (`GPIO 1 ```text multi-functional-controller/ -├── docs/ -│ └── PROJECT_HANDOFF.md # Canonical engineering handoff & specification ├── firmware/ # ESP-IDF v5.x C99 Firmware Project (ESP32-S3 Rev 0.1 Baseline) │ ├── CMakeLists.txt # Top-level CMake project configuration │ ├── sdkconfig # Verified ESP32-S3 target configuration diff --git a/docs/PROJECT_HANDOFF.md b/docs/PROJECT_HANDOFF.md deleted file mode 100644 index f379fe3..0000000 --- a/docs/PROJECT_HANDOFF.md +++ /dev/null @@ -1,173 +0,0 @@ -# Project Handoff: Multi-Functional Controller (MFC) & RC Vehicle - -## 1. Project Overview & Aim -**Goal:** Engineer a high-performance, bare-metal remote controller (MFC) from scratch using an ESP32-S3, paired with a custom 4WD RC vehicle. -**Secondary Objectives:** Extend the controller's capabilities to include a cloud-connected AI voice assistant, local telemetry logging, and PC gamepad (USB HID/Bluetooth) support. -**Tech Stack:** C/C++, ESP-IDF v5.x (FreeRTOS), Bare-metal register manipulation, SPI, I2C, Hardware PCNT, ADC Oneshot. - -## 2. Current Situation -* **Controller Prototype:** Currently prototyped on a 6x9cm perfboard. The ESP32-S3 successfully communicates over a shared SPI bus with an NRF24L01+ transceiver and a temporary 1.3" OLED display. -* **Firmware:** A robust FreeRTOS state machine is running. It handles analog ADC joystick polling, hardware quadrature decoding (PCNT) for a rotary encoder menu UI, software button debouncing, and blind RF transmission on 2.4GHz. -* **Hardware Pivot:** We recently discovered the 7-pin 1.3" OLED lacks a Chip Select (CS) pin, causing SPI collisions. We have decided to upgrade to a 1.8" ST7789 color TFT (which has a CS pin) to share the SPI bus safely. -* **Manufacturing:** Paused cutting the rigid ABS plastic project box (`DT-100`) until next month when a proper rotary tool (Dremel/E108) and 2.35mm cutting wheels arrive to ensure clean, professional cutouts. - -## 3. Hardware Architecture & Bill of Materials (BOM) - -### 3.1 Handheld Controller (MFC) -* **MCU:** Espressif ESP32-S3-N16R8 (16MB Flash, 8MB PSRAM). -* **RF Telemetry:** Nordic nRF24L01+ 2.4GHz Module. -* **Display:** 1.8" ST7789 TFT Color LCD (3.3V logic, SPI with CS pin). -* **Joysticks:** 2x K-Silver (KS) PS5 Magnetic Hall-Effect modules (3.3V active sensors). -* **UI Input:** KY-040 Rotary Encoder (CLK, DT, SW). -* **Voice AI:** MAX4466 Electret Microphone Module (Analog output). -* **Data Logging:** Arduino Micro SD Card Module (SPI interface, formatted FAT32). -* **Audio Output:** 1x Passive Buzzer (Melody), 2x Active Buzzers (Percussive clicks) driven by 2N2222 NPN Transistors. -* **Power:** Dual 18650 Li-ion cells, TP4056 Charger, MT3608 DC-DC Boost Converter (5V rail), 100µF Electrolytic Capacitor (for NRF24 burst smoothing), 100nF Ceramic Caps. - -### 3.2 RC Vehicle (Receiver Node) -* **MCU:** GD32F103C8T6 ARM Cortex-M3 Mini Board. -* **RF Telemetry:** nRF24L01+ PA+LNA (with external SMA antenna for 1km range). -* **IMU / Navigation:** MPU9250 9-DOF Sensor (Gyro, Accelerometer, Magnetometer for tilt-compensated heading). -* **Drivetrain:** 4x JGB37-520 12V 333RPM Gear Motors (with built-in encoders for PID velocity control). -* **Chassis/Enclosure:** DT-100 Project Box (190x137x59mm). -* **Power:** 12V Battery, Heavy-duty Motor Drivers, 12-24V Waterproof Main Switch. - -## 4. Pinout Definitions (ESP32-S3 Controller) -* **SPI Hub:** MOSI (`GPIO11`), MISO (`GPIO13`), SCK (`GPIO12`) -* **NRF24:** CSN (`GPIO14`), CE (`GPIO21`) -* **TFT Display (Planned):** CS (`GPIO10`), DC (`GPIO9`), RES (`GPIO8`), BLK (`3.3V`) -* **Rotary Encoder:** CLK (`GPIO15`), DT (`GPIO16`), SW (`GPIO17` - Pull-up) -* **Joysticks:** VRx (`GPIO4`), VRy (`GPIO5`) via ADC1. (Second joystick pins pending). - -## 5. Master Codebase (Latest Working Version) -This code currently uses the monochrome OLED logic, but handles PCNT menu decoding and NRF transmission perfectly. - -```c -#include -#include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "driver/spi_master.h" -#include "driver/gpio.h" -#include "driver/pulse_cnt.h" -#include "esp_system.h" -#include "esp_log.h" - -// Hardware Pins -#define PIN_NUM_MOSI 11 -#define PIN_NUM_MISO 13 -#define PIN_NUM_CLK 12 -#define NRF_PIN_CS 14 -#define NRF_PIN_CE 21 -#define OLED_PIN_CS 10 -#define OLED_PIN_DC 9 -#define OLED_PIN_RES 8 -#define PIN_ENCODER_CLK 15 -#define PIN_ENCODER_DT 16 -#define PIN_ENCODER_SW 17 - -#define NUM_MENU_ITEMS 4 - -static const char *TAG = "MFC_CORE"; -spi_device_handle_t oled_spi; -spi_device_handle_t nrf_spi; -int current_radio_channel = 76; - -typedef enum { SCREEN_MAIN_MENU = 0, SCREEN_DRIVE, SCREEN_RADIO_CONFIG, SCREEN_CALIBRATE, SCREEN_SYSTEM_INFO } screen_state_t; - -// [Font arrays omitted in handoff for brevity, but exist in master file: font_AZ, font_nums, etc.] -const uint8_t* get_font_data(char c) { /* ... */ return NULL; } - -void oled_cmd(uint8_t cmd) { - gpio_set_level(OLED_PIN_DC, 0); - spi_transaction_t t = { .length = 8, .tx_buffer = &cmd }; - spi_device_polling_transmit(oled_spi, &t); -} -void oled_data(uint8_t data) { - gpio_set_level(OLED_PIN_DC, 1); - spi_transaction_t t = { .length = 8, .tx_buffer = &data }; - spi_device_polling_transmit(oled_spi, &t); -} -void oled_draw_string(uint8_t page, uint8_t col, const char* str) { - oled_cmd(0xB0 + page); - uint8_t phys_col = col + 2; - oled_cmd(0x00 | (phys_col & 0x0F)); - oled_cmd(0x10 | ((phys_col >> 4) & 0x0F)); - while (*str) { - const uint8_t* pixels = get_font_data(*str++); - for (int i = 0; i < 5; i++) { oled_data(pixels[i]); } - oled_data(0x00); - } -} -void oled_clear() { - for (uint8_t p = 0; p < 8; p++) { - oled_cmd(0xB0 + p); oled_cmd(0x02); oled_cmd(0x10); - for (uint8_t c = 0; c < 128; c++) { oled_data(0x00); } - } -} -void oled_init() { - gpio_set_level(OLED_PIN_RES, 0); vTaskDelay(pdMS_TO_TICKS(50)); - gpio_set_level(OLED_PIN_RES, 1); vTaskDelay(pdMS_TO_TICKS(50)); - uint8_t init_cmds[] = {0xAE,0xD5,0x80,0xA8,0x3F,0xD3,0x00,0x40,0x8D,0x14,0xA1,0xC8,0xDA,0x12,0x81,0xCF,0xD9,0xF1,0xDB,0x40,0xA4,0xA6,0xAF}; - for(int i = 0; i < sizeof(init_cmds); i++) { oled_cmd(init_cmds[i]); } -} - -bool nrf_check_connection() { - uint8_t tx[2] = { 0x03, 0xFF }; - uint8_t rx[2] = { 0 }; - spi_transaction_t t = { .length = 16, .tx_buffer = tx, .rx_buffer = rx }; - spi_device_polling_transmit(nrf_spi, &t); - return (rx[1] == 0x03); -} -void set_nrf_channel(uint8_t channel) { - uint8_t tx[2] = { 0x25, channel }; - spi_transaction_t t = { .length = 16, .tx_buffer = tx }; - spi_device_polling_transmit(nrf_spi, &t); -} - -void draw_menu(int selected_index) { /* Renders Main Menu items */ } -void draw_system_info() { /* Renders ESP32 Free Heap */ } -void draw_radio_config_screen(int channel) { /* Interactive channel tuning UI */ } -void draw_placeholder_screen(const char* title) { /* Basic placeholder */ } - -void app_main(void) { - // 1. SPI Init - spi_bus_config_t buscfg = { .miso_io_num = PIN_NUM_MISO, .mosi_io_num = PIN_NUM_MOSI, .sclk_io_num = PIN_NUM_CLK, .max_transfer_sz = 4096 }; - spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO); - - // 2. Devices (OLED & NRF) - spi_device_interface_config_t oled_cfg = { .clock_speed_hz = 10000000, .mode = 0, .spics_io_num = OLED_PIN_CS, .queue_size = 1 }; - spi_bus_add_device(SPI2_HOST, &oled_cfg, &oled_spi); - - spi_device_interface_config_t nrf_cfg = { .clock_speed_hz = 1000000, .mode = 0, .spics_io_num = NRF_PIN_CS, .queue_size = 1 }; - spi_bus_add_device(SPI2_HOST, &nrf_cfg, &nrf_spi); - - // 3. PCNT Setup for Rotary Encoder - // [PCNT Init logic omitted for brevity in handoff, but fully functional in master] - - // 4. FreeRTOS State Machine Loop - int count = 0, last_menu_index = -1, last_sw_state = 1; - TickType_t last_button_press = 0; - screen_state_t current_screen = SCREEN_MAIN_MENU; - bool screen_needs_redraw = true; - int radio_start_count = 0, last_tuned_channel = current_radio_channel; - - while (1) { - // Core polling loop handling screen state, PCNT steps, debouncing, and NRF register updating. - vTaskDelay(pdMS_TO_TICKS(30)); - } -} -``` - -## 6. Immediate Next Steps (For the Assisting Agent) -1. **ST7789 TFT Migration:** Rewrite the display initialization and frame buffer logic using ESP-IDF's `esp_lcd` component to replace the custom 5x8 monochrome OLED code. -2. **SD Card SPI Setup:** Configure the SD card module on the shared SPI bus (or a new SPI bus) and initialize the `FATFS` VFS so we can read/write data logs. -3. **NVS Calibration:** Write the calibration routine for the upcoming K-Silver Hall-effect joysticks. We need to measure resting, min, and max voltages and save them permanently to the ESP32's flash memory. -4. **GD32 Vehicle Receiver Code:** Begin structuring the C code for the ARM Cortex-M3 GD32 to poll the NRF24 PA+LNA module and read the MPU9250 I2C data. - -## 7. Known Context & Hardware Rules -* Do NOT use standard `16000 RPM` tools on the plastic case; we are waiting for a 3-speed drill with 2.35mm diamond cutting discs. -* Do NOT wire the Hall-effect joystick `VCC` backward; it is an active component and will burn out. -* Do NOT wire the HC-SR04 `ECHO` pin directly to the GD32; it requires a resistor voltage divider. (Though we are considering the VL53L0X I2C ToF instead). -* Must use a 100µF capacitor on the NRF24 power lines to prevent brown-outs during PTX bursts. \ No newline at end of file