работает с перемычкой на 1МГц 2%

This commit is contained in:
2026-08-06 15:53:32 +03:00
parent 1edc420b77
commit f52f65686d
11 changed files with 207 additions and 55 deletions

View File

@@ -11,7 +11,7 @@ const char *roleName(Role r) {
const char *failName(FailReason r) {
static const char *names[] = {"NONE", "NO SIGNAL", "PERIOD OUT", "DUTY OUT",
"EXTRA EDGE", "GLITCH", "LOST EDGE", "TOO FEW PERIODS", "LINK LOST",
"UNSUPPORTED", "RESOLUTION", "ABORTED", "DATA LOST"};
"UNSUPPORTED", "RESOLUTION", "ABORTED"};
const uint8_t i = static_cast<uint8_t>(r);
return i < (sizeof(names) / sizeof(names[0])) ? names[i] : "UNKNOWN";
}
@@ -72,6 +72,80 @@ uint8_t choosePwmResolution(uint32_t frequencyHz, uint32_t sourceClockHz,
return bits;
}
uint8_t chooseStablePwmResolution(uint32_t frequencyHz, uint32_t sourceClockHz,
uint8_t maxBits, uint8_t dutyPct) {
const uint8_t fallback = choosePwmResolution(frequencyHz, sourceClockHz, maxBits);
if (!fallback || dutyPct > 100U) return fallback;
for (uint8_t bits = fallback; bits > 0; --bits) {
const uint32_t levels = 1UL << bits;
const uint64_t denominator = static_cast<uint64_t>(frequencyHz) * levels;
if (denominator > sourceClockHz || sourceClockHz % denominator) continue;
const uint32_t divider = static_cast<uint32_t>(sourceClockHz / denominator);
if (!divider || divider > 1024U) continue;
if ((static_cast<uint32_t>(levels) * dutyPct) % 100U == 0U) return bits;
}
return fallback;
}
bool chooseIntegerPwmConfig(uint32_t requestedHz, uint32_t sourceClockHz,
uint8_t maxBits, uint8_t dutyPct,
IntegerPwmConfig &config) {
if (!requestedHz || !sourceClockHz || !maxBits || dutyPct > 100U) return false;
bool found = false;
uint64_t bestError = 0;
uint32_t bestDenominator = 1;
uint32_t bestDutyError = 0;
uint32_t bestLevels = 1;
for (uint8_t bits = 1; bits <= maxBits && bits < 31; ++bits) {
const uint32_t levels = 1UL << bits;
const uint64_t requestedProduct = static_cast<uint64_t>(requestedHz) * levels;
uint32_t lowerDivider = static_cast<uint32_t>(sourceClockHz / requestedProduct);
if (lowerDivider < 1U) lowerDivider = 1U;
if (lowerDivider > 1023U) lowerDivider = 1023U;
const uint32_t candidates[] = {lowerDivider,
lowerDivider < 1023U ? lowerDivider + 1U : lowerDivider};
for (uint8_t candidate = 0; candidate < 2; ++candidate) {
const uint32_t divider = candidates[candidate];
if (candidate && divider == candidates[0]) continue;
const uint32_t denominator = levels * divider;
const uint64_t targetClock = static_cast<uint64_t>(requestedHz) * denominator;
const uint64_t error = targetClock > sourceClockHz
? targetClock - sourceClockHz : sourceClockHz - targetClock;
const uint32_t dutyCount = (static_cast<uint64_t>(levels) * dutyPct + 50U) / 100U;
const uint32_t representedDuty = dutyCount * 100U;
const uint32_t requestedDuty = levels * dutyPct;
const uint32_t dutyError = representedDuty > requestedDuty
? representedDuty - requestedDuty : requestedDuty - representedDuty;
const bool frequencyBetter = !found ||
error * bestDenominator < bestError * denominator;
const bool frequencyEqual = found &&
error * bestDenominator == bestError * denominator;
const bool dutyBetter = frequencyEqual &&
static_cast<uint64_t>(dutyError) * bestLevels <
static_cast<uint64_t>(bestDutyError) * levels;
const bool dutyEqual = frequencyEqual &&
static_cast<uint64_t>(dutyError) * bestLevels ==
static_cast<uint64_t>(bestDutyError) * levels;
if (!frequencyBetter && !dutyBetter && !(dutyEqual && bits > config.bits)) continue;
config.actualHz = static_cast<uint32_t>(
(static_cast<uint64_t>(sourceClockHz) + denominator / 2U) / denominator);
config.divider = static_cast<uint16_t>(divider);
config.bits = bits;
bestError = error;
bestDenominator = denominator;
bestDutyError = dutyError;
bestLevels = levels;
found = true;
}
}
return found;
}
FailReason validateResolution(uint32_t frequencyHz, float dutyPct, float accuracyPct,
uint32_t captureHz, uint8_t pwmBits) {
if (!frequencyHz || !captureHz || !pwmBits) return FailReason::RESOLUTION;