попытки запустится до 1 МГц
This commit is contained in:
@@ -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"};
|
||||
"UNSUPPORTED", "RESOLUTION", "ABORTED", "DATA LOST"};
|
||||
const uint8_t i = static_cast<uint8_t>(r);
|
||||
return i < (sizeof(names) / sizeof(names[0])) ? names[i] : "UNKNOWN";
|
||||
}
|
||||
@@ -81,8 +81,10 @@ FailReason validateResolution(uint32_t frequencyHz, float dutyPct, float accurac
|
||||
if (periodTicks < 4.0f || activeTicks < 2.0f || inactiveTicks < 2.0f) return FailReason::RESOLUTION;
|
||||
const float timerPeriodError = 100.0f / periodTicks;
|
||||
const float timerDutyError = 100.0f / periodTicks;
|
||||
const float pwmDutyStep = 100.0f / static_cast<float>((1UL << pwmBits) - 1UL);
|
||||
return (timerPeriodError > accuracyPct || timerDutyError > accuracyPct || pwmDutyStep > accuracyPct)
|
||||
// Measurement uses the duty actually programmed into LEDC. A coarse PWM
|
||||
// step is not itself an error when the requested value (e.g. 50%) is exactly
|
||||
// representable; only the selected value's actual quantization matters.
|
||||
return (timerPeriodError > accuracyPct || timerDutyError > accuracyPct)
|
||||
? FailReason::RESOLUTION : FailReason::NONE;
|
||||
}
|
||||
|
||||
@@ -107,3 +109,56 @@ FailReason evaluatePeriod(const PulsePeriod &p, uint32_t tickHz, float expectedH
|
||||
}
|
||||
return reason;
|
||||
}
|
||||
|
||||
bool makePeriodLimits(uint32_t expectedHz, float expectedDuty, float tolerance,
|
||||
uint32_t tickHz, PeriodLimits &limits) {
|
||||
if (!expectedHz || !tickHz || tolerance < 0.0f || tolerance >= 100.0f ||
|
||||
expectedDuty <= 0.0f || expectedDuty >= 100.0f) return false;
|
||||
const uint32_t toleranceX100 = static_cast<uint32_t>(lroundf(tolerance * 100.0f));
|
||||
const uint32_t dutyX100 = static_cast<uint32_t>(lroundf(expectedDuty * 100.0f));
|
||||
const uint64_t numerator = static_cast<uint64_t>(tickHz) * 10000ULL;
|
||||
const uint64_t highDenominator = static_cast<uint64_t>(expectedHz) * (10000U + toleranceX100);
|
||||
const uint64_t lowDenominator = static_cast<uint64_t>(expectedHz) * (10000U - toleranceX100);
|
||||
limits.minPeriodTicks = static_cast<uint32_t>((numerator + highDenominator - 1U) / highDenominator);
|
||||
limits.maxPeriodTicks = static_cast<uint32_t>(numerator / lowDenominator);
|
||||
limits.minDutyX100 = dutyX100 > toleranceX100 ? dutyX100 - toleranceX100 : 0;
|
||||
limits.maxDutyX100 = dutyX100 + toleranceX100;
|
||||
return limits.minPeriodTicks && limits.maxPeriodTicks >= limits.minPeriodTicks;
|
||||
}
|
||||
|
||||
FailReason evaluatePeriodFast(const PulsePeriod &p, uint32_t tickHz,
|
||||
const PeriodLimits &limits, uint8_t repeat,
|
||||
StageStats &s) {
|
||||
if (!p.periodTicks || p.activeTicks >= p.periodTicks) return FailReason::EXTRA_EDGE;
|
||||
++s.periods;
|
||||
s.periodSum += p.periodTicks; s.activeSum += p.activeTicks;
|
||||
if (p.periodTicks < s.minPeriod) s.minPeriod = p.periodTicks;
|
||||
if (p.periodTicks > s.maxPeriod) s.maxPeriod = p.periodTicks;
|
||||
if (p.activeTicks < s.minActive) s.minActive = p.activeTicks;
|
||||
if (p.activeTicks > s.maxActive) s.maxActive = p.activeTicks;
|
||||
|
||||
FailReason reason = FailReason::NONE;
|
||||
if (p.periodTicks < limits.minPeriodTicks || p.periodTicks > limits.maxPeriodTicks) {
|
||||
reason = FailReason::PERIOD_OUT;
|
||||
} else {
|
||||
// The configured range (>= 1 kHz at 80 MHz capture) fits these products
|
||||
// into 32 bits. Keep a 64-bit fallback for unusually slow external input.
|
||||
if (p.periodTicks <= UINT32_MAX / 10000U && limits.maxDutyX100 <= 10000U) {
|
||||
const uint32_t scaledActive = p.activeTicks * 10000U;
|
||||
const uint32_t minActive = p.periodTicks * limits.minDutyX100;
|
||||
const uint32_t maxActive = p.periodTicks * limits.maxDutyX100;
|
||||
if (scaledActive < minActive || scaledActive > maxActive) reason = FailReason::DUTY_OUT;
|
||||
} else {
|
||||
const uint64_t scaledActive = static_cast<uint64_t>(p.activeTicks) * 10000ULL;
|
||||
const uint64_t minActive = static_cast<uint64_t>(p.periodTicks) * limits.minDutyX100;
|
||||
const uint64_t maxActive = static_cast<uint64_t>(p.periodTicks) * limits.maxDutyX100;
|
||||
if (scaledActive < minActive || scaledActive > maxActive) reason = FailReason::DUTY_OUT;
|
||||
}
|
||||
}
|
||||
if (reason != FailReason::NONE && s.reason == FailReason::NONE) {
|
||||
s.reason = reason; s.firstBadPeriod = s.periods; s.firstBadRepeat = repeat;
|
||||
s.badFrequency = static_cast<float>(tickHz) / p.periodTicks;
|
||||
s.badDuty = 100.0f * p.activeTicks / p.periodTicks;
|
||||
}
|
||||
return reason;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user