Repository navigation
Hardware Initialization and Tuning
This is the canonical, source-backed record of how the ControllerBoardMini firmware initializes its peripherals. It records the exact compiled settings, why they were selected, and the useful alternatives. A source setting is not the same as a completed electrical test; the final verification report must identify the firmware hash used on the board and list the observed devices and measurements separately.
The source paths cited below are authoritative for the next build. A valid MCU EEPROM record can override settings explicitly identified as persistent.
The ATmega328P starts a 2 s watchdog, opens the native COBS/opcode UART, sends an early HELLO, then initializes shift I/O, relays, monitored inputs, buzzer, addressable LEDs, EEPROM settings, TM1637, I2C, PWM, INA219, DS18B20, RF, and the boot melody. Relays are forced off before their output-enable pin is driven, and all 16 PWM channels are explicitly written off before saved PWM, enclosure, power-indicator, and status-RGB state is applied.
| Area | Compiled initialization | Why this is the current choice | Useful alternatives |
|---|---|---|---|
| CPU/watchdog | MiniCore ATmega328P at 16 MHz; 2 s watchdog | Bounds a genuinely stalled peripheral path while leaving startup headroom | Change only with a complete timing/build/upload verification because I2C, UART, TM1637, WS2811, and tone timing depend on it |
| Native UART | 115200 baud, normal AVR 8N1; COBS frames with opcode/CRC; always enabled | Responsive control and telemetry without using UART as a debug console | Lower baud only for a demonstrated electrical integrity problem; DTR reset is a separate host setting and is off by default |
| I2C/TWI | Compact master, 100 kHz, prescaler 1, TWBR=72, 25,000 us wait timeout with peripheral reset, repeated START, 16-byte host read/write cap |
Stable INA/PWM traffic and bounded faults with much lower flash/SRAM than generic Wire | 400 kHz is possible only after validating every device, cable, pull-up, generic host transfer, and LCD operation |
| INA219 | Address 0x40; config 0x3F7F; calibration 4096; continuous shunt+bus conversion; voltage/bus EMA 1/4 and current/power EMA 1/8 |
Correct 32 V range for a 12 V system and stronger hardware/software smoothing for the noisier current path | See the detailed INA219 section before changing range, averaging, software filtering, or shunt calibration |
| PWM expander | Address 0x41; requested 1000 Hz; prescale 5; MODE2 0x04; active-high logical outputs |
Separates it from INA219 and moves lighting PWM well above visibly flickery rates | Frequency 24..1526 Hz is supported; polarity is a compile-time electrical choice, not a display preference |
| DS18B20 pair | D10/CS 1-Wire bus; external 4.7 kOhm pull-up; externally powered; at most two family-0x28 ROMs; 11-bit; asynchronous 375 ms conversion |
Responsive temperatures without blocking UART/RF; bounded search survives a missing pull-up | 9/10-bit are faster and coarser; 12-bit gives 0.0625 C resolution but requires 750 ms |
| TM1637 | D13/SCK clock, D11/MOSI data, 3 us bit timing; 20 ms render service; cached four-segment writes; EEPROM brightness 0..7, factory 5 | Fast menu response while avoiding repeated writes of unchanged segments | Brightness and voltage/current decimal places are EEPROM settings |
| 433 MHz | RX D2/INT0 on CHANGE, TX D3/INT1 pin; rc-switch 2.6.4; 70% receive tolerance; TX defaults to protocol 1, 350 us pulse, 10 repeats | Broad compatibility with the observed low-cost remote family | Lower tolerance reduces false matches; protocol/pulse can be supplied per transmit command |
| Shift I/O | 74HC165 input and 74HC595 active-low output; 5 ms scan; first four input bits are keys; outputs start 0xFF/off |
Deterministic safe relay state and responsive keys | Electrical polarity constants must change only after a raw-input/output test |
| Buzzer | D9/PB1/OC1A; Timer1 CTC hardware toggle; no audio-rate ISR | Removes the former timer/interrupt jitter and leaves Timer0 timing intact | Do not combine with Servo or analogWrite() on D9/D10 |
| Addressable LEDs | D6/PD6, 11 pixels, 800 kHz, WS2811 BRG order, cleared at startup | Matches the installed strip without heap-heavy libraries | Set PCCONTROLLER_USE_WS2812B=1 for a confirmed WS2812B/GRB strip |
| HOST LCD | Firmware HD44780 renderer disabled; the host scans common PCF8574 addresses 0x27 and 0x3F and uses generic I2C transfers |
Saves AVR flash while retaining richer text whenever the host is connected | An MCU LCD renderer can be restored at a measurable flash cost |
The firmware uses Project/CompactI2c.cpp, not
MiniCore's Wire implementation.
- A4/SDA and A5/SCL are released with their weak internal pull-ups for startup recovery. Correct external I2C pull-ups are still required for reliable bus operation.
- A low SCL aborts initialization. If SDA is low while SCL is available, the firmware generates nine recovery clocks, 5 us low plus 5 us high, followed by a STOP, then requires both lines to be high.
- The master runs at 100 kHz at the fixed 16 MHz CPU clock. Every wait is bounded to 25 ms and resets the TWI peripheral on timeout.
- Register reads use a repeated START. Cooperative raw host transfers can read or write any 7-bit address, with at most 16 bytes in each direction and an optional lease of at most 10 seconds.
The compact master intentionally gives up generic Wire slave mode, multi-instance support, and Wire's separate 32-byte TX/RX buffering. It does not give up on-board INA/PWM ownership, repeated-START register reads, or the cooperative arbitrary host I2C bridge.
Current expected addresses are:
| Device | Address | Ownership/conflict note |
|---|---|---|
| INA219 | 0x40 |
Fixed current/voltage monitor |
| PWM/PCA9685 | 0x41 |
Hardware strap changed specifically to avoid the former 0x40 collision |
| PCF8574 LCD backpack | commonly 0x27 or 0x3F
|
Host-scanned and host-rendered; no conflict with 0x40/0x41
|
Project/Ina219Sensor.cpp writes calibration
4096 and configuration 0x3F7F after probing 0x40. Calibration is written
again before every reading because compatible parts can clear it after reset.
Configuration 0x3F7F decodes as:
| Field | Value | Result |
|---|---|---|
| BRNG | 1 |
32 V bus range |
| PGA | 3 |
gain /8, plus/minus 320 mV shunt range |
| BADC | 14 |
12-bit bus ADC with 64-sample averaging, about 34.05 ms |
| SADC | 15 |
12-bit shunt ADC with 128-sample averaging, about 68.10 ms |
| MODE | 7 |
continuous shunt-and-bus conversion |
One full bus-plus-shunt cycle is therefore about 102.15 ms. The firmware polls the completed registers every 100 ms while the door is open and every 500 ms while closed. This keeps the open-enclosure display responsive but does not pretend that polling faster than the ADC conversion produces a new sample.
Calibration 4096 assumes the board's common 0.1 ohm shunt and selects a
0.1 mA current LSB. The code reports:
- bus voltage at 4 mV per raw bus count;
- supply voltage as bus voltage plus signed shunt voltage;
- current at 0.1 mA per current-register count, rounded to integer mA; and
- power at 2 mW per power-register count.
This is a deliberate smoothing/speed balance: current receives 128-sample hardware averaging because it was the noisier value, while bus voltage uses 64 samples. Each completed reading then passes through an integer software EMA: supply and bus voltage apply one quarter of the new delta with a 1 mV deadband; current and power apply one eighth with a two-unit deadband (2 mA or 2 mW in their stored units). The first valid reading is applied immediately, and a failed read marks the module unavailable rather than smoothing stale data. Host graphing may add presentation-only smoothing, but it must not be mistaken for the board's source-of-truth filter or used to delay MCU safety/event logic.
Before modifying INA settings:
- If the fitted shunt is not
0.1 ohm, change the calibration and conversion scale together. Software filtering cannot correct a wrong shunt value. - Reducing ADC averages makes controls respond sooner but increases displayed noise. Increasing them further is not available on INA219.
- A smaller PGA range can catch shunt over-range earlier, but must still cover the maximum load current.
- Compare a calibrated meter at the INA219 bus pins and across the shunt before adding a software voltage offset.
The codebase calls this module PWM; PCA9685 is retained here only to identify
the chip. LocalLib/BoardPins.h fixes its address at
0x41, while INA219 remains at 0x40.
Initialization performs the following operations:
- Probe
0x41and write MODE10x20(auto-increment). - Request 1000 Hz. With the internal nominal 25 MHz oscillator, integer
rounding selects prescale
5, corresponding to about 1017.25 Hz nominal. - Enter sleep, write the prescaler, restore MODE1, wait 500 us, then issue RESTART plus auto-increment.
- Write MODE2
0x04: non-inverted, totem-pole output, update on STOP. The alternative active-low build writes0x05. - Force all 16 channels off, retrying one failed all-off pass. Three consecutive write errors mark PWM unavailable rather than claiming success.
- Apply illumination, display, status, and relay timing settings, then restore only the relay/PWM domains explicitly enabled by the EEPROM output policy.
Logical values are always 0..4095, where 0 is electrically inactive and
4095 is fully active. This build has PCCONTROLLER_PWM_ACTIVE_LOW=0; zero uses
the PCA9685 FULL_OFF bit and 4095 uses FULL_ON.
| Channels | Function |
|---|---|
| 0..7 | External MOSFET lighting/user outputs |
| 8..10 | Additional general PWM user outputs |
| 11 | Enclosure illumination |
| 12 | Power/on signal light |
| 13, 14, 15 | Status RGB red, green, blue |
There is no autonomous sweep or global operating state. Every channel is set
directly to a logical 0..4095 value through the front panel or the native
PWM_SET command; repeatable demonstrations belong in host macros or
automations. Channels 0..7 mirror their last value into the compact EEPROM
array when changed by the native command/RF paths; the dedicated uPWM editor
updates the same stored values. The direct all-channel front-panel editor is
live-only. On a normal cold start those eight values are restored only when
output persistence bit 2 is enabled. Channels 8..15 are not restored from that
array.
One kilohertz was chosen to remove visible lighting flicker while staying well inside the PCA9685 range. A different frequency can be requested from 24 to 1526 Hz, but the actual value depends on the module oscillator tolerance. For precision, measure the output frequency and add an oscillator calibration constant rather than assuming every module is exactly 25 MHz.
The two sensors share D10, the board's CS pin. The data line requires an
external 4.7 kOhm pull-up to VCC. The custom Dallas driver assumes the VDD
pins are externally powered; parasite power would additionally require a
strong pull-up during conversion and is not enabled.
At startup the driver:
- first requires an idle-high bus, so a missing pull-up or short-to-ground returns promptly instead of locking the MCU;
- caps ROM-search attempts at eight and retains at most two valid family
0x28addresses whose ROM CRC passes; - sorts the ROMs lexicographically for deterministic identity;
- writes 11-bit scratchpad resolution to each detected sensor; and
- starts conversion asynchronously, keeping UART and RF service available.
Eleven-bit conversion takes 375 ms and has 0.125 C resolution. New conversions start every 450 ms while the door is open and every 1000 ms while it is closed. Valid temperature samples use a 50/50 EMA. A first sample, a disconnected sample, or a sample at/above the 50.00 C HOT threshold bypasses the EMA so a fault or warning is not hidden by smoothing.
The factory role mapping assigns lexicographically sorted ROM 0 to
Temperature LED (tLED) and ROM 1 to Temperature BT (tBT). The persistent
swapTemperatureSensors flag reverses that assignment if a probe is replaced
or the harness changes. The host reports each full 64-bit ROM so identity can
be confirmed electrically rather than inferred only from heat response.
Resolution alternatives are:
| Resolution | Step | Maximum conversion |
|---|---|---|
| 9-bit | 0.5 C | 93.75 ms |
| 10-bit | 0.25 C | 187.5 ms |
| 11-bit | 0.125 C | 375 ms |
| 12-bit | 0.0625 C | 750 ms |
The TM1637 is a fixed-pin, allocation-free driver rather than the installed generic TM1637 library. It services presentation every 20 ms but compares the four encoded segment bytes with a cache and sends nothing when they have not changed. This provides a 50 Hz decision rate without the old constant bus refresh flicker. The low-level bit delay is 3 us, and the chip brightness range is 0..7 with factory EEPROM value 5.
Voltage and current decimal places are independent persistent settings in the range 0..2; erased EEPROM decodes both to two decimals. Measurement acquisition rate and display render rate remain separate, so a fast display never invents new sensor samples.
The enclosure light on PWM channel 11 uses Auto by factory default, with on-level 128/255 and off-level 0/255. Its linear transition advances 4/255 every 20 ms, about 1.28 s for a full-scale fade, and catches up by at most 16 steps after a delayed loop. Opening the door selects the on level; closing selects the off level. Both levels and Off/Auto/On mode are EEPROM settings.
The optional 16x2 LCD is host-driven. The host discovers common backpacks,
renders richer menu/event/prompt text, and can preload PC offline / Connect USB to PC behavior. The AVR retains only compact transfer/offline support.
The firmware links the installed rc-switch 2.6.4 library. Receive uses
D2/INT0 with edge-change interrupts and a configured 70% pulse tolerance.
The library accepts a decoded frame after the expected repeated transmission,
which rejects isolated noise but means a transmitter must repeat consistently.
Transmit uses D3, physically the INT1 pin, as a digital output. The rc-switch constructor defaults to protocol 1, a 350 us base pulse, and 10 repeats. Every native transmit command can select protocol 1..12, 1..32 bits, and an optional pulse length. Receive is disabled during a send and re-enabled on INT0 immediately afterward.
Learning defaults to 15 seconds, is capped at 120 seconds for timed sessions, and also supports indefinite and multi-code modes. Up to 20 learned records are stored in the board's EEPROM; names/categories/colors remain host-owned.
Seventy percent tolerance is intentionally permissive. If false decodes appear, capture actual pulse lengths first and try 60% or a remote-specific value. Do not narrow it merely to save bytes; it changes RF acceptance behavior.
The 74HC165/74HC595 chain initializes with relay output enable inactive, writes
0xFF (all active-low outputs off), samples inputs, and only then enables the
outputs. It polls every 5 ms.
Keys occupy 74HC165 bits 0..3 and use:
- 20 ms debounce, with the primary action on the first debounced Down edge;
- 300 ms double-click window;
- hold start at 600 ms;
- held repeat every 150 ms;
- acceleration after 1800 ms to one repeat every 60 ms.
The double-click window classifies telemetry and the optional K1 shortcut; it must never delay the initial action. UART virtual-key Down events act in their receive pass, and learned RF key/menu mappings act in their RF service pass. Do not place EEPROM writes, network round trips, sound cues, display rendering, or sleeps ahead of these dispatch points. Any timing change must retain the 25 ms physical debounce ceiling and rerun latency tests plus physical/UART/RF acceptance.
Bits 4 and 5 are reserved senses. Bit 6 is the active-low BT Audio LED input; bit 7 is door-open-active-high. Both are debounced for 40 ms. BT transitions within 2500 ms are classified as blinking; a stable active LED means BT Audio connected, a blinking LED means its module is advertising/not connected, and off means the module indicator is off.
Relay outputs are active-low and start off:
| Relay | Meaning |
|---|---|
| R1 | Side A direction; de-energized is Forward, energized is Reverse |
| R2 | Side A enable/output |
| R3 | Side B direction; de-energized is Forward, energized is Reverse |
| R4 | Side B enable/output |
| R5..R8 | Independent general outputs |
A reversal is sequenced as enable off, the configured break, direction change,
then enable. The EEPROM setting accepts 1..255 ms and defaults to 1 ms; no
hidden settling delay is added. Direction changes
between the two sides are separated by at least 5 ms. Factory motion-door policy is always; closed,
open, and never are the other persistent policies.
The buzzer is driven by Timer1 CTC hardware output on OC1A/D9. No Timer1 compare ISR runs at audio frequency, so buzzer playback does not starve INT0/INT1 RF or UART service. Factory EEPROM is audible; the persistent silent flag suppresses tones without changing command acknowledgement.
PWM channel 12 is the power indicator, and channels 13..15 are status RGB. The factory status brightness is 128/255. Animation service runs every 20 ms with a step of 4/255. The Go-owned factory profile makes Ready white; all nineteen persistent condition profiles can be changed by the host, while the AVR keeps only a compact blue/red safety fallback for blank or corrupt records.
The addressable output is 11 pixels on D6 at 800 kHz. The installed hardware default is WS2811 BRG byte order. The startup frame is black/off. The current compact driver reports full brightness and its compatibility brightness setter does not scale pixels; brightness-sensitive effects should scale RGB values or add a tested compact scaler.
These are the defaults used only when the EEPROM record is erased, invalid, or explicitly reset. They are not proof of the settings currently stored on a particular board.
| Setting | Factory value |
|---|---|
| Silent | off / audible |
| Illumination mode | Auto |
| Illumination on / off | 128 / 0 |
| TM1637 brightness, door open / closed | 5 / 0 (closed 0 is display off) |
| Status brightness | 128 of 255 |
| Output persistence | restore user relays and stored user PWM; do not restore motion; full direction-off on stop |
| Relay restore mask | 0x00 |
| Telemetry stream | 500 ms |
| User PWM 0..7 | all zero |
| Default menu page | 0, Door |
| Save last page as default | off |
| Voltage / current decimals | 2 / 2 |
| Motion door policy | Always |
| Break before direction | 1 ms |
| Door / relay buzzer cues | enabled |
| Temperature identity swap | off; sorted ROM 0 is tLED, ROM 1 is tBT |
For each final firmware hash, record the following in the acceptance report:
- I2C scan results and absence of a
0x40/0x41collision. - INA219 bus, shunt, supply, current, and power compared with calibrated instruments at at least idle and one known load.
- Both DS18B20 ROMs, role mapping, unplugged-pull-up behavior, and the expected LED-probe temperature rise while the BT probe stays comparatively cool.
- PWM frequency, polarity, all-off startup, channels 0..10 sweep, channel 11 enclosure fade, channel 12 power signal, and channels 13..15 RGB order.
- TM1637 responsiveness, caching/no visible flicker, brightness, decimal choices, confirmation blink, and host-owned preview.
- RF receive codes/repeats and a known transmit captured by another receiver.
- Relay mapping and loaded direction interlock with safe physical observation.
- UART reconnect without default DTR reset, boot melody, silent setting, and reset-count telemetry.
Only after those measurements should a setting be called "best" for the final hardware. The values above are the current engineering choices and are exposed here so any requested change can be made deliberately and compared against a known baseline.
- π Getting started and operations
- πΊοΈ Repository and file map
- ποΈ Front panel and menus
- π§ Hardware initialization and tuning
- βοΈ Host configuration and integrations
- π§ Hosted front-panel menus
- π Portable WebUI
- π Protocol and network API
- π§© C library API
βοΈ Control-surface capability matrix
- ποΈ Build and packaging tool
- πΎ Firmware tool
- π₯οΈ Host Controller
- π§ͺ Virtual Board
- π¦ Dependency maintenance
- π‘οΈ Toolchain bootstrap and safe programming
- π§ Memory and feature tradeoffs
- π¦ CI/CD and releases
- π© Urboot-Custom reproducible fork
- π Audit and traceability tools
- β Project acceptance
- π Requirements backlog
- 𧬠Local-library variant comparison