mirror of
https://github.com/micropython/micropython.git
synced 2025-07-21 13:01:10 +02:00
Some checks are pending
JavaScript code lint and formatting with Biome / eslint (push) Waiting to run
Check code formatting / code-formatting (push) Waiting to run
Check spelling with codespell / codespell (push) Waiting to run
Build docs / build (push) Waiting to run
Check examples / embedding (push) Waiting to run
Package mpremote / build (push) Waiting to run
.mpy file format and tools / test (push) Waiting to run
Build ports metadata / build (push) Waiting to run
cc3200 port / build (push) Waiting to run
esp32 port / build_idf (esp32_build_cmod_spiram_s2) (push) Waiting to run
esp32 port / build_idf (esp32_build_s3_c3) (push) Waiting to run
esp8266 port / build (push) Waiting to run
mimxrt port / build (push) Waiting to run
nrf port / build (push) Waiting to run
powerpc port / build (push) Waiting to run
qemu port / build_and_test_arm (push) Waiting to run
qemu port / build_and_test_rv32 (push) Waiting to run
renesas-ra port / build_renesas_ra_board (push) Waiting to run
rp2 port / build (push) Waiting to run
samd port / build (push) Waiting to run
stm32 port / build_stm32 (stm32_misc_build) (push) Waiting to run
stm32 port / build_stm32 (stm32_nucleo_build) (push) Waiting to run
stm32 port / build_stm32 (stm32_pyb_build) (push) Waiting to run
unix port / minimal (push) Waiting to run
unix port / reproducible (push) Waiting to run
unix port / standard (push) Waiting to run
unix port / standard_v2 (push) Waiting to run
unix port / coverage (push) Waiting to run
unix port / coverage_32bit (push) Waiting to run
unix port / nanbox (push) Waiting to run
unix port / float (push) Waiting to run
unix port / stackless_clang (push) Waiting to run
unix port / float_clang (push) Waiting to run
unix port / settrace (push) Waiting to run
unix port / settrace_stackless (push) Waiting to run
unix port / macos (push) Waiting to run
unix port / qemu_mips (push) Waiting to run
unix port / qemu_arm (push) Waiting to run
unix port / qemu_riscv64 (push) Waiting to run
webassembly port / build (push) Waiting to run
windows port / build-vs (Debug, x64, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Debug, x64, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Debug, x86, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Debug, x86, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2019, dev, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2019, standard, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2022, standard, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-latest, standard, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2019, dev, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2019, standard, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2022, standard, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-latest, standard, 2017, [15, 16)) (push) Waiting to run
windows port / build-mingw (i686, mingw32, dev) (push) Waiting to run
windows port / build-mingw (i686, mingw32, standard) (push) Waiting to run
windows port / build-mingw (x86_64, mingw64, dev) (push) Waiting to run
windows port / build-mingw (x86_64, mingw64, standard) (push) Waiting to run
windows port / cross-build-on-linux (push) Waiting to run
zephyr port / build (push) Waiting to run
Python code lint and formatting with ruff / ruff (push) Waiting to run
Found by codespell. Signed-off-by: Christian Clauss <cclauss@me.com>
167 lines
5.3 KiB
Python
167 lines
5.3 KiB
Python
# Test machine.PWM, frequency and duty cycle (using machine.time_pulse_us).
|
|
#
|
|
# IMPORTANT: This test requires hardware connections: the PWM-output and pulse-input
|
|
# pins must be wired together (see the variable `pwm_pulse_pins`).
|
|
|
|
import sys
|
|
import time
|
|
|
|
try:
|
|
from machine import time_pulse_us, Pin, PWM
|
|
except ImportError:
|
|
print("SKIP")
|
|
raise SystemExit
|
|
|
|
import unittest
|
|
|
|
pwm_freq_limit = 1000000
|
|
freq_margin_per_thousand = 0
|
|
duty_margin_per_thousand = 0
|
|
timing_margin_us = 5
|
|
|
|
# Configure pins based on the target.
|
|
if "esp32" in sys.platform:
|
|
pwm_pulse_pins = ((4, 5),)
|
|
freq_margin_per_thousand = 2
|
|
duty_margin_per_thousand = 1
|
|
timing_margin_us = 20
|
|
elif "esp8266" in sys.platform:
|
|
pwm_pulse_pins = ((4, 5),)
|
|
pwm_freq_limit = 1_000
|
|
duty_margin_per_thousand = 3
|
|
timing_margin_us = 50
|
|
elif "mimxrt" in sys.platform:
|
|
if "Teensy" in sys.implementation._machine:
|
|
# Teensy 4.x
|
|
pwm_pulse_pins = (
|
|
("D0", "D1"), # FLEXPWM X and UART 1
|
|
("D2", "D3"), # FLEXPWM A/B
|
|
("D11", "D12"), # QTMR and MOSI/MISO of SPI 0
|
|
)
|
|
else:
|
|
pwm_pulse_pins = (("D0", "D1"),)
|
|
elif "rp2" in sys.platform:
|
|
pwm_pulse_pins = (("GPIO0", "GPIO1"),)
|
|
elif "samd" in sys.platform:
|
|
pwm_pulse_pins = (("D0", "D1"),)
|
|
if "SAMD21" in sys.implementation._machine:
|
|
# MCU is too slow to capture short pulses.
|
|
pwm_freq_limit = 2_000
|
|
else:
|
|
print("Please add support for this test on this platform.")
|
|
raise SystemExit
|
|
|
|
|
|
# Test a specific frequency and duty cycle.
|
|
def _test_freq_duty(self, pulse_in, pwm, freq, duty_u16):
|
|
print("freq={:<5} duty_u16={:<5} :".format(freq, duty_u16), end="")
|
|
|
|
# Check configured freq/duty_u16 is within error bound.
|
|
freq_error = abs(pwm.freq() - freq) * 1000 // freq
|
|
duty_error = abs(pwm.duty_u16() - duty_u16) * 1000 // (duty_u16 or 1)
|
|
print(" freq={} freq_er={}".format(pwm.freq(), freq_error), end="")
|
|
print(" duty={} duty_er={}".format(pwm.duty_u16(), duty_error), end="")
|
|
print(" :", end="")
|
|
self.assertLessEqual(freq_error, freq_margin_per_thousand)
|
|
self.assertLessEqual(duty_error, duty_margin_per_thousand)
|
|
|
|
# Calculate expected timing.
|
|
expected_total_us = 1_000_000 // freq
|
|
expected_high_us = expected_total_us * duty_u16 // 65535
|
|
expected_low_us = expected_total_us - expected_high_us
|
|
expected_us = (expected_low_us, expected_high_us)
|
|
timeout = 2 * expected_total_us
|
|
|
|
# Wait for output to settle.
|
|
time_pulse_us(pulse_in, 0, timeout)
|
|
time_pulse_us(pulse_in, 1, timeout)
|
|
|
|
if duty_u16 == 0 or duty_u16 == 65535:
|
|
# Expect a constant output level.
|
|
no_pulse = (
|
|
time_pulse_us(pulse_in, 0, timeout) < 0 and time_pulse_us(pulse_in, 1, timeout) < 0
|
|
)
|
|
self.assertTrue(no_pulse)
|
|
if expected_high_us == 0:
|
|
# Expect a constant low level.
|
|
self.assertEqual(pulse_in(), 0)
|
|
else:
|
|
# Expect a constant high level.
|
|
self.assertEqual(pulse_in(), 1)
|
|
else:
|
|
# Test timing of low and high pulse.
|
|
n_averaging = 10
|
|
for level in (0, 1):
|
|
t = 0
|
|
time_pulse_us(pulse_in, level, timeout)
|
|
for _ in range(n_averaging):
|
|
t += time_pulse_us(pulse_in, level, timeout)
|
|
t //= n_averaging
|
|
expected = expected_us[level]
|
|
print(" level={} timing_er={}".format(level, abs(t - expected)), end="")
|
|
self.assertLessEqual(abs(t - expected), timing_margin_us)
|
|
|
|
print()
|
|
|
|
|
|
# Test a specific frequency with multiple duty cycles.
|
|
def _test_freq(self, freq):
|
|
print()
|
|
self.pwm.freq(freq)
|
|
for duty in (0, 10, 25, 50, 75, 90, 100):
|
|
duty_u16 = duty * 65535 // 100
|
|
if sys.platform == "esp32":
|
|
# TODO why is this bit needed to get it working on esp32?
|
|
self.pwm.init(freq=freq, duty_u16=duty_u16)
|
|
time.sleep(0.1)
|
|
self.pwm.duty_u16(duty_u16)
|
|
_test_freq_duty(self, self.pulse_in, self.pwm, freq, duty_u16)
|
|
|
|
|
|
# Given a set of pins, this test class will test multiple frequencies and duty cycles.
|
|
class TestBase:
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
print("set up pins:", cls.pwm_pin, cls.pulse_pin)
|
|
cls.pwm = PWM(cls.pwm_pin)
|
|
cls.pulse_in = Pin(cls.pulse_pin, Pin.IN)
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
cls.pwm.deinit()
|
|
|
|
def test_freq_50(self):
|
|
_test_freq(self, 50)
|
|
|
|
def test_freq_100(self):
|
|
_test_freq(self, 100)
|
|
|
|
def test_freq_500(self):
|
|
_test_freq(self, 500)
|
|
|
|
def test_freq_1000(self):
|
|
_test_freq(self, 1000)
|
|
|
|
@unittest.skipIf(pwm_freq_limit < 2000, "frequency too high")
|
|
def test_freq_2000(self):
|
|
_test_freq(self, 2000)
|
|
|
|
@unittest.skipIf(pwm_freq_limit < 5000, "frequency too high")
|
|
def test_freq_5000(self):
|
|
_test_freq(self, 5000)
|
|
|
|
@unittest.skipIf(pwm_freq_limit < 10000, "frequency too high")
|
|
def test_freq_10000(self):
|
|
_test_freq(self, 10000)
|
|
|
|
|
|
# Generate test classes, one for each set of pins to test.
|
|
for pwm, pulse in pwm_pulse_pins:
|
|
cls_name = "Test_{}_{}".format(pwm, pulse)
|
|
globals()[cls_name] = type(
|
|
cls_name, (TestBase, unittest.TestCase), {"pwm_pin": pwm, "pulse_pin": pulse}
|
|
)
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|