Compare commits
10 commits
b80328f4a6
...
b13417200c
| Author | SHA1 | Date | |
|---|---|---|---|
| b13417200c | |||
| d379b902b1 | |||
| 2ce9838918 | |||
| 163ba4bea9 | |||
| bc4cc25e46 | |||
| d94bd09527 | |||
| df7dc140ff | |||
| fdc186afaf | |||
| e3a4be6032 | |||
| 09439eaf52 |
14 changed files with 25581 additions and 17 deletions
19
.gitignore
vendored
19
.gitignore
vendored
|
|
@ -5,14 +5,27 @@
|
||||||
*.bin
|
*.bin
|
||||||
*.map
|
*.map
|
||||||
*.out
|
*.out
|
||||||
|
*.log
|
||||||
|
*.old
|
||||||
|
|
||||||
# Build folders
|
# Build folders & caches
|
||||||
build/
|
build/
|
||||||
bin/
|
bin/
|
||||||
|
.cache/
|
||||||
|
managed_components/
|
||||||
|
dependencies.lock
|
||||||
|
|
||||||
# VS Code local workspace settings
|
# KiCad temporary & local files
|
||||||
|
*.kicad_prl
|
||||||
|
*-bak
|
||||||
|
*-bak.kicad_*
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# IDE & Editor files
|
||||||
.vscode/
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
|
||||||
# Arch Linux / System files
|
# OS / System temporary files
|
||||||
*~
|
*~
|
||||||
.directory
|
.directory
|
||||||
|
.DS_Store
|
||||||
|
|
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Ertunç Özbay
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
187
README.md
187
README.md
|
|
@ -1,27 +1,186 @@
|
||||||
# Multifunctional Controller Project(In Progress)
|
# Multi-Functional Controller (MFC)
|
||||||
|
|
||||||
A custom handheld controller that built for both gaming and conrolling RC devices.
|
[](https://github.com/espressif/esp-idf)
|
||||||
|
[](https://www.espressif.com/en/products/socs/esp32-s3)
|
||||||
|
[](https://www.kicad.org/)
|
||||||
|
[](https://en.wikipedia.org/wiki/C_(programming_language))
|
||||||
|
[](https://www.freertos.org/)
|
||||||
|
|
||||||
**NOTE:** This project is still in development and some features and modules could be changed in the future.
|
## 1. Project Overview & Aim
|
||||||
|
|
||||||
## FEATURES
|
- **Primary Goal:** Engineer a high-performance, bare-metal Multi-Functional Controller (**MFC**) from scratch using an **ESP32-S3-N16R8** for low-latency 2.4 GHz RF control (such as custom RC platforms) and **PC Gamepad (`USB HID / Bluetooth`)** support.
|
||||||
|
- **Secondary Objectives:** Extend the controller's capabilities to include a **cloud-connected AI voice assistant**, **local FAT32 SD card telemetry logging**, and **multi-transducer acoustic feedback**.
|
||||||
|
- **Tech Stack:** C/C++, ESP-IDF v5.x (FreeRTOS), bare-metal register manipulation, SPI, Hardware Pulse Counter (`PCNT`), and One-Shot `ADC1`.
|
||||||
|
|
||||||
* Low latency on both bluetooth and radio signal connection
|
---
|
||||||
|
|
||||||
* -----**New features will be added in the future**-----
|
## 2. Current Situation & Early Prototype Showcase (Rev 0.1)
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> **Early Prototype Notice (Rev 0.1 Carrier Build):**
|
||||||
|
> The photographs and schematic below represent the **very early initial stage** of the physical hardware build. At this stage, only the core carrier foundation is soldered onto the 6×9 cm perfboard: the **ESP32-S3-N16R8 microcontroller**, **nRF24L01+ 2.4 GHz radio module**, **100 µF electrolytic burst-smoothing capacitor**, **signal male pin headers**, and **power rail male headers**.
|
||||||
|
> The repository's firmware (`firmware/main/mmcontroller.c`) and schematic (`hardware/mfc-1.kicad_sch`) are intentionally kept matched to this verified **Rev 0.1 hardware baseline**. As the new controller modules (`1.8" ST7789 TFT`, `K-Silver PS5 Hall-Effect Joysticks`, `MicroSD`, `MAX4466`, `2N2222` buzzer stage, and enclosure) are physically integrated, both the hardware photos and firmware will be updated step-by-step.
|
||||||
|
|
||||||
## COMPONENTS
|
- **Controller Prototype (Rev 0.1):** Prototyped on a **6×9 cm perfboard**. The `ESP32-S3-N16R8` communicates over a shared `SPI2_HOST` bus with a Nordic `nRF24L01+` 2.4 GHz transceiver and a temporary benchtop 1.3" SH1106 OLED display connected via the male breakout headers.
|
||||||
|
- **Current Baseline Firmware:** A deterministic FreeRTOS state machine (`firmware/main/mmcontroller.c`) handles hardware quadrature decoding (`PCNT`) for a `KY-040` rotary encoder menu UI, `300 ms` software button debouncing, and live 2.4 GHz RF channel configuration (`0–125`).
|
||||||
|
- **Display Hardware Pivot (`1.3" OLED` $\rightarrow$ `1.8" ST7789 TFT`):** Bench testing revealed that the 7-pin 1.3" OLED module lacks a physical Chip Select (`CS`) pin (hard-tied to GND internally), causing SPI bus collisions when sharing the bus. We are upgrading to a **1.8" ST7789 Color TFT LCD** (which exposes a dedicated hardware `CS` pin on `GPIO 10`) to share the SPI bus safely without bus contention.
|
||||||
|
- **Manufacturing & Enclosure Status:** Paused cutting the rigid ABS plastic enclosure (`DT-100`, `190 × 137 × 59 mm`) until next month when a variable 3-speed rotary tool (`Dremel/E108`) and `2.35 mm` diamond cutting wheels arrive to ensure clean, professional cutouts without melting the ABS plastic.
|
||||||
|
|
||||||
- High performance ESP32-S3-N16R8 microcontroller
|
<p align="center">
|
||||||
- Affordable NRF24L01+ radio module for short comminications(Will be changed in future)
|
<img src="images/TOP_VIEW.png" alt="Early Prototype Rev 0.1 Top View" width="700">
|
||||||
* 1 Rotary Encoder
|
<br>
|
||||||
* 1 100 microfarad electrolytic capacitor
|
<em><b>Figure 1 (Early Build — Rev 0.1):</b> Initial 6×9 cm perfboard carrier top view — ESP32-S3-N16R8 module, nRF24L01+ 2.4 GHz transceiver, 100 µF decoupling capacitor, peripheral male pin headers, and power rail male headers. (Will be updated as Phase 2 modules are installed).</em>
|
||||||
* Male and female headers
|
</p>
|
||||||
* 6x9 cm perfboard
|
|
||||||
|
|
||||||
---**Some of them could be changed due to various reasons in the future**----
|
<p align="center">
|
||||||
|
<img src="images/SIDE_VIEW_WITH_ANTENNA.png" alt="Early Prototype Rev 0.1 Side Profile & RF Antenna" width="700">
|
||||||
|
<br>
|
||||||
|
<em><b>Figure 2 (Early Build — Rev 0.1):</b> Side profile showing the external 2.4 GHz SMA dipole antenna connected to the nRF24L01+ transceiver and dual USB-C ports (Native USB-OTG & UART).</em>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="images/BOTTOM_VIEW.png" alt="Early Prototype Rev 0.1 Underbody Perfboard Soldering" width="700">
|
||||||
|
<br>
|
||||||
|
<em><b>Figure 3 (Early Build — Rev 0.1):</b> Underbody point-to-point solder bridges, common ground/power rails, and shared SPI2 signal routing on the 6×9 cm perfboard.</em>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
### Rev 0.1 Core Carrier Schematic (`hardware/mfc-1.kicad_sch`)
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="images/mfc-1.svg" alt="Rev 0.1 KiCad Schematic" width="750">
|
||||||
|
<br>
|
||||||
|
<em><b>Figure 4:</b> KiCad 10 schematic of the Rev 0.1 Core Carrier (`U1: ESP32-S3`, `U2: nRF24L01+`, `C1: 100 µF` decoupling capacitor).</em>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Controller Hardware Architecture & Bill of Materials (BOM)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph MFC["Multi-Functional 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
|
||||||
|
ENC["KY-040 Rotary Encoder"] -->|Hardware PCNT| MCU
|
||||||
|
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 Transceiver"]
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
| Subsystem | Component | Technical Details & Role | Build State |
|
||||||
|
| :--- | :--- | :--- | :---: |
|
||||||
|
| **MCU** | **Espressif ESP32-S3-N16R8** | Dual-core Xtensa® LX7 @ 240 MHz, 16 MB Quad SPI Flash, 8 MB Octal PSRAM. | **Installed (Rev 0.1)** |
|
||||||
|
| **RF Telemetry** | **Nordic nRF24L01+ Module** | 2.4 GHz ISM band transceiver over shared `SPI2_HOST`. | **Installed (Rev 0.1)** |
|
||||||
|
| **Bulk Decoupling**| **100 µF Electrolytic + Male Headers**| Suppresses nRF24 PTX current spikes; modular header rails for peripherals. | **Installed (Rev 0.1)** |
|
||||||
|
| **Display** | **1.8" ST7789 TFT Color LCD** | 3.3V logic, full-color SPI display **with dedicated `CS` pin** (replacing 7-pin CS-less 1.3" bench OLED). | **Next Upgrade** |
|
||||||
|
| **Joysticks** | **2× K-Silver (KS) PS5 Hall-Effect Modules** | 3.3V active magnetic contactless gimbals for zero stick drift. | **Next Upgrade** |
|
||||||
|
| **UI Input** | **KY-040 Rotary Encoder** | Quadrature encoder (`CLK`, `DT`, `SW`) decoded in hardware via ESP32-S3 `PCNT`. | **Bench Verified** |
|
||||||
|
| **Voice AI** | **MAX4466 Electret Microphone Module** | Analog pre-amplifier with adjustable gain for cloud-connected AI voice assistant input. | **Next Upgrade** |
|
||||||
|
| **Data Logging** | **Arduino Micro SD Card Module** | SPI interface, formatted `FAT32` for local telemetry and configuration logging. | **Next Upgrade** |
|
||||||
|
| **Audio Output** | **1× Passive Buzzer + 2× Active Buzzers** | Passive buzzer for melodies + 2× active buzzers for percussive UI clicks, driven by **2N2222 NPN Transistors**. | **Next Upgrade** |
|
||||||
|
| **Enclosure** | **DT-100 Project Box** | Rigid black ABS desktop/console instrument enclosure (`190 × 137 × 59 mm`). | **Next Upgrade** |
|
||||||
|
| **Switches** | **Waterproof Main + KTS-303 Toggle + Slide** | 12–24V illuminated push-button switch, KTS-303 3-pin toggle switch, and 180° vertical slide switch. | **Next Upgrade** |
|
||||||
|
| **Power System** | **Dual 18650 Li-ion + TP4056 + MT3608** | Dual 18650 cells (4800 mAh), `TP4056` charger, `MT3608` DC-DC boost converter, `1N5817` Schottky & `1N4001` diodes, `100 nF` ceramic caps. | **Next Upgrade** |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Pinout Definitions (ESP32-S3 Controller)
|
||||||
|
|
||||||
|
### 4.1 Current Verified Pin Allocation (`firmware/main/mmcontroller.c`)
|
||||||
|
|
||||||
|
| Bus / Peripheral | Signal | ESP32-S3 Pin | Interface / Mode | Notes |
|
||||||
|
| :--- | :--- | :---: | :--- | :--- |
|
||||||
|
| **SPI Hub (`SPI2_HOST`)** | `MOSI` | `GPIO 11` | SPI Master Output | Shared data line (`nRF24L01+`, Display `SDA`, MicroSD) |
|
||||||
|
| **SPI Hub (`SPI2_HOST`)** | `MISO` | `GPIO 13` | SPI Master Input | Shared data input (`nRF24L01+`, MicroSD) |
|
||||||
|
| **SPI Hub (`SPI2_HOST`)** | `SCK` | `GPIO 12` | SPI Master Clock | Shared clock line (`nRF24L01+`, Display `CLK`, MicroSD) |
|
||||||
|
| **nRF24L01+ Radio** | `CSN` | `GPIO 14` | SPI Chip Select | Dedicated radio bus enable |
|
||||||
|
| **nRF24L01+ Radio** | `CE` | `GPIO 21` | Digital Output | Radio TX/RX power state activation |
|
||||||
|
| **TFT Display (1.8" ST7789)**| `CS` | `GPIO 10` | SPI Chip Select | Dedicated display bus enable |
|
||||||
|
| **TFT Display (1.8" ST7789)**| `DC` | `GPIO 9` | Digital Output | Command vs. frame data selection |
|
||||||
|
| **TFT Display (1.8" ST7789)**| `RES` | `GPIO 8` | Digital Output | Hardware display reset (`BLK` tied to `3.3V`) |
|
||||||
|
| **KY-040 Rotary Encoder** | `CLK` | `GPIO 15` | Hardware `PCNT` | Quadrature channel A (1000 ns glitch filter) |
|
||||||
|
| **KY-040 Rotary Encoder** | `DT` | `GPIO 16` | Hardware `PCNT` | Quadrature channel B (direction sensing) |
|
||||||
|
| **KY-040 Rotary Encoder** | `SW` | `GPIO 17` | Input (`PULLUP`) | Push-button switch (300 ms software debounce) |
|
||||||
|
| **K-Silver Hall Joystick 1**| `VRx` | `GPIO 4` | `ADC1_CH3` (`12 dB`) | Analog X-axis (0–3.3V active Hall sensor) |
|
||||||
|
| **K-Silver Hall Joystick 1**| `VRy` | `GPIO 5` | `ADC1_CH4` (`12 dB`) | Analog Y-axis (0–3.3V active Hall sensor) |
|
||||||
|
|
||||||
|
### 4.2 Planned Pin Allocation for Phase 2 Modules (Safe ESP32-S3 Matrix)
|
||||||
|
|
||||||
|
To avoid ESP32-S3 Octal Flash/PSRAM pins (`GPIO 26–37`), USB-OTG pins (`GPIO 19–20`), strapping pins (`GPIO 0, 3, 45, 46`), and `ADC2` Wi-Fi conflicts, the remaining controller modules map cleanly to:
|
||||||
|
|
||||||
|
| Upcoming Module | Signal | Recommended GPIO | Hardware Resource |
|
||||||
|
| :--- | :--- | :---: | :--- |
|
||||||
|
| **K-Silver Hall Joystick 2** | `VRx2` / `VRy2` | `GPIO 6` / `GPIO 7` | `ADC1_CH5` / `ADC1_CH6` (`12 dB` Atten) |
|
||||||
|
| **MAX4466 Microphone** | `OUT` (Analog) | `GPIO 1` | `ADC1_CH0` (DMA / Oneshot audio sampling) |
|
||||||
|
| **Battery Sense Divider** | `VBAT_SNS` | `GPIO 2` | `ADC1_CH1` (100kΩ / 100kΩ voltage divider) |
|
||||||
|
| **MicroSD Card Module** | `CS_SD` | `GPIO 18` | Shared `SPI2_HOST` Chip Select #3 |
|
||||||
|
| **Passive Buzzer (Melody)** | `BUZ_PWM` | `GPIO 38` | `LEDC` Hardware Timer PWM via `2N2222` |
|
||||||
|
| **Active Buzzers 1 & 2** | `ACT_BUZ_1/2` | `GPIO 39` / `GPIO 40`| Digital Output via `2N2222` NPN low-side switches |
|
||||||
|
| **Toggle / Slide Switches** | `SW_MODE` | `GPIO 41` / `GPIO 42`| Digital Input (`GPIO_PULLUP_ENABLE`) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Hardware Safety & Engineering Rules
|
||||||
|
|
||||||
|
1. **Enclosure Machining RPM Rule:** Do **NOT** use standard fixed `16,000 RPM` rotary tools on the `DT-100` ABS plastic enclosure; high friction melts ABS instead of cutting it. Machining is paused until the variable 3-speed rotary tool with `2.35 mm` diamond cutting discs arrives.
|
||||||
|
2. **Hall-Effect Gimbal Polarity Protection:** Do **NOT** wire the K-Silver (KS) PS5 Hall-effect joystick `VCC` backward. Unlike passive carbon potentiometers, these are active 3.3V CMOS magnetic sensors and will burn out immediately under reverse polarity.
|
||||||
|
3. **nRF24L01+ Burst Decoupling:** Always keep the `100 µF` electrolytic capacitor across the `nRF24L01+` `VCC`/`GND` pins (alongside a `100 nF` ceramic cap for high-frequency noise) to prevent 3.3V rail brown-outs during PTX transmission bursts.
|
||||||
|
4. **2N2222 Base Resistor & Flyback Protection:** Always place a **`1 kΩ` series resistor** between the ESP32-S3 GPIO pin and the Base (`B`) of each `2N2222` NPN transistor (an unresisted BJT base clamps the GPIO to `0.7V` and draws excessive current). Place a **`1N4001` flyback diode** in reverse-parallel across inductive buzzer coils.
|
||||||
|
5. **Multi-Slave SPI Bus Initialization Rule:** When sharing `SPI2_HOST` across `nRF24L01+` (`GPIO 14`), `TFT Display` (`GPIO 10`), and `MicroSD` (`GPIO 18`), configure all three `CS` pins as outputs and drive them **HIGH (`1`)** prior to initializing the first SPI device so uninitialized slaves do not corrupt `MISO` (`GPIO 13`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Immediate Next Steps & Engineering Roadmap
|
||||||
|
|
||||||
|
1. **1.8" ST7789 TFT Migration:** Rewrite the display initialization and frame buffer logic using ESP-IDF's `esp_lcd` component to replace the custom 5×8 monochrome OLED driver once the CS-equipped TFT module is wired.
|
||||||
|
2. **MicroSD Card SPI & FATFS Setup:** Configure the Arduino MicroSD card module on the shared SPI bus and initialize the `FATFS` virtual filesystem (`VFS`) for reading/writing telemetry logs.
|
||||||
|
3. **NVS Hall-Effect Joystick Calibration:** Write the calibration routine for the K-Silver PS5 Hall-effect joysticks—measuring resting center, minimum, and maximum voltages and saving them persistently to ESP32-S3 Non-Volatile Storage (`NVS`) flash.
|
||||||
|
4. **USB HID & Bluetooth Gamepad Stack:** Expose the calibrated Hall-effect axes and buttons as a standard gamepad interface over the ESP32-S3 native USB-OTG port and BLE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Repository Structure & Build Instructions
|
||||||
|
|
||||||
|
```text
|
||||||
|
multi-functional-controller/
|
||||||
|
├── 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
|
||||||
|
│ └── main/
|
||||||
|
│ ├── CMakeLists.txt # Component registration
|
||||||
|
│ └── mmcontroller.c # Master firmware: Shared SPI2, PCNT menu UI, nRF24 tuning
|
||||||
|
├── hardware/ # KiCad 10 Electronic Design Automation (EDA)
|
||||||
|
│ ├── mfc-1.kicad_pro # KiCad project file
|
||||||
|
│ ├── mfc-1.kicad_sch # Rev 0.1 carrier schematic (ESP32-S3, nRF24L01+, 100uF cap)
|
||||||
|
│ └── mfc-1.kicad_pcb # Board layout & routing rules
|
||||||
|
├── images/ # Rev 0.1 early prototype photography & vector schematic
|
||||||
|
│ ├── TOP_VIEW.png # Early build (Rev 0.1) carrier top view
|
||||||
|
│ ├── SIDE_VIEW_WITH_ANTENNA.png # Early build (Rev 0.1) RF antenna & profile view
|
||||||
|
│ ├── BOTTOM_VIEW.png # Early build (Rev 0.1) perfboard underside wiring
|
||||||
|
│ └── mfc-1.svg # Vector export of Rev 0.1 KiCad schematic
|
||||||
|
├── .gitignore # Clean repository filter (builds, caches, local configs)
|
||||||
|
├── LICENSE # MIT License
|
||||||
|
└── README.md # Master engineering documentation
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build & Flash (ESP32-S3 Controller)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
. $HOME/esp/esp-idf/export.sh
|
||||||
|
cd firmware
|
||||||
|
idf.py set-target esp32s3
|
||||||
|
idf.py build
|
||||||
|
idf.py -p /dev/ttyACM0 flash monitor
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Author & Project Links
|
||||||
|
|
||||||
|
- **Author:** [Ertunç Özbay](https://github.com/ertunc-ozbay)
|
||||||
|
- **Personal Workshop & Portfolio:** [ertuncozbay.dev](https://ertuncozbay.dev)
|
||||||
|
- **Project Detail Page:** [ertuncozbay.dev/projects/multi-functional-controller.html](https://ertuncozbay.dev/projects/multi-functional-controller.html)
|
||||||
|
- **License:** [MIT License](LICENSE)
|
||||||
|
|
|
||||||
8
firmware/CMakeLists.txt
Normal file
8
firmware/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
# For more information about build system see
|
||||||
|
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||||
|
# The following five lines of boilerplate have to be in your project's
|
||||||
|
# CMakeLists in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(mmcontroller)
|
||||||
2
firmware/main/CMakeLists.txt
Normal file
2
firmware/main/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
idf_component_register(SRCS "mmcontroller.c"
|
||||||
|
INCLUDE_DIRS ".")
|
||||||
367
firmware/main/mmcontroller.c
Normal file
367
firmware/main/mmcontroller.c
Normal file
|
|
@ -0,0 +1,367 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#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"
|
||||||
|
|
||||||
|
// ==========================================
|
||||||
|
// VERIFIED HARDWARE PIN MAPPINGS
|
||||||
|
// ==========================================
|
||||||
|
#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;
|
||||||
|
|
||||||
|
// Global Radio State
|
||||||
|
int current_radio_channel = 76;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SCREEN_MAIN_MENU = 0,
|
||||||
|
SCREEN_DRIVE,
|
||||||
|
SCREEN_RADIO_CONFIG,
|
||||||
|
SCREEN_CALIBRATE,
|
||||||
|
SCREEN_SYSTEM_INFO
|
||||||
|
} screen_state_t;
|
||||||
|
|
||||||
|
// ==========================================
|
||||||
|
// 5x8 BARE-METAL FONT LIBRARY
|
||||||
|
// ==========================================
|
||||||
|
const uint8_t font_AZ[26][5] = {
|
||||||
|
{0x7E, 0x11, 0x11, 0x11, 0x7E}, {0x7F, 0x49, 0x49, 0x49, 0x36}, {0x3E, 0x41, 0x41, 0x41, 0x22},
|
||||||
|
{0x7F, 0x41, 0x41, 0x22, 0x1C}, {0x7F, 0x49, 0x49, 0x49, 0x41}, {0x7F, 0x09, 0x09, 0x09, 0x01},
|
||||||
|
{0x3E, 0x41, 0x49, 0x49, 0x7A}, {0x7F, 0x08, 0x08, 0x08, 0x7F}, {0x00, 0x41, 0x7F, 0x41, 0x00},
|
||||||
|
{0x20, 0x40, 0x41, 0x3F, 0x01}, {0x7F, 0x08, 0x14, 0x22, 0x41}, {0x7F, 0x40, 0x40, 0x40, 0x40},
|
||||||
|
{0x7F, 0x02, 0x0C, 0x02, 0x7F}, {0x7F, 0x04, 0x08, 0x10, 0x7F}, {0x3E, 0x41, 0x41, 0x41, 0x3E},
|
||||||
|
{0x7F, 0x09, 0x09, 0x09, 0x06}, {0x3E, 0x41, 0x51, 0x21, 0x5E}, {0x7F, 0x09, 0x19, 0x29, 0x46},
|
||||||
|
{0x46, 0x49, 0x49, 0x49, 0x31}, {0x01, 0x01, 0x7F, 0x01, 0x01}, {0x3F, 0x40, 0x40, 0x40, 0x3F},
|
||||||
|
{0x1F, 0x20, 0x40, 0x20, 0x1F}, {0x3F, 0x40, 0x38, 0x40, 0x3F}, {0x63, 0x14, 0x08, 0x14, 0x63},
|
||||||
|
{0x03, 0x04, 0x78, 0x04, 0x03}, {0x61, 0x51, 0x49, 0x45, 0x43}
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t font_nums[10][5] = {
|
||||||
|
{0x3E, 0x51, 0x49, 0x45, 0x3E}, {0x00, 0x42, 0x7F, 0x40, 0x00}, {0x42, 0x61, 0x51, 0x49, 0x46},
|
||||||
|
{0x21, 0x41, 0x45, 0x4B, 0x31}, {0x18, 0x14, 0x12, 0x7F, 0x10}, {0x27, 0x45, 0x45, 0x45, 0x39},
|
||||||
|
{0x3C, 0x4A, 0x49, 0x49, 0x30}, {0x01, 0x71, 0x09, 0x05, 0x03}, {0x36, 0x49, 0x49, 0x49, 0x36},
|
||||||
|
{0x06, 0x49, 0x49, 0x29, 0x1E}
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t* get_font_data(char c) {
|
||||||
|
static const uint8_t f_spc[5] = {0,0,0,0,0};
|
||||||
|
static const uint8_t f_ptr[5] = {0x08, 0x04, 0x7E, 0x04, 0x08}; // '>'
|
||||||
|
static const uint8_t f_lt[5] = {0x08, 0x14, 0x22, 0x41, 0x00}; // '<'
|
||||||
|
static const uint8_t f_lbr[5] = {0x00, 0x7F, 0x41, 0x41, 0x00}; // '['
|
||||||
|
static const uint8_t f_rbr[5] = {0x00, 0x41, 0x41, 0x7F, 0x00}; // ']'
|
||||||
|
static const uint8_t f_lpar[5] = {0x00, 0x1C, 0x22, 0x41, 0x00}; // '('
|
||||||
|
static const uint8_t f_rpar[5] = {0x00, 0x41, 0x22, 0x1C, 0x00}; // ')'
|
||||||
|
static const uint8_t f_slash[5] = {0x20, 0x10, 0x08, 0x04, 0x02}; // '/'
|
||||||
|
static const uint8_t f_dash[5] = {0x08, 0x08, 0x08, 0x08, 0x08}; // '-'
|
||||||
|
static const uint8_t f_col[5] = {0x00, 0x36, 0x36, 0x00, 0x00}; // ':'
|
||||||
|
static const uint8_t f_dot[5] = {0x00, 0x60, 0x60, 0x00, 0x00}; // '.'
|
||||||
|
|
||||||
|
if (c >= 'A' && c <= 'Z') { return font_AZ[c - 'A']; }
|
||||||
|
if (c >= '0' && c <= '9') { return font_nums[c - '0']; }
|
||||||
|
if (c == '>') { return f_ptr; }
|
||||||
|
if (c == '<') { return f_lt; }
|
||||||
|
if (c == '[') { return f_lbr; }
|
||||||
|
if (c == ']') { return f_rbr; }
|
||||||
|
if (c == '(') { return f_lpar; }
|
||||||
|
if (c == ')') { return f_rpar; }
|
||||||
|
if (c == '/') { return f_slash; }
|
||||||
|
if (c == '-') { return f_dash; }
|
||||||
|
if (c == ':') { return f_col; }
|
||||||
|
if (c == '.') { return f_dot; }
|
||||||
|
return f_spc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================
|
||||||
|
// OLED & NRF SPI DRIVERS
|
||||||
|
// ==========================================
|
||||||
|
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; // SH1106 center offset
|
||||||
|
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 }; // Write to RF_CH register (0x05)
|
||||||
|
spi_transaction_t t = { .length = 16, .tx_buffer = tx };
|
||||||
|
spi_device_polling_transmit(nrf_spi, &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================
|
||||||
|
// UI SCREEN RENDERING
|
||||||
|
// ==========================================
|
||||||
|
void draw_menu(int selected_index) {
|
||||||
|
char* items[] = {"DRIVE VEHICLE", "RADIO CONFIG", "CALIBRATE", "SYSTEM INFO"};
|
||||||
|
char buffer[32];
|
||||||
|
|
||||||
|
oled_draw_string(0, 20, "- MAIN MENU -");
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_MENU_ITEMS; i++) {
|
||||||
|
if (i == selected_index) {
|
||||||
|
sprintf(buffer, "> %-14s", items[i]);
|
||||||
|
} else {
|
||||||
|
sprintf(buffer, " %-14s", items[i]);
|
||||||
|
}
|
||||||
|
oled_draw_string(2 + (i * 2), 5, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_system_info() {
|
||||||
|
char buffer[32];
|
||||||
|
oled_draw_string(0, 15, "- SYSTEM INFO -");
|
||||||
|
|
||||||
|
sprintf(buffer, "CHIP: ESP32-S3");
|
||||||
|
oled_draw_string(2, 5, buffer);
|
||||||
|
|
||||||
|
sprintf(buffer, "HEAP: %lu KB", (unsigned long)(esp_get_free_heap_size() / 1024));
|
||||||
|
oled_draw_string(4, 5, buffer);
|
||||||
|
|
||||||
|
oled_draw_string(6, 10, "[CLICK TO BACK]");
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_radio_config_screen(int channel) {
|
||||||
|
char buffer[32];
|
||||||
|
oled_draw_string(0, 5, "- RADIO CONFIG -");
|
||||||
|
|
||||||
|
if (nrf_check_connection()) {
|
||||||
|
sprintf(buffer, "CH: <%03d> (2.4G)", channel);
|
||||||
|
oled_draw_string(2, 2, buffer);
|
||||||
|
oled_draw_string(4, 2, "TURN DIAL TO TUNE");
|
||||||
|
} else {
|
||||||
|
oled_draw_string(2, 2, "STATUS: FAILED ");
|
||||||
|
oled_draw_string(4, 2, "CHECK WIRING ");
|
||||||
|
}
|
||||||
|
|
||||||
|
oled_draw_string(6, 5, "[CLICK TO SAVE]");
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_placeholder_screen(const char* title) {
|
||||||
|
oled_draw_string(0, 15, title);
|
||||||
|
oled_draw_string(3, 20, "NOT CONNECTED");
|
||||||
|
oled_draw_string(6, 10, "[CLICK TO BACK]");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================
|
||||||
|
// MAIN APPLICATION ENTRY
|
||||||
|
// ==========================================
|
||||||
|
void app_main(void) {
|
||||||
|
// 1. Initialize Shared SPI Bus
|
||||||
|
spi_bus_config_t buscfg = {
|
||||||
|
.miso_io_num = PIN_NUM_MISO,
|
||||||
|
.mosi_io_num = PIN_NUM_MOSI,
|
||||||
|
.sclk_io_num = PIN_NUM_CLK,
|
||||||
|
.quadwp_io_num = -1,
|
||||||
|
.quadhd_io_num = -1,
|
||||||
|
.max_transfer_sz = 4096
|
||||||
|
};
|
||||||
|
spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);
|
||||||
|
|
||||||
|
// 2. Add OLED Device
|
||||||
|
spi_device_interface_config_t oled_cfg = {
|
||||||
|
.clock_speed_hz = 10 * 1000 * 1000,
|
||||||
|
.mode = 0,
|
||||||
|
.spics_io_num = OLED_PIN_CS,
|
||||||
|
.queue_size = 1
|
||||||
|
};
|
||||||
|
spi_bus_add_device(SPI2_HOST, &oled_cfg, &oled_spi);
|
||||||
|
gpio_reset_pin(OLED_PIN_DC); gpio_set_direction(OLED_PIN_DC, GPIO_MODE_OUTPUT);
|
||||||
|
gpio_reset_pin(OLED_PIN_RES); gpio_set_direction(OLED_PIN_RES, GPIO_MODE_OUTPUT);
|
||||||
|
|
||||||
|
oled_init();
|
||||||
|
oled_clear();
|
||||||
|
|
||||||
|
// 3. Add NRF24 Device
|
||||||
|
spi_device_interface_config_t nrf_cfg = {
|
||||||
|
.clock_speed_hz = 1 * 1000 * 1000,
|
||||||
|
.mode = 0,
|
||||||
|
.spics_io_num = NRF_PIN_CS,
|
||||||
|
.queue_size = 1
|
||||||
|
};
|
||||||
|
spi_bus_add_device(SPI2_HOST, &nrf_cfg, &nrf_spi);
|
||||||
|
|
||||||
|
// 4. Init Rotary Encoder Switch
|
||||||
|
gpio_config_t sw_cfg = {
|
||||||
|
.pin_bit_mask = (1ULL << PIN_ENCODER_SW),
|
||||||
|
.mode = GPIO_MODE_INPUT,
|
||||||
|
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||||
|
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||||
|
.intr_type = GPIO_INTR_DISABLE
|
||||||
|
};
|
||||||
|
gpio_config(&sw_cfg);
|
||||||
|
|
||||||
|
// 5. Init PCNT Hardware Decoder for Quadrature Encoder
|
||||||
|
pcnt_unit_handle_t pcnt_unit = NULL;
|
||||||
|
pcnt_unit_config_t unit_config = { .high_limit = 10000, .low_limit = -10000 };
|
||||||
|
pcnt_new_unit(&unit_config, &pcnt_unit);
|
||||||
|
|
||||||
|
pcnt_glitch_filter_config_t filter_config = { .max_glitch_ns = 1000 };
|
||||||
|
pcnt_unit_set_glitch_filter(pcnt_unit, &filter_config);
|
||||||
|
|
||||||
|
pcnt_channel_handle_t pcnt_chan_a = NULL, pcnt_chan_b = NULL;
|
||||||
|
pcnt_chan_config_t chan_a_config = { .edge_gpio_num = PIN_ENCODER_CLK, .level_gpio_num = PIN_ENCODER_DT };
|
||||||
|
pcnt_new_channel(pcnt_unit, &chan_a_config, &pcnt_chan_a);
|
||||||
|
pcnt_chan_config_t chan_b_config = { .edge_gpio_num = PIN_ENCODER_DT, .level_gpio_num = PIN_ENCODER_CLK };
|
||||||
|
pcnt_new_channel(pcnt_unit, &chan_b_config, &pcnt_chan_b);
|
||||||
|
|
||||||
|
pcnt_channel_set_edge_action(pcnt_chan_a, PCNT_CHANNEL_EDGE_ACTION_DECREASE, PCNT_CHANNEL_EDGE_ACTION_INCREASE);
|
||||||
|
pcnt_channel_set_level_action(pcnt_chan_a, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_INVERSE);
|
||||||
|
pcnt_channel_set_edge_action(pcnt_chan_b, PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_DECREASE);
|
||||||
|
pcnt_channel_set_level_action(pcnt_chan_b, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_INVERSE);
|
||||||
|
|
||||||
|
pcnt_unit_enable(pcnt_unit);
|
||||||
|
pcnt_unit_clear_count(pcnt_unit);
|
||||||
|
pcnt_unit_start(pcnt_unit);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "MFC Multi-Tasking OS State Machine Online.");
|
||||||
|
|
||||||
|
// 6. Master UI State Machine Loop
|
||||||
|
int count = 0;
|
||||||
|
int last_menu_index = -1;
|
||||||
|
int 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;
|
||||||
|
int last_tuned_channel = current_radio_channel;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
pcnt_unit_get_count(pcnt_unit, &count);
|
||||||
|
int sw_state = gpio_get_level(PIN_ENCODER_SW);
|
||||||
|
|
||||||
|
if (current_screen == SCREEN_MAIN_MENU) {
|
||||||
|
int raw_steps = count / 4;
|
||||||
|
int current_menu_index = ((raw_steps % NUM_MENU_ITEMS) + NUM_MENU_ITEMS) % NUM_MENU_ITEMS;
|
||||||
|
|
||||||
|
if (current_menu_index != last_menu_index || screen_needs_redraw) {
|
||||||
|
oled_clear();
|
||||||
|
draw_menu(current_menu_index);
|
||||||
|
last_menu_index = current_menu_index;
|
||||||
|
screen_needs_redraw = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Click to Select with 300ms Debounce
|
||||||
|
if (sw_state == 0 && last_sw_state == 1) {
|
||||||
|
if ((xTaskGetTickCount() - last_button_press) > pdMS_TO_TICKS(300)) {
|
||||||
|
current_screen = (screen_state_t)(current_menu_index + 1);
|
||||||
|
screen_needs_redraw = true;
|
||||||
|
|
||||||
|
if (current_screen == SCREEN_RADIO_CONFIG) {
|
||||||
|
radio_start_count = count;
|
||||||
|
last_tuned_channel = current_radio_channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_button_press = xTaskGetTickCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Sub-screen handling
|
||||||
|
if (current_screen == SCREEN_RADIO_CONFIG) {
|
||||||
|
int encoder_delta = (count - radio_start_count) / 4;
|
||||||
|
int target_channel = current_radio_channel + encoder_delta;
|
||||||
|
|
||||||
|
if (target_channel < 0) target_channel = 0;
|
||||||
|
if (target_channel > 125) target_channel = 125;
|
||||||
|
|
||||||
|
if (target_channel != last_tuned_channel || screen_needs_redraw) {
|
||||||
|
current_radio_channel = target_channel;
|
||||||
|
set_nrf_channel(current_radio_channel);
|
||||||
|
|
||||||
|
oled_clear();
|
||||||
|
draw_radio_config_screen(current_radio_channel);
|
||||||
|
last_tuned_channel = target_channel;
|
||||||
|
screen_needs_redraw = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (screen_needs_redraw) {
|
||||||
|
oled_clear();
|
||||||
|
if (current_screen == SCREEN_SYSTEM_INFO) {
|
||||||
|
draw_system_info();
|
||||||
|
} else if (current_screen == SCREEN_DRIVE) {
|
||||||
|
draw_placeholder_screen("- DRIVE VEHICLE -");
|
||||||
|
} else if (current_screen == SCREEN_CALIBRATE) {
|
||||||
|
draw_placeholder_screen("- CALIBRATION -");
|
||||||
|
}
|
||||||
|
screen_needs_redraw = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Click to return to Main Menu with 300ms Debounce
|
||||||
|
if (sw_state == 0 && last_sw_state == 1) {
|
||||||
|
if ((xTaskGetTickCount() - last_button_press) > pdMS_TO_TICKS(300)) {
|
||||||
|
current_screen = SCREEN_MAIN_MENU;
|
||||||
|
screen_needs_redraw = true;
|
||||||
|
last_button_press = xTaskGetTickCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
last_sw_state = sw_state;
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(30));
|
||||||
|
}
|
||||||
|
}
|
||||||
2081
firmware/sdkconfig
Normal file
2081
firmware/sdkconfig
Normal file
File diff suppressed because it is too large
Load diff
2
hardware/mfc-1.kicad_pcb
Normal file
2
hardware/mfc-1.kicad_pcb
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
(kicad_pcb (version 20260206) (generator "pcbnew") (generator_version "10.0")
|
||||||
|
)
|
||||||
680
hardware/mfc-1.kicad_pro
Normal file
680
hardware/mfc-1.kicad_pro
Normal file
|
|
@ -0,0 +1,680 @@
|
||||||
|
{
|
||||||
|
"board": {
|
||||||
|
"3dviewports": [],
|
||||||
|
"design_settings": {
|
||||||
|
"defaults": {
|
||||||
|
"apply_defaults_to_fp_barcodes": false,
|
||||||
|
"apply_defaults_to_fp_dimensions": false,
|
||||||
|
"apply_defaults_to_fp_fields": false,
|
||||||
|
"apply_defaults_to_fp_shapes": false,
|
||||||
|
"apply_defaults_to_fp_text": false,
|
||||||
|
"board_outline_line_width": 0.05,
|
||||||
|
"copper_line_width": 0.2,
|
||||||
|
"copper_text_italic": false,
|
||||||
|
"copper_text_size_h": 1.5,
|
||||||
|
"copper_text_size_v": 1.5,
|
||||||
|
"copper_text_thickness": 0.3,
|
||||||
|
"copper_text_upright": false,
|
||||||
|
"courtyard_line_width": 0.05,
|
||||||
|
"dimension_precision": 4,
|
||||||
|
"dimension_units": 3,
|
||||||
|
"dimensions": {
|
||||||
|
"arrow_length": 1270000,
|
||||||
|
"extension_offset": 500000,
|
||||||
|
"keep_text_aligned": true,
|
||||||
|
"suppress_zeroes": true,
|
||||||
|
"text_position": 0,
|
||||||
|
"units_format": 0
|
||||||
|
},
|
||||||
|
"fab_line_width": 0.1,
|
||||||
|
"fab_text_italic": false,
|
||||||
|
"fab_text_size_h": 1.0,
|
||||||
|
"fab_text_size_v": 1.0,
|
||||||
|
"fab_text_thickness": 0.15,
|
||||||
|
"fab_text_upright": false,
|
||||||
|
"other_line_width": 0.1,
|
||||||
|
"other_text_italic": false,
|
||||||
|
"other_text_size_h": 1.0,
|
||||||
|
"other_text_size_v": 1.0,
|
||||||
|
"other_text_thickness": 0.15,
|
||||||
|
"other_text_upright": false,
|
||||||
|
"pads": {
|
||||||
|
"drill": 0.8,
|
||||||
|
"height": 1.27,
|
||||||
|
"width": 1.27
|
||||||
|
},
|
||||||
|
"silk_line_width": 0.1,
|
||||||
|
"silk_text_italic": false,
|
||||||
|
"silk_text_size_h": 1.0,
|
||||||
|
"silk_text_size_v": 1.0,
|
||||||
|
"silk_text_thickness": 0.1,
|
||||||
|
"silk_text_upright": false,
|
||||||
|
"zones": {
|
||||||
|
"border_display_style": 2,
|
||||||
|
"border_hatch_pitch": 0.5,
|
||||||
|
"corner_radius": 0.0,
|
||||||
|
"corner_smoothing": 0,
|
||||||
|
"fill_mode": 0,
|
||||||
|
"hatch_gap": 1.5,
|
||||||
|
"hatch_orientation": 0.0,
|
||||||
|
"hatch_smoothing_level": 0,
|
||||||
|
"hatch_smoothing_value": 0.1,
|
||||||
|
"hatch_thickness": 1.0,
|
||||||
|
"min_clearance": 0.5,
|
||||||
|
"min_island_area": 10.0,
|
||||||
|
"min_thickness": 0.25,
|
||||||
|
"pad_connection": 1,
|
||||||
|
"remove_islands": 0,
|
||||||
|
"thermal_relief_gap": 0.5,
|
||||||
|
"thermal_relief_spoke_width": 0.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"diff_pair_dimensions": [],
|
||||||
|
"drc_exclusions": [],
|
||||||
|
"meta": {
|
||||||
|
"version": 2
|
||||||
|
},
|
||||||
|
"rule_severities": {
|
||||||
|
"annular_width": "error",
|
||||||
|
"clearance": "error",
|
||||||
|
"connection_width": "warning",
|
||||||
|
"copper_edge_clearance": "error",
|
||||||
|
"copper_sliver": "warning",
|
||||||
|
"courtyards_overlap": "error",
|
||||||
|
"creepage": "error",
|
||||||
|
"diff_pair_gap_out_of_range": "error",
|
||||||
|
"diff_pair_uncoupled_length_too_long": "error",
|
||||||
|
"drill_out_of_range": "error",
|
||||||
|
"duplicate_footprints": "warning",
|
||||||
|
"extra_footprint": "warning",
|
||||||
|
"footprint": "error",
|
||||||
|
"footprint_filters_mismatch": "ignore",
|
||||||
|
"footprint_symbol_field_mismatch": "warning",
|
||||||
|
"footprint_symbol_mismatch": "warning",
|
||||||
|
"footprint_type_mismatch": "ignore",
|
||||||
|
"hole_clearance": "error",
|
||||||
|
"hole_to_hole": "warning",
|
||||||
|
"holes_co_located": "warning",
|
||||||
|
"invalid_outline": "error",
|
||||||
|
"isolated_copper": "warning",
|
||||||
|
"item_on_disabled_layer": "error",
|
||||||
|
"items_not_allowed": "error",
|
||||||
|
"length_out_of_range": "error",
|
||||||
|
"lib_footprint_issues": "warning",
|
||||||
|
"lib_footprint_mismatch": "warning",
|
||||||
|
"malformed_courtyard": "error",
|
||||||
|
"microvia_drill_out_of_range": "error",
|
||||||
|
"mirrored_text_on_front_layer": "warning",
|
||||||
|
"missing_courtyard": "ignore",
|
||||||
|
"missing_footprint": "warning",
|
||||||
|
"missing_tuning_profile": "warning",
|
||||||
|
"net_conflict": "warning",
|
||||||
|
"nonmirrored_text_on_back_layer": "warning",
|
||||||
|
"npth_inside_courtyard": "error",
|
||||||
|
"padstack": "warning",
|
||||||
|
"pth_inside_courtyard": "error",
|
||||||
|
"shorting_items": "error",
|
||||||
|
"silk_edge_clearance": "warning",
|
||||||
|
"silk_over_copper": "warning",
|
||||||
|
"silk_overlap": "warning",
|
||||||
|
"skew_out_of_range": "error",
|
||||||
|
"solder_mask_bridge": "error",
|
||||||
|
"starved_thermal": "error",
|
||||||
|
"text_height": "warning",
|
||||||
|
"text_on_edge_cuts": "error",
|
||||||
|
"text_thickness": "warning",
|
||||||
|
"through_hole_pad_without_hole": "error",
|
||||||
|
"too_many_vias": "error",
|
||||||
|
"track_angle": "error",
|
||||||
|
"track_dangling": "warning",
|
||||||
|
"track_not_centered_on_via": "ignore",
|
||||||
|
"track_on_post_machined_layer": "error",
|
||||||
|
"track_segment_length": "error",
|
||||||
|
"track_width": "error",
|
||||||
|
"tracks_crossing": "error",
|
||||||
|
"tuning_profile_track_geometries": "ignore",
|
||||||
|
"unconnected_items": "error",
|
||||||
|
"unresolved_variable": "error",
|
||||||
|
"via_dangling": "warning",
|
||||||
|
"zones_intersect": "error"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"max_error": 0.005,
|
||||||
|
"min_clearance": 0.0,
|
||||||
|
"min_connection": 0.0,
|
||||||
|
"min_copper_edge_clearance": 0.5,
|
||||||
|
"min_groove_width": 0.0,
|
||||||
|
"min_hole_clearance": 0.25,
|
||||||
|
"min_hole_to_hole": 0.25,
|
||||||
|
"min_microvia_diameter": 0.2,
|
||||||
|
"min_microvia_drill": 0.1,
|
||||||
|
"min_resolved_spokes": 2,
|
||||||
|
"min_silk_clearance": 0.0,
|
||||||
|
"min_text_height": 0.8,
|
||||||
|
"min_text_thickness": 0.08,
|
||||||
|
"min_through_hole_diameter": 0.3,
|
||||||
|
"min_track_width": 0.2,
|
||||||
|
"min_via_annular_width": 0.1,
|
||||||
|
"min_via_diameter": 0.5,
|
||||||
|
"solder_mask_to_copper_clearance": 0.0,
|
||||||
|
"use_height_for_length_calcs": true
|
||||||
|
},
|
||||||
|
"teardrop_options": [
|
||||||
|
{
|
||||||
|
"td_onpthpad": true,
|
||||||
|
"td_onroundshapesonly": false,
|
||||||
|
"td_onsmdpad": true,
|
||||||
|
"td_ontrackend": false,
|
||||||
|
"td_onvia": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"teardrop_parameters": [
|
||||||
|
{
|
||||||
|
"td_allow_use_two_tracks": true,
|
||||||
|
"td_curve_segcount": 0,
|
||||||
|
"td_height_ratio": 1.0,
|
||||||
|
"td_length_ratio": 0.5,
|
||||||
|
"td_maxheight": 2.0,
|
||||||
|
"td_maxlen": 1.0,
|
||||||
|
"td_on_pad_in_zone": false,
|
||||||
|
"td_target_name": "td_round_shape",
|
||||||
|
"td_width_to_size_filter_ratio": 0.9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"td_allow_use_two_tracks": true,
|
||||||
|
"td_curve_segcount": 0,
|
||||||
|
"td_height_ratio": 1.0,
|
||||||
|
"td_length_ratio": 0.5,
|
||||||
|
"td_maxheight": 2.0,
|
||||||
|
"td_maxlen": 1.0,
|
||||||
|
"td_on_pad_in_zone": false,
|
||||||
|
"td_target_name": "td_rect_shape",
|
||||||
|
"td_width_to_size_filter_ratio": 0.9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"td_allow_use_two_tracks": true,
|
||||||
|
"td_curve_segcount": 0,
|
||||||
|
"td_height_ratio": 1.0,
|
||||||
|
"td_length_ratio": 0.5,
|
||||||
|
"td_maxheight": 2.0,
|
||||||
|
"td_maxlen": 1.0,
|
||||||
|
"td_on_pad_in_zone": false,
|
||||||
|
"td_target_name": "td_track_end",
|
||||||
|
"td_width_to_size_filter_ratio": 0.9
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"track_widths": [],
|
||||||
|
"tuning_pattern_settings": {
|
||||||
|
"diff_pair_defaults": {
|
||||||
|
"corner_radius_percentage": 80,
|
||||||
|
"corner_style": 1,
|
||||||
|
"max_amplitude": 1.0,
|
||||||
|
"min_amplitude": 0.2,
|
||||||
|
"single_sided": false,
|
||||||
|
"spacing": 1.0
|
||||||
|
},
|
||||||
|
"diff_pair_skew_defaults": {
|
||||||
|
"corner_radius_percentage": 80,
|
||||||
|
"corner_style": 1,
|
||||||
|
"max_amplitude": 1.0,
|
||||||
|
"min_amplitude": 0.2,
|
||||||
|
"single_sided": false,
|
||||||
|
"spacing": 0.6
|
||||||
|
},
|
||||||
|
"single_track_defaults": {
|
||||||
|
"corner_radius_percentage": 80,
|
||||||
|
"corner_style": 1,
|
||||||
|
"max_amplitude": 1.0,
|
||||||
|
"min_amplitude": 0.2,
|
||||||
|
"single_sided": false,
|
||||||
|
"spacing": 0.6
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"via_dimensions": [],
|
||||||
|
"zones_allow_external_fillets": false
|
||||||
|
},
|
||||||
|
"ipc2581": {
|
||||||
|
"bom_rev": "",
|
||||||
|
"dist": "",
|
||||||
|
"distpn": "",
|
||||||
|
"internal_id": "",
|
||||||
|
"mfg": "",
|
||||||
|
"mpn": "",
|
||||||
|
"sch_revision": ""
|
||||||
|
},
|
||||||
|
"layer_pairs": [],
|
||||||
|
"layer_presets": [],
|
||||||
|
"viewports": []
|
||||||
|
},
|
||||||
|
"boards": [],
|
||||||
|
"component_class_settings": {
|
||||||
|
"assignments": [],
|
||||||
|
"meta": {
|
||||||
|
"version": 0
|
||||||
|
},
|
||||||
|
"sheet_component_classes": {
|
||||||
|
"enabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cvpcb": {
|
||||||
|
"equivalence_files": []
|
||||||
|
},
|
||||||
|
"erc": {
|
||||||
|
"erc_exclusions": [],
|
||||||
|
"meta": {
|
||||||
|
"version": 0
|
||||||
|
},
|
||||||
|
"pin_map": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"rule_severities": {
|
||||||
|
"bus_definition_conflict": "error",
|
||||||
|
"bus_entry_needed": "error",
|
||||||
|
"bus_to_bus_conflict": "error",
|
||||||
|
"bus_to_net_conflict": "error",
|
||||||
|
"different_unit_footprint": "error",
|
||||||
|
"different_unit_net": "error",
|
||||||
|
"duplicate_reference": "error",
|
||||||
|
"duplicate_sheet_names": "error",
|
||||||
|
"endpoint_off_grid": "warning",
|
||||||
|
"extra_units": "error",
|
||||||
|
"field_name_whitespace": "warning",
|
||||||
|
"footprint_filter": "ignore",
|
||||||
|
"footprint_link_issues": "warning",
|
||||||
|
"four_way_junction": "ignore",
|
||||||
|
"ground_pin_not_ground": "warning",
|
||||||
|
"hier_label_mismatch": "error",
|
||||||
|
"isolated_pin_label": "warning",
|
||||||
|
"label_dangling": "error",
|
||||||
|
"label_multiple_wires": "warning",
|
||||||
|
"lib_symbol_issues": "warning",
|
||||||
|
"lib_symbol_mismatch": "warning",
|
||||||
|
"missing_bidi_pin": "warning",
|
||||||
|
"missing_input_pin": "warning",
|
||||||
|
"missing_power_pin": "error",
|
||||||
|
"missing_unit": "warning",
|
||||||
|
"multiple_net_names": "warning",
|
||||||
|
"net_not_bus_member": "warning",
|
||||||
|
"no_connect_connected": "warning",
|
||||||
|
"no_connect_dangling": "warning",
|
||||||
|
"pin_not_connected": "error",
|
||||||
|
"pin_not_driven": "error",
|
||||||
|
"pin_to_pin": "warning",
|
||||||
|
"power_pin_not_driven": "error",
|
||||||
|
"same_local_global_label": "warning",
|
||||||
|
"similar_label_and_power": "warning",
|
||||||
|
"similar_labels": "warning",
|
||||||
|
"similar_power": "warning",
|
||||||
|
"simulation_model_issue": "ignore",
|
||||||
|
"single_global_label": "ignore",
|
||||||
|
"stacked_pin_name": "warning",
|
||||||
|
"unannotated": "error",
|
||||||
|
"unconnected_wire_endpoint": "warning",
|
||||||
|
"undefined_netclass": "error",
|
||||||
|
"unit_value_mismatch": "error",
|
||||||
|
"unresolved_variable": "error",
|
||||||
|
"wire_dangling": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libraries": {
|
||||||
|
"pinned_footprint_libs": [],
|
||||||
|
"pinned_symbol_libs": []
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"filename": "mfc-1.kicad_pro",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"net_settings": {
|
||||||
|
"classes": [
|
||||||
|
{
|
||||||
|
"bus_width": 12,
|
||||||
|
"clearance": 0.2,
|
||||||
|
"diff_pair_gap": 0.25,
|
||||||
|
"diff_pair_via_gap": 0.25,
|
||||||
|
"diff_pair_width": 0.2,
|
||||||
|
"line_style": 0,
|
||||||
|
"microvia_diameter": 0.3,
|
||||||
|
"microvia_drill": 0.1,
|
||||||
|
"name": "Default",
|
||||||
|
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
||||||
|
"priority": 2147483647,
|
||||||
|
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
||||||
|
"track_width": 0.2,
|
||||||
|
"tuning_profile": "",
|
||||||
|
"via_diameter": 0.6,
|
||||||
|
"via_drill": 0.3,
|
||||||
|
"wire_width": 6
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"version": 5
|
||||||
|
},
|
||||||
|
"net_colors": null,
|
||||||
|
"netclass_assignments": null,
|
||||||
|
"netclass_patterns": []
|
||||||
|
},
|
||||||
|
"pcbnew": {
|
||||||
|
"last_paths": {
|
||||||
|
"idf": "",
|
||||||
|
"netlist": "",
|
||||||
|
"plot": "",
|
||||||
|
"specctra_dsn": "",
|
||||||
|
"step": "",
|
||||||
|
"vrml": ""
|
||||||
|
},
|
||||||
|
"page_layout_descr_file": ""
|
||||||
|
},
|
||||||
|
"schematic": {
|
||||||
|
"annotate_start_num": 0,
|
||||||
|
"annotation": {
|
||||||
|
"method": 0,
|
||||||
|
"sort_order": 0
|
||||||
|
},
|
||||||
|
"bom_export_filename": "${PROJECTNAME}.csv",
|
||||||
|
"bom_fmt_presets": [],
|
||||||
|
"bom_fmt_settings": {
|
||||||
|
"field_delimiter": ",",
|
||||||
|
"keep_line_breaks": false,
|
||||||
|
"keep_tabs": false,
|
||||||
|
"name": "CSV",
|
||||||
|
"ref_delimiter": ",",
|
||||||
|
"ref_range_delimiter": "",
|
||||||
|
"string_delimiter": "\""
|
||||||
|
},
|
||||||
|
"bom_presets": [],
|
||||||
|
"bom_settings": {
|
||||||
|
"exclude_dnp": false,
|
||||||
|
"fields_ordered": [
|
||||||
|
{
|
||||||
|
"group_by": false,
|
||||||
|
"label": "Reference",
|
||||||
|
"name": "Reference",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": false,
|
||||||
|
"label": "Qty",
|
||||||
|
"name": "${QUANTITY}",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": true,
|
||||||
|
"label": "Value",
|
||||||
|
"name": "Value",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": true,
|
||||||
|
"label": "DNP",
|
||||||
|
"name": "${DNP}",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": true,
|
||||||
|
"label": "Exclude from BOM",
|
||||||
|
"name": "${EXCLUDE_FROM_BOM}",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": true,
|
||||||
|
"label": "Exclude from Board",
|
||||||
|
"name": "${EXCLUDE_FROM_BOARD}",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": true,
|
||||||
|
"label": "Exclude from Simulation",
|
||||||
|
"name": "${EXCLUDE_FROM_SIM}",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": true,
|
||||||
|
"label": "Exclude from Position Files",
|
||||||
|
"name": "${EXCLUDE_FROM_POS_FILES}",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": true,
|
||||||
|
"label": "Footprint",
|
||||||
|
"name": "Footprint",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": false,
|
||||||
|
"label": "Datasheet",
|
||||||
|
"name": "Datasheet",
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filter_string": "",
|
||||||
|
"group_symbols": true,
|
||||||
|
"include_excluded_from_bom": true,
|
||||||
|
"name": "Default Editing",
|
||||||
|
"sort_asc": true,
|
||||||
|
"sort_field": "Reference"
|
||||||
|
},
|
||||||
|
"bus_aliases": {},
|
||||||
|
"connection_grid_size": 50.0,
|
||||||
|
"drawing": {
|
||||||
|
"dashed_lines_dash_length_ratio": 12.0,
|
||||||
|
"dashed_lines_gap_length_ratio": 3.0,
|
||||||
|
"default_line_thickness": 6.0,
|
||||||
|
"default_text_size": 50.0,
|
||||||
|
"field_names": [],
|
||||||
|
"hop_over_size_choice": 0,
|
||||||
|
"intersheets_ref_own_page": false,
|
||||||
|
"intersheets_ref_prefix": "",
|
||||||
|
"intersheets_ref_short": false,
|
||||||
|
"intersheets_ref_show": false,
|
||||||
|
"intersheets_ref_suffix": "",
|
||||||
|
"junction_size_choice": 3,
|
||||||
|
"label_size_ratio": 0.375,
|
||||||
|
"operating_point_overlay_i_precision": 3,
|
||||||
|
"operating_point_overlay_i_range": "~A",
|
||||||
|
"operating_point_overlay_v_precision": 3,
|
||||||
|
"operating_point_overlay_v_range": "~V",
|
||||||
|
"overbar_offset_ratio": 1.23,
|
||||||
|
"pin_symbol_size": 25.0,
|
||||||
|
"text_offset_ratio": 0.15
|
||||||
|
},
|
||||||
|
"legacy_lib_dir": "",
|
||||||
|
"legacy_lib_list": [],
|
||||||
|
"meta": {
|
||||||
|
"version": 1
|
||||||
|
},
|
||||||
|
"page_layout_descr_file": "",
|
||||||
|
"plot_directory": "",
|
||||||
|
"reuse_designators": true,
|
||||||
|
"subpart_first_id": 65,
|
||||||
|
"subpart_id_separator": 0,
|
||||||
|
"top_level_sheets": [
|
||||||
|
{
|
||||||
|
"filename": "mfc-1.kicad_sch",
|
||||||
|
"name": "Root",
|
||||||
|
"uuid": "859e05b1-62ca-4191-b0be-c155eab457bb"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"used_designators": "C1,U1-2",
|
||||||
|
"variants": []
|
||||||
|
},
|
||||||
|
"sheets": [
|
||||||
|
[
|
||||||
|
"859e05b1-62ca-4191-b0be-c155eab457bb",
|
||||||
|
"Root"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"text_variables": {},
|
||||||
|
"tuning_profiles": {
|
||||||
|
"meta": {
|
||||||
|
"version": 0
|
||||||
|
},
|
||||||
|
"tuning_profiles_impedance_geometric": []
|
||||||
|
}
|
||||||
|
}
|
||||||
2441
hardware/mfc-1.kicad_sch
Normal file
2441
hardware/mfc-1.kicad_sch
Normal file
File diff suppressed because it is too large
Load diff
BIN
images/BOTTOM_VIEW.png
Normal file
BIN
images/BOTTOM_VIEW.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.5 MiB |
BIN
images/SIDE_VIEW_WITH_ANTENNA.png
Normal file
BIN
images/SIDE_VIEW_WITH_ANTENNA.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 MiB |
BIN
images/TOP_VIEW.png
Normal file
BIN
images/TOP_VIEW.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.1 MiB |
19790
images/mfc-1.svg
Normal file
19790
images/mfc-1.svg
Normal file
File diff suppressed because it is too large
Load diff
|
After Width: | Height: | Size: 368 KiB |
Loading…
Reference in a new issue