Skip to content

M4.2b: the counter, PWM and ADC classes; applications in Harmony's form - #148

Draft
teo1747 wants to merge 12 commits into
mainfrom
feat/m4.2b-adc-timers
Draft

teo1747 wants to merge 12 commits into
mainfrom
feat/m4.2b-adc-timers

Conversation

@teo1747

@teo1747 teo1747 commented Nov 13, 2026

Copy link
Copy Markdown
Member

M4.2b, the short driver phase before M4.4: timers that drive PWM, capture signals and raise alarms, and an ADC that converts once or samples by DMA, on the NUCLEO-F446RE and the Pico 2 W (A129). The owner asked during the phase for applications to follow MPLAB Harmony's form, on this branch (A130).

Draft: the classes are in progress.

Done so far

  • A129 (proposed): the counter, PWM and ADC classes, their status codes, the DMA class's circular jobs, the bench.
  • Descriptions: the STM32F446's TIM3 to TIM5, ADC1's inputs, temperature sensor, VREFINT and DMA2 streams, and 45 alternate functions; the RP2350's ADC, PWM slices, TIMER0 and TIMER1, PLL_USB at 48 MHz and its pin functions. Each was checked against RM0390 or pico-sdk 2.1.1.
  • The generator:
    • a binding per class (compatible:class), which a board device picks with class:;
    • the STM32F4 timers' doubled clock, and a PLL of a fixed rate (output_hz, clocked_by);
    • analog pins, a timer's counter_bits and an ADC's facts;
    • a binding's taken peripherals (takes:) and its fields' defaults.
  • A130 (proposed): applications in MPLAB Harmony v3's form.
    • Each board's files are in src/config/<board>/: definitions.h, configuration.h, initialization.c (SYS_Initialize()), tasks.c (SYS_Tasks()) and interrupts.c.
    • Each task is src/<task>.c and .h in Harmony's template and names. A periodic task is Harmony's _Tasks() switch; an event task keeps a handler per state.
    • A system's interrupts: lists the application's own handlers.
    • examples/tasks ran on the NUCLEO-F446RE and the Pico 2 W.

To come on this branch

  • The counter, PWM and ADC classes: their cores, the STM32 and RP2350 drivers, the DMA ring, native fakes and conformance tests.
  • Bindings and the boards' devices, and EmbSIM in CI.
  • HIL on both boards with the loop wires and the analyzer, the controller's session, and the report.

Checked locally

  • hw/gen tests (229) and emb-hwgen check --strict.
  • The file-header check (771 files) and clang-format 18 on the generated C.
  • clang-tidy 18 on the controller and the tasks example.
  • Nine presets built from a clean tree; the native suite and QEMU AN386, 42 of 42 each.
  • The tasks example with GCC and Clang on both boards.

The MISRA baseline has the controller's moved files to adopt from this run's misra-baseline-now.

Signed-off-by: teo1747 motsoujunior17@gmail.com

The project owner chose on 2026-11-13 to add them to M4 before M4.4, on
the STM32F446 and the RP2350: timers that drive PWM, capture signals and
raise alarms, an ADC that converts once or samples into a buffer by DMA,
and loop wires on the bench. A129 writes out the classes' operations,
their status codes, the DMA class's circular jobs, the descriptions'
new peripherals and the wires.

Signed-off-by: teo1747 <motsoujunior17@gmail.com>
Signed-off-by: teo1747 <motsoujunior17@gmail.com>
…lass

The STM32F446 gains TIM3 to TIM5 (RM0390 Table 38, the RCC's APB1ENR),
ADC1's inputs, temperature sensor, VREFINT and DMA2 streams (Table 29),
and 45 alternate functions from EmbSIM's catalog. The RP2350 gains its
ADC, PWM slices, TIMER0 and TIMER1 and PLL_USB, each checked against
pico-sdk 2.1.1's addressmap.h, intctrl.h, dreq.h and RP2350.svd.

The generator:
- a binding per class, keyed compatible:class, picked by a device's
  class: (A129);
- the STM32F4 timers' doubled clock, peripheral.timer_clock_hz;
- a PLL of a fixed rate, solved from the board's source, and
  clocked_by: on a peripheral;
- analog pins, the counter's width and the ADC's facts;
- a node path may hold a binding's class (diagnostics).

Signed-off-by: teo1747 <motsoujunior17@gmail.com>
A binding's takes: names peripherals a device uses besides its own, by
the device key that names each and the compatible it must have: the
STM32 ADC's pacing timer (trigger: tim2). They are checked, reserved,
ordered after the clock tree, and read as takes.<key>.<field>. A field
may be { from, default } for a device that does not give it (A129).

Signed-off-by: teo1747 <motsoujunior17@gmail.com>
The owner chose on 2026-11-13 that an application's generated files
follow MPLAB Harmony v3's layout, templates and names. Each board's go
to Harmony's configuration folder, src/config/<board>/:
- definitions.h, configuration.h, initialization.c (SYS_Initialize()),
  tasks.c (the tasks and SYS_Tasks()), interrupts.h and interrupts.c;
- the board's outputs under peripheral/, linker/, build/ and docs/,
  their folders given to the SoC builds by board.cmake.

The application's own files are in Harmony's templates: main.c calls
SYS_Initialize(NULL) then SYS_Tasks(), and each task is src/<task>.c
and .h with DOOR_STATES, DOOR_EVENTS, DOOR_DATA doorData,
DOOR_Initialize() and a handler per state, or a periodic task's
BLINK_Tasks() switch. A system's interrupts: lists the application's
own handlers, checked against the SoC, the devices and the port.

examples/tasks raises a spare line on each SoC and opens the door from
its handler; it ran on the NUCLEO-F446RE and the Pico 2 W. The naming
check is relaxed for applications' files (examples/.clang-tidy), and
the header check reads Harmony's banner.

Signed-off-by: teo1747 <motsoujunior17@gmail.com>
<emb/drv_counter.h> behind CONFIG_EMB_DRV_COUNTER (SPEC-017 §11a): a
free-running counter widened to 64 bits, one-shot alarms at an absolute
count that never fire early (EMB_EPAST for one already passed), and
periodic callbacks without drift, late periods skipped.

- drivers/st/stm32_tim_counter.c: the STM32's general-purpose timers,
  widened by the update interrupt; an alarm's compare is programmed
  once its count is in the current wrap.
- drivers/rpi/rp2350_timer.c: TIMER0 and TIMER1 on their tick; an
  alarm more than 2^32 counts away is armed again until it is due.
- The NUCLEO-F446RE's TIM5 and TIM9 (16 bits, two channels: it wraps
  every 65.5 ms, so the board's tests widen the count) and the Pico 2
  W's TIMER1 are devices; the generator gives a peripheral's index and
  the board's counters (EMB_SOC_COUNTER_DEVICES).
- EMB_EPAST (-96) and EMB_ENOSIGNAL (-100), named.

test_counter (a fake) passes on native and on the NUCLEO-F446RE, and
test_counter_board on the NUCLEO-F446RE's TIM5 and TIM9.

Signed-off-by: teo1747 <motsoujunior17@gmail.com>
.gitignore's build/ hid each application's src/config/<board>/build/,
board.cmake and CMakeLists.txt among them, so CI found the outputs
stale and could not configure the controller. It now keeps them, as it
keeps a generated directory's build/.

Signed-off-by: teo1747 <motsoujunior17@gmail.com>
The new codes broke clang-format's column layout of emb_status_name()'s
driver table, which CI's lint refused. The table is now a row per class,
its four codes, with each class named, kept out of clang-format.

Signed-off-by: teo1747 <motsoujunior17@gmail.com>
<emb/drv_pwm.h> behind CONFIG_EMB_DRV_PWM (SPEC-017 §11b): output
channels set by period and pulse in nanoseconds, rounded to the
hardware's nearest and reported back, the channels of a device sharing
its period; and an input's period and pulse captured, EMB_ENOSIGNAL
when no whole cycle comes before the timeout.

- drivers/st/stm32_tim_pwm.c: PWM mode 1, preloaded, the prescaler the
  smallest for the period; one cycle captured exactly in PWM input
  mode, the counter's wraps counted by the update interrupt.
- drivers/rpi/rp2350_pwm.c: a slice's A and B, its divider in
  sixteenths; its input B averaged over a gate, edges between two of
  the counter's changes timed by the cycle counter for the period, and
  clk_sys counted while high over exactly those periods for the pulse.
- The NUCLEO-F446RE's TIM3 out on D12 and TIM4 in on D10; the Pico 2
  W's slice 7 out on GPIO14 and slice 0 in on GPIO17.
- test_pwm_loop, configured by EMB_TEST_PWM_LOOP; a pwm_input bound;
  hw.json takes the RP2350's lines above 15 and analog pins.

test_pwm passes on native and on the NUCLEO-F446RE; the loop waits for
the bench's wires.

Signed-off-by: teo1747 <motsoujunior17@gmail.com>
- 5.9: the STM32 timer drivers' statics named apart, from each other and
  from dwork.c's disarm_locked(); the counter class's too; the RP2350's
  spin.
- 10.6 and 12.2: masks shifted as 32 bits, not as unsigned char.
- 17.8, 12.1: the RP2350 PWM's flags left as given; a sleep's precedence.
- 7.3, cppcheck misreading names that end in l: a capture's fields
  renamed, and the RP2350 pin table's pull read once, in a switch.
- cppcheck's knownConditionTrueFalse (two reads of a volatile register)
  and constParameterCallback (an interrupt handler's argument),
  suppressed where they are.

Signed-off-by: teo1747 <motsoujunior17@gmail.com>
<emb/drv_adc.h> behind CONFIG_EMB_DRV_ADC (SPEC-017 §11c): one
conversion, waiting or polled; a count's millivolts; the internal
temperature sensor; and a sequence sampled at a rate into a buffer by
DMA, a callback at each half, EMB_EOVERRUN when samples are lost.

- drivers/st/stm32_adc.c: ADC1 paced by TIM2's TRGO (the device takes
  it: trigger: tim2) and moved by DMA2, its temperature from the factory
  calibration; set up by each request, so the controller keeps the ADC1
  and TIM2 it drives by hand.
- drivers/rpi/rp2350_adc.c: on clk_adc, 48 MHz from PLL_USB, which
  rp2350_clocks.c now starts; a round robin drained through its FIFO.
- The DMA class's circular jobs: the STM32's circular mode, and on the
  RP2350 one channel triggering itself again over its address ring.
- The STM32 capture timestamps each edge on a free-running counter its
  wraps extend, in place of a slave reset at the rising edge: EmbSIM
  showed a late reset moving the cycle's start.
- simulation.loopbacks takes a PWM pair and an ADC's rails: EmbSIM runs
  test_pwm_loop (D12 to D10) and test_adc_board (A2 to 3V3, A3 to GND).
- The benchmarks read hw.json from the board's docs/.

Native 45 of 45, EmbSIM's NUCLEO-F446RE 53 of 53, the NUCLEO-F446RE's
suite 54 of 54 without the two tests that wait for the bench's wires.

Signed-off-by: teo1747 <motsoujunior17@gmail.com>
"at most @period_ns:" inside the pulse's description read as a second
@PARAM section for the period, which the strict Doxygen build refuses.

Signed-off-by: teo1747 <motsoujunior17@gmail.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant