Skip to content

arch/arm/am67: Add eCAP APWM lower-half driver - #20138

Draft
gemstonedevteam wants to merge 9 commits into
apache:masterfrom
t3gemstone:am67-pr-06
Draft

gemstonedevteam wants to merge 9 commits into
apache:masterfrom
t3gemstone:am67-pr-06

Conversation

@gemstonedevteam

Copy link
Copy Markdown

Opening as draft since this depends on #20137 will mark ready once that lands.

Summary

  • Adds a PWM lower-half driver for the AM67 eCAP modules in APWM mode, where
    the module is used as a single-channel PWM generator rather than a capture
    unit.
  • Period is programmed in CAP1 and the compare value in CAP2, with the
    counter free-running from the eCAP functional clock at 125 MHz.
  • start() reprograms the time base only when the frequency changes, so a
    duty-only update does not clear TSCNTSTP or zero TSCTR on a running
    counter.
  • t3-gem-o1 registers eCAP1 as /dev/ecap1 and eCAP2 as /dev/ecap2. Output
    pad selection is left to the board; the candidate pads collide with I2C0 on
    this design.

Impact

  • Is new feature added? YES — eCAP APWM support for AM67.
  • Impact on user? NO — new driver, opt-in by Kconfig.
  • Impact on build? NO.
  • Impact on hardware? YES — arch/arm/am67 and board t3-gem-o1.
  • Impact on documentation? YES — provided in this PR (second commit).
  • Impact on security? NO.
  • Impact on compatibility? NO — additive.
  • Anything else? Depends on PRs 3–5.

Testing

Build Host(s): Pardus GNU/Linux 25 (Debian 13 base), x86_64, host gcc 14
Toolchain:     arm-none-eabi-gcc 14.2.1 20241119 (15:14.2.rel1-1)
Target:        arm / TI AM67 (J722S) Cortex-R5F, board t3-gem-o1:nsh
nuttx-apps:    5a7ab4200
Loaded on the main-domain R5F by Linux remoteproc; console on UART-MAIN1.

Testing logs before change: no eCAP support on this arch.

The version string in the logs is from the tested build; the commits were
GPG-signed afterwards, which rewrites hashes. The code is unchanged.

Testing logs after change:

make distclean && ./tools/configure.sh t3-gem-o1:nsh && make -j
  -> nuttx ELF 543332 bytes, 0 compiler warnings

Console:
nsh> pwm -p /dev/ecap1 -f 1000 -d 50 -t 1
pwm_main: starting output with frequency: 1000 channel: 1 duty: 00007fff channel: 2 duty: 00007fff
pwm_main: stopping output
nsh> pwm -p /dev/ecap2 -f 1000 -d 50 -t 1
pwm_main: starting output with frequency: 1000 channel: 1 duty: 00007fff channel: 2 duty: 00007fff
pwm_main: stopping output
nsh> pwm -p /dev/ecap1 -f 1000 -d 25 -t 2
pwm_main: starting output with frequency: 1000 channel: 1 duty: 00003fff channel: 2 duty: 00007fff
pwm_main: stopping output
nsh> pwm -p /dev/ecap1 -f 1000 -d 75 -t 2
pwm_main: starting output with frequency: 1000 channel: 1 duty: 0000bfff channel: 2 duty: 00007fff
pwm_main: stopping output
nsh>

Test plan result:
console_alive            PASS  prompt responsive
version                  PASS  NuttX version 0.0.0 aaf0c2583d Sep 10 2026 13:49:06 t3-gem-o1:nsh
procfs                   PASS  procfs readable
tasks                    PASS  2 task lines
dev_nodes                PASS  all expected nodes present
pwm_ecap1                PASS  /dev/ecap1 1 kHz / 50% for 1 s
pwm_ecap2                PASS  /dev/ecap2 1 kHz / 50% for 1 s
ecap_duty_only           PASS  25% then 75% at 1 kHz accepted

PASS=8

Measured time base, captured 2026-09-11, read back from the A53 over
/dev/mem while NuttX drives the output.

NuttX:  nsh> pwm -p /dev/ecap1 -f 1000 -d 50 -t 25 &

A53, while that is running (eCAP registers are 32-bit natively):

  /dev/ecap1 @ 0x23110000   APRD = 124999, ACMP = 62498
  /dev/ecap2 @ 0x23120000   APRD = 124999, ACMP = 62498

  frequency = 125 MHz / (124999 + 1) = 1000.00 Hz
  duty      = 62498 / 125000         = 49.998 %

  TSCTR sampled twice 0.4 s apart: 12959 -> 109982 (ecap1) and
  67938 -> 93142 (ecap2), so the counter is free-running.

This is also the direct evidence for the duty-only path above: the eCAP
clock is FICLK/2 of the EPWM's, and the 125000-tick period confirms the
125 MHz figure the driver assumes.

PR verification Self-Check

  • This PR introduces only one functional change.
  • I have updated all required description fields above.
  • My PR adheres to Contributing Guidelines and Documentation.
  • My PR is still work in progress (not ready for review).
  • My PR is ready for review and can be safely merged into a codebase.

halak0013 and others added 9 commits September 10, 2026 15:43
Adds the AM67 GPIO lower half and a polled MCU_MCSPI0 master driver, with the
pad configuration both need.  The K3 instance is not the OMAP2 layout: an HL
header block precedes the functional registers.

Chip select is released only after CHSTAT.EOT, since a high SCLK otherwise
drops it mid-word and truncates the write, and CHCTRL.EN stays asserted between
transfers.

t3-gem-o1 registers /dev/spi0 for its ICM-20948 (CS3) and LPS22DF (CS1), and
raises NSH_MAXARGUMENTS to 16 so the spi tool can address a device.

Verified on t3-gem-o1: WHO_AM_I reads 0xEA on CS3 and 0xB4 on CS1, and the
ICM-20948 streams continuous accelerometer samples over the bus.

Co-authored-by: Ulaş Sertan Kemeç <sertan.usk@gmail.com>
Assisted-by: Cursor
Assisted-by: Claude Code:claude-opus-4-8
Signed-off-by: Ulaş Sertan Kemeç <sertan.usk@gmail.com>
Add a Peripheral Support section to the board page listing the GPIO and
MCU_MCSPI0 drivers, and replace the "UART console only" warning on both
the chip and board pages -- it no longer describes the port.  The
replacement states what actually constrains the port: NuttX runs on the
R5F under RemoteProc and depends on the bootloader or Linux Device
Manager having powered and clocked the peripherals, because there is no
TISCI client yet.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Ulaş Sertan Kemeç <sertan.usk@gmail.com>
Adds an I2C master driver for the AM67 I2C instances, completing transfers on
ARDY as the K3 controller signals.

Bring-up is deferred to the first transfer, because the Linux Device Manager
enables the I2C clocks late and touching the bus during early board init is not
safe here.  The last reference drop clears the flag so the next transfer
re-initialises the hardware.

t3-gem-o1 registers WKUP_I2C0 as /dev/i2c2.

Verified on t3-gem-o1: i2c dev finds 0x30, 0x40, 0x51 and 0x68, the RTC at
0x68 reads a ticking BCD seconds register, repeated reads are consistent, and
NACK recovery returns the bus to a usable state.

Assisted-by: Claude Code:claude-fable-5
Assisted-by: Claude Code:claude-opus-4-8
Signed-off-by: Ulaş Sertan Kemeç <sertan.usk@gmail.com>
Record the WKUP_I2C0 master in the board's Peripheral Support list.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Ulaş Sertan Kemeç <sertan.usk@gmail.com>
Adds a PWM lower-half for EPWM0 and EPWM1, covering both output channels of
each.  The CTRL_MMR EPWM clock enables are unlocked once during board bring-up.

t3-gem-o1 registers /dev/pwm0 and /dev/pwm1 with PWM_NCHANNELS=2.

Verified on t3-gem-o1: all four outputs (EPWM0 A+B, EPWM1 A+B) drive physical
pins, jumpered into a Linux GPIO input -- 50% and 20% duty read back at the
expected sample ratios, and gpiomon timed a 50 Hz half-period at 9.998-10.002
ms.  examples/pwm starts and stops a 1 kHz train cleanly.

Assisted-by: Claude Code:claude-fable-5
Signed-off-by: Ulaş Sertan Kemeç <sertan.usk@gmail.com>
Record the EPWM0 and EPWM1 outputs in the board's Peripheral Support
list.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Ulaş Sertan Kemeç <sertan.usk@gmail.com>
Adds a PWM lower-half using the eCAP modules in APWM mode as single-channel
generators rather than capture units.

start() reprograms the time base only when the frequency changes, so a
duty-only update does not stop or zero a live counter.

t3-gem-o1 registers /dev/ecap1 and /dev/ecap2; output pad selection is left to
the board, as the candidates collide with I2C0.

Verified on t3-gem-o1: examples/pwm runs a 1 kHz, 50% duty train on both
instances and accepts a duty-only change (25% then 75%).  The output pins have
not been measured on copper, as no pad is assigned to them on this board.

Assisted-by: Claude Code:claude-opus-4-8
Signed-off-by: Ulaş Sertan Kemeç <sertan.usk@gmail.com>
Record the eCAP1 and eCAP2 APWM outputs in the board's Peripheral
Support list.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Ulaş Sertan Kemeç <sertan.usk@gmail.com>
arch/arm/am67: Add eCAP APWM lower-half driver.
@github-actions github-actions Bot added Area: Documentation Improvements or additions to documentation Arch: arm Issues related to ARM (32-bit) architecture Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces. Board: arm labels Sep 14, 2026
@github-actions

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

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

Labels

Arch: arm Issues related to ARM (32-bit) architecture Area: Documentation Improvements or additions to documentation Board: arm Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants