Сделана настройка мощности передающей оптики
This commit is contained in:
@@ -14,6 +14,8 @@
|
||||
#include <string.h>
|
||||
|
||||
namespace {
|
||||
constexpr uint8_t MENU_OPTICAL_CALIBRATION_ITEM = 7;
|
||||
|
||||
const char *uiFailName(FailReason reason);
|
||||
|
||||
const char *appStateName(AppState state) {
|
||||
@@ -248,6 +250,13 @@ uint8_t cycleIndex(uint8_t value, uint8_t first, uint8_t last, int direction) {
|
||||
return value <= first ? last : static_cast<uint8_t>(value - 1U);
|
||||
}
|
||||
|
||||
uint8_t nextMenuItem(uint8_t current, TestGroup group) {
|
||||
if (group == TestGroup::BOARD)
|
||||
return current == 0U ? MENU_OPTICAL_CALIBRATION_ITEM : 0U;
|
||||
return current >= MENU_OPTICAL_CALIBRATION_ITEM ? 0U
|
||||
: static_cast<uint8_t>(current + 1U);
|
||||
}
|
||||
|
||||
bool parseUnsigned(const char *text, uint32_t &value) {
|
||||
if (!text || !*text || *text == '-') return false;
|
||||
char *end = nullptr;
|
||||
@@ -388,18 +397,25 @@ void App::update() {
|
||||
}
|
||||
if (state_ == AppState::MENU) {
|
||||
if (modeEvent == ButtonEvent::SHORT) {
|
||||
const uint8_t menuCount = static_cast<TestGroup>(settings_.testGroup) == TestGroup::BOARD ? 1U : 7U;
|
||||
menuItem_ = (menuItem_ + 1U) % menuCount; Log::printf("ACTION", "menu item selected index=%u", menuItem_); showMenu();
|
||||
leaveOpticalCalibration();
|
||||
menuItem_ = nextMenuItem(menuItem_,
|
||||
static_cast<TestGroup>(settings_.testGroup));
|
||||
Log::printf("ACTION", "menu item selected index=%u", menuItem_);
|
||||
showMenu();
|
||||
}
|
||||
else if (modeEvent == ButtonEvent::LONG) {
|
||||
leaveOpticalCalibration();
|
||||
sanitizeRange(); const bool saved = store_.save(settings_); params_ = store_.params(settings_);
|
||||
Log::printf("ACTION", "settings menu saved and closed, NVS=%s", saved ? "OK" : "FAILED");
|
||||
state_ = AppState::IDLE; printConfiguration();
|
||||
if (static_cast<TestGroup>(settings_.testGroup) == TestGroup::OPTICS &&
|
||||
static_cast<Role>(settings_.role) == Role::SLAVE) armSlave();
|
||||
else showIdle();
|
||||
} else if (startEvent == ButtonEvent::SHORT) changeMenu(+1);
|
||||
else if (startEvent == ButtonEvent::LONG || startEvent == ButtonEvent::REPEAT) changeMenu(-1);
|
||||
} else if (menuItem_ != MENU_OPTICAL_CALIBRATION_ITEM &&
|
||||
startEvent == ButtonEvent::SHORT) changeMenu(+1);
|
||||
else if (menuItem_ != MENU_OPTICAL_CALIBRATION_ITEM &&
|
||||
(startEvent == ButtonEvent::LONG || startEvent == ButtonEvent::REPEAT)) changeMenu(-1);
|
||||
updateOpticalCalibration(now);
|
||||
return;
|
||||
}
|
||||
if (state_ == AppState::SOLO_MEASURE) {
|
||||
@@ -544,6 +560,7 @@ bool App::serialSettingsMutable() const {
|
||||
|
||||
void App::finishSerialSettingsChange() {
|
||||
if (state_ == AppState::SLAVE_READY) radio_.end();
|
||||
leaveOpticalCalibration();
|
||||
state_ = AppState::IDLE;
|
||||
sanitizeRange();
|
||||
params_ = store_.params(settings_);
|
||||
@@ -589,6 +606,7 @@ void App::handleSerialCommand(char *line) {
|
||||
Serial.println("OK board test stopped");
|
||||
stopBoardTest();
|
||||
} else if (state_ == AppState::MENU) {
|
||||
leaveOpticalCalibration();
|
||||
state_ = AppState::IDLE; showIdle(); Serial.println("OK menu closed");
|
||||
} else if (state_ == AppState::SLAVE_READY) Serial.println("OK slave is armed; no test is running");
|
||||
else {
|
||||
@@ -823,6 +841,9 @@ void App::showMenu() {
|
||||
display_.show(one, total);
|
||||
return;
|
||||
}
|
||||
case MENU_OPTICAL_CALIBRATION_ITEM:
|
||||
enterOpticalCalibration(millis());
|
||||
return;
|
||||
default: return;
|
||||
}
|
||||
formatMenuLine(label, value, one, sizeof(one));
|
||||
@@ -833,6 +854,43 @@ void App::showMenu() {
|
||||
display_.show(one, total);
|
||||
}
|
||||
|
||||
void App::enterOpticalCalibration(uint32_t now) {
|
||||
if (opticalCalibrationActive_) return;
|
||||
optical_current_begin();
|
||||
pwm_.lightOn();
|
||||
opticalCalibrationActive_ = true;
|
||||
opticalCalibrationStartedMs_ = now;
|
||||
opticalCalibrationUpdatedMs_ = 0;
|
||||
display_.show("Idiode: --.- mA", "Vcc: --.-- V");
|
||||
Log::printf("CALIB", "optical LED ON; sense GPIO=%u, VCC GPIO=%u, settling %lums",
|
||||
GPIO_OPTICAL_CURRENT, GPIO_OPTICAL_VCC, OPTICAL_CURRENT_SETTLE_MS);
|
||||
}
|
||||
|
||||
void App::updateOpticalCalibration(uint32_t now, bool force) {
|
||||
if (!opticalCalibrationActive_ ||
|
||||
now - opticalCalibrationStartedMs_ < OPTICAL_CURRENT_SETTLE_MS) return;
|
||||
(void)force;
|
||||
OpticalCurrentMeasurement reading = {};
|
||||
if (!optical_current_poll(reading)) return;
|
||||
opticalCalibrationUpdatedMs_ = now;
|
||||
char current[32], vcc[24];
|
||||
snprintf(current, sizeof(current), "Idiode: %.1f mA", reading.currentMa);
|
||||
snprintf(vcc, sizeof(vcc), "Vcc: %.2f V", reading.vccVoltage);
|
||||
display_.show(current, vcc);
|
||||
Log::printf("CALIB",
|
||||
"raw sense=%u vcc=%u | ADC sense=%.3fV vcc=%.3fV | Usense=%.3fV Vcc=%.3fV | Idiode=%.1fmA",
|
||||
reading.senseRaw, reading.vccRaw, reading.senseAdcVoltage,
|
||||
reading.vccAdcVoltage, reading.senseVoltage, reading.vccVoltage,
|
||||
reading.currentMa);
|
||||
}
|
||||
|
||||
void App::leaveOpticalCalibration() {
|
||||
if (!opticalCalibrationActive_) return;
|
||||
pwm_.stop();
|
||||
opticalCalibrationActive_ = false;
|
||||
Log::event("CALIB", "optical LED OFF; calibration menu left");
|
||||
}
|
||||
|
||||
void App::startTest() {
|
||||
leaveIdlePowerSave();
|
||||
pwm_.stop();
|
||||
@@ -1463,12 +1521,9 @@ bool App::usbHostPresent() const {
|
||||
}
|
||||
|
||||
void App::setStandbyOpticalOutput() {
|
||||
// A gate driver must never be held enabled while the tester is idle or
|
||||
// showing a result. DRIVER is SOLO-only, so force real light OFF here.
|
||||
if (static_cast<TestGroup>(settings_.testGroup) == TestGroup::BOARD ||
|
||||
static_cast<Role>(settings_.role) == Role::SLAVE ||
|
||||
static_cast<TestKind>(settings_.testKind) == TestKind::DRIVER) pwm_.stop();
|
||||
else pwm_.active();
|
||||
// Calibration and tests may hold the transmitter active. Idle/result
|
||||
// screens must always detach PWM and restore the physical light-OFF level.
|
||||
pwm_.stop();
|
||||
}
|
||||
|
||||
void App::setActivePerformance(bool active) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "Display.h"
|
||||
#include "DriverTest.h"
|
||||
#include "Measurement.h"
|
||||
#include "OpticalCurrent.h"
|
||||
#include "Pwm.h"
|
||||
#include "Radio.h"
|
||||
#include "SettingsStore.h"
|
||||
@@ -23,6 +24,9 @@ class App {
|
||||
void finishInitialization(bool factoryReset);
|
||||
void showMenu();
|
||||
void changeMenu(int direction);
|
||||
void enterOpticalCalibration(uint32_t now);
|
||||
void updateOpticalCalibration(uint32_t now, bool force = false);
|
||||
void leaveOpticalCalibration();
|
||||
void cycleRunMode();
|
||||
void sanitizeRange();
|
||||
void startTest();
|
||||
@@ -105,6 +109,9 @@ class App {
|
||||
uint32_t boardTestUpdatedMs_ = 0;
|
||||
uint32_t boardDisplayUpdatedMs_ = 0;
|
||||
bool boardPwmLightOn_ = false;
|
||||
bool opticalCalibrationActive_ = false;
|
||||
uint32_t opticalCalibrationStartedMs_ = 0;
|
||||
uint32_t opticalCalibrationUpdatedMs_ = 0;
|
||||
mutable uint32_t lastUsbHostSeenMs_ = 0;
|
||||
char serialLine_[96] = {};
|
||||
uint8_t serialLineLength_ = 0;
|
||||
|
||||
@@ -5,13 +5,15 @@
|
||||
// ------------------------- Hardware configuration -------------------------
|
||||
// Enabled for the hand-wired prototype. Comment out for the production PCB.
|
||||
// Both profiles map S3 signals by physical header position with 5V/GND aligned.
|
||||
//#define MAKETKA
|
||||
#define MAKETKA
|
||||
|
||||
// Select exactly one populated receiver circuit. Use
|
||||
// BOARD_RX_INTERFACE_DIGITAL for MAKETKA and boards fitted with GPIO_RX.
|
||||
#define BOARD_RX_INTERFACE_ADC 1
|
||||
#define BOARD_RX_INTERFACE_DIGITAL 2
|
||||
#define BOARD_RX_INTERFACE BOARD_RX_INTERFACE_ADC
|
||||
#ifndef BOARD_RX_INTERFACE
|
||||
#define BOARD_RX_INTERFACE BOARD_RX_INTERFACE_DIGITAL
|
||||
#endif
|
||||
|
||||
#if BOARD_RX_INTERFACE != BOARD_RX_INTERFACE_ADC && \
|
||||
BOARD_RX_INTERFACE != BOARD_RX_INTERFACE_DIGITAL
|
||||
@@ -38,12 +40,16 @@ constexpr uint8_t GPIO_RX = 4;
|
||||
constexpr bool BOARD_ADC_AVAILABLE = false;
|
||||
constexpr uint8_t GPIO_BUTTON_MODE = 0;
|
||||
constexpr uint8_t GPIO_BUTTON_START = 1;
|
||||
constexpr uint8_t GPIO_OPTICAL_CURRENT = 2;
|
||||
constexpr uint8_t GPIO_OPTICAL_VCC = 5;
|
||||
constexpr uint8_t GPIO_VBAT = UINT8_MAX;
|
||||
constexpr uint8_t GPIO_ANALOG_RX = UINT8_MAX;
|
||||
#else
|
||||
constexpr bool BOARD_ADC_AVAILABLE = true;
|
||||
constexpr uint8_t GPIO_BUTTON_MODE = 20;
|
||||
constexpr uint8_t GPIO_BUTTON_START = 10;
|
||||
constexpr uint8_t GPIO_OPTICAL_CURRENT = 1;
|
||||
constexpr uint8_t GPIO_OPTICAL_VCC = 5;
|
||||
constexpr uint8_t GPIO_VBAT = 2;
|
||||
constexpr uint8_t GPIO_ANALOG_RX = 0;
|
||||
#endif
|
||||
@@ -58,6 +64,8 @@ constexpr uint8_t GPIO_PWM = 12;
|
||||
constexpr uint8_t GPIO_RX = 13;
|
||||
constexpr uint8_t GPIO_BUTTON_MODE = 9;
|
||||
constexpr uint8_t GPIO_BUTTON_START = 10;
|
||||
constexpr uint8_t GPIO_OPTICAL_CURRENT = 2;
|
||||
constexpr uint8_t GPIO_OPTICAL_VCC = 6;
|
||||
constexpr uint8_t GPIO_SDA = 44;
|
||||
constexpr uint8_t GPIO_SCL = 1;
|
||||
constexpr uint8_t GPIO_VBAT = UINT8_MAX;
|
||||
@@ -70,6 +78,8 @@ constexpr uint8_t GPIO_PWM = 12;
|
||||
constexpr uint8_t GPIO_RX = 13;
|
||||
constexpr uint8_t GPIO_BUTTON_MODE = 5;
|
||||
constexpr uint8_t GPIO_BUTTON_START = 4;
|
||||
constexpr uint8_t GPIO_OPTICAL_CURRENT = 10;
|
||||
constexpr uint8_t GPIO_OPTICAL_VCC = 6;
|
||||
constexpr uint8_t GPIO_SDA = 44;
|
||||
constexpr uint8_t GPIO_SCL = 1;
|
||||
constexpr uint8_t GPIO_VBAT = 11;
|
||||
@@ -79,6 +89,22 @@ constexpr uint8_t GPIO_ANALOG_RX = 9;
|
||||
#error "Only ESP32-C3 and ESP32-S3 are supported"
|
||||
#endif
|
||||
|
||||
static_assert(GPIO_OPTICAL_CURRENT != GPIO_PWM &&
|
||||
GPIO_OPTICAL_CURRENT != GPIO_RX &&
|
||||
GPIO_OPTICAL_CURRENT != GPIO_BUTTON_MODE &&
|
||||
GPIO_OPTICAL_CURRENT != GPIO_BUTTON_START &&
|
||||
GPIO_OPTICAL_CURRENT != GPIO_SDA &&
|
||||
GPIO_OPTICAL_CURRENT != GPIO_SCL,
|
||||
"Optical-current ADC GPIO conflicts with another board signal");
|
||||
static_assert(GPIO_OPTICAL_VCC != GPIO_OPTICAL_CURRENT &&
|
||||
GPIO_OPTICAL_VCC != GPIO_PWM &&
|
||||
GPIO_OPTICAL_VCC != GPIO_RX &&
|
||||
GPIO_OPTICAL_VCC != GPIO_BUTTON_MODE &&
|
||||
GPIO_OPTICAL_VCC != GPIO_BUTTON_START &&
|
||||
GPIO_OPTICAL_VCC != GPIO_SDA &&
|
||||
GPIO_OPTICAL_VCC != GPIO_SCL,
|
||||
"Optical-VCC ADC GPIO conflicts with another board signal");
|
||||
|
||||
constexpr uint8_t OLED_ROTATION = 0;
|
||||
|
||||
constexpr uint8_t OLED_ADDRESS = 0x3C;
|
||||
@@ -89,6 +115,11 @@ constexpr uint32_t SERIAL_BAUD = 115200;
|
||||
constexpr uint32_t SERIAL_TX_TIMEOUT_MS = 2;
|
||||
constexpr uint32_t BOARD_ADC_PRINT_INTERVAL_MS = 100;
|
||||
constexpr uint32_t BOARD_TEST_DISPLAY_INTERVAL_MS = 250;
|
||||
constexpr float OPTICAL_VCC = 5.1f;
|
||||
constexpr float OPTICAL_SENSE_R = 47.0f;
|
||||
constexpr float OPTICAL_DIVIDER_RATIO = 2.0f;
|
||||
constexpr uint32_t OPTICAL_CURRENT_SETTLE_MS = 20;
|
||||
constexpr uint32_t OPTICAL_CURRENT_AVERAGING_MS = 200;
|
||||
constexpr bool SERIAL_ACTION_LOG = true;
|
||||
constexpr bool SERIAL_LOG_TIMESTAMPS = true;
|
||||
constexpr bool SERIAL_MINIMAL_LOG = true;
|
||||
|
||||
@@ -58,6 +58,7 @@ constexpr const char *MENU_MIN_PULSE = "МИН. ИМПУЛЬС:";
|
||||
constexpr const char *MENU_ACCURACY = "ТОЧНОСТЬ:";
|
||||
constexpr const char *MENU_TEST_TIME = "ВРЕМЯ ВЫБОРКИ:";
|
||||
constexpr const char *MENU_LIGHT_CODE = "АКТ. УРОВЕНЬ:";
|
||||
constexpr const char *MENU_OPTICAL_CALIBRATION = "КАЛИБР. ОПТИКИ";
|
||||
constexpr const char *LIGHT_CODE_FORMAT = "TX:%c, RX:%c";
|
||||
constexpr const char *LIGHT_AUTO = "АВТО";
|
||||
constexpr const char *LIGHT_AUTO_FORMAT = "TX/RX: АВТО";
|
||||
@@ -136,6 +137,7 @@ constexpr const char *MENU_MIN_PULSE = "MIN PULSE:";
|
||||
constexpr const char *MENU_ACCURACY = "ACCURACY:";
|
||||
constexpr const char *MENU_TEST_TIME = "TEST TIME:";
|
||||
constexpr const char *MENU_LIGHT_CODE = "ACTIVE LEVEL:";
|
||||
constexpr const char *MENU_OPTICAL_CALIBRATION = "OPTICAL CALIBRATION";
|
||||
constexpr const char *LIGHT_CODE_FORMAT = "TX:%c, RX:%c";
|
||||
constexpr const char *LIGHT_AUTO = "AUTO";
|
||||
constexpr const char *LIGHT_AUTO_FORMAT = "TX/RX: AUTO";
|
||||
|
||||
74
OpticalChannelTester/OpticalCurrent.cpp
Normal file
74
OpticalChannelTester/OpticalCurrent.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#include "OpticalCurrent.h"
|
||||
#include "Config.h"
|
||||
|
||||
namespace {
|
||||
struct AdcAccumulator {
|
||||
uint64_t senseRaw = 0;
|
||||
uint64_t vccRaw = 0;
|
||||
uint64_t senseMillivolts = 0;
|
||||
uint64_t vccMillivolts = 0;
|
||||
uint32_t samples = 0;
|
||||
uint32_t startedMs = 0;
|
||||
};
|
||||
|
||||
AdcAccumulator accumulator;
|
||||
|
||||
void resetAccumulator(uint32_t now) {
|
||||
accumulator = {};
|
||||
accumulator.startedMs = now;
|
||||
}
|
||||
|
||||
OpticalCurrentMeasurement finishMeasurement() {
|
||||
const float senseAdcVoltage =
|
||||
accumulator.senseMillivolts / (1000.0f * accumulator.samples);
|
||||
const float vccAdcVoltage =
|
||||
accumulator.vccMillivolts / (1000.0f * accumulator.samples);
|
||||
const float senseVoltage = senseAdcVoltage * OPTICAL_DIVIDER_RATIO;
|
||||
const float vccVoltage = vccAdcVoltage * OPTICAL_DIVIDER_RATIO;
|
||||
const float resistorVoltage = vccVoltage - senseVoltage;
|
||||
const float currentMa = resistorVoltage * 1000.0f / OPTICAL_SENSE_R;
|
||||
return {
|
||||
static_cast<uint16_t>(accumulator.senseRaw / accumulator.samples),
|
||||
static_cast<uint16_t>(accumulator.vccRaw / accumulator.samples),
|
||||
senseAdcVoltage, vccAdcVoltage, senseVoltage, vccVoltage,
|
||||
currentMa > 0.0f ? currentMa : 0.0f
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void optical_current_begin(void) {
|
||||
analogReadResolution(12);
|
||||
pinMode(GPIO_OPTICAL_CURRENT, INPUT);
|
||||
pinMode(GPIO_OPTICAL_VCC, INPUT);
|
||||
// Both 10k/10k dividers can present about 2.5 V to their ADC inputs.
|
||||
analogSetPinAttenuation(GPIO_OPTICAL_CURRENT, ADC_11db);
|
||||
analogSetPinAttenuation(GPIO_OPTICAL_VCC, ADC_11db);
|
||||
resetAccumulator(0);
|
||||
}
|
||||
|
||||
bool optical_current_poll(OpticalCurrentMeasurement &measurement) {
|
||||
const uint32_t now = millis();
|
||||
if (!accumulator.startedMs) resetAccumulator(now ? now : 1U);
|
||||
|
||||
accumulator.senseRaw += analogRead(GPIO_OPTICAL_CURRENT);
|
||||
accumulator.senseMillivolts += analogReadMilliVolts(GPIO_OPTICAL_CURRENT);
|
||||
accumulator.vccRaw += analogRead(GPIO_OPTICAL_VCC);
|
||||
accumulator.vccMillivolts += analogReadMilliVolts(GPIO_OPTICAL_VCC);
|
||||
++accumulator.samples;
|
||||
|
||||
if (now - accumulator.startedMs < OPTICAL_CURRENT_AVERAGING_MS) return false;
|
||||
measurement = finishMeasurement();
|
||||
resetAccumulator(now);
|
||||
return true;
|
||||
}
|
||||
|
||||
OpticalCurrentMeasurement optical_get_led_measurement(void) {
|
||||
OpticalCurrentMeasurement measurement = {};
|
||||
resetAccumulator(millis());
|
||||
while (!optical_current_poll(measurement)) delay(1);
|
||||
return measurement;
|
||||
}
|
||||
|
||||
float optical_get_led_current_ma(void) {
|
||||
return optical_get_led_measurement().currentMa;
|
||||
}
|
||||
18
OpticalChannelTester/OpticalCurrent.h
Normal file
18
OpticalChannelTester/OpticalCurrent.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct OpticalCurrentMeasurement {
|
||||
uint16_t senseRaw;
|
||||
uint16_t vccRaw;
|
||||
float senseAdcVoltage;
|
||||
float vccAdcVoltage;
|
||||
float senseVoltage;
|
||||
float vccVoltage;
|
||||
float currentMa;
|
||||
};
|
||||
|
||||
void optical_current_begin(void);
|
||||
bool optical_current_poll(OpticalCurrentMeasurement &measurement);
|
||||
OpticalCurrentMeasurement optical_get_led_measurement(void);
|
||||
float optical_get_led_current_ma(void);
|
||||
Reference in New Issue
Block a user