Skip to content

serial: leave a UART only the DMA streams a timer output will use - #12128

Open
MrScothh wants to merge 22 commits into
iNavFlight:maintenance-10.xfrom
MrScothh:feature/uart-dma-streams-by-use
Open

MrScothh wants to merge 22 commits into
iNavFlight:maintenance-10.xfrom
MrScothh:feature/uart-dma-streams-by-use

Conversation

@MrScothh

@MrScothh MrScothh commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Builds on #12062 (UART TX DMA), which builds on
#12033 (UART RX DMA)
; until those merge this diff carries their commits too, and only the last commit is this PR.

Stacked on this one: #12129 and #12132.

With #12033/#12062 a UART refuses any DMA stream that any timer output in target.c is mapped to, because MSP ports
open before the motors do. On F4 and F7 each UART can only use one or two fixed streams, and the timer outputs take
most of them: counting the 182 F4/F7 target folders on maintenance-10.x (931 UARTs), 42 % of the UARTs find no
stream to receive on and 50 % none to send on.

A stream is now refused only when a timer output will really use it:

  • with the motors on DSHOT, every output's stream until the motors start, and afterwards the streams the motors
    took, which they own by then;
  • the LED strip's pad, when that feature is on, since the strip claims its stream late in init.

Outputs that end up as servos or unused, and every output when the motors are not on DSHOT, leave their streams to
the serial ports, except the LED strip's pad while that feature is on. With the same count, the UARTs with no stream to receive on drop to 26 % on a quad (four DSHOT
motors) and 6 % on a plane (one).

On its own this changes nothing for the targets in the tree today: only TBS_LUCID_H7_WING names a UART stream, and none of its outputs is mapped to it. It matters once ports get streams without naming them, which #12129 (DMA on every UART, stacked on this one) does; without this rule half of those ports on F4 and F7 would find none.

This is decided at each boot: after changing the motor protocol, the mixer or the LED strip feature, a port gets or
gives back its stream at the next reboot. The target guide (timer-dma-conflicts.md) says so.

Tested

A test-only patch (not in this PR) names, on a locally modified target, a UART stream that an unused output is also
mapped to, and prints the owner of the streams in status.

FLYWOOF722PRO, GPS (u-blox M10) on UART5, receive stream DMA1 S0 = output S7:

Setup #12062 this PR
4 motors, DSHOT300 S0 free, GPS on the interrupt S0 taken by UART5
8 motors, DSHOT300 (S7 is a motor) S0 taken by the timer, GPS on the interrupt
PWM motors, LED strip on, UART6 send stream DMA2 S6 = the LED's S6 taken by the LED strip
same, LED strip off S6 taken by UART6

GPS for 3 minutes on DMA and 3 on the interrupt: 0 errors, 0 timeouts, about 10.4 packets/s both ways. With the GPS on
DMA and the ESC powered (no props), disarmed motor steps drew the same current as on the base image, with 0 GPS errors.

KAKUTEH7MINI, GPS (SAM-M10Q) on UART2, receive stream DMA1 S7 = output S8: free on #12062; with this PR taken by
UART2 with 4 DSHOT motors, taken by the timer with 8, taken by UART2 again with 8 on ONESHOT125. GPS 0 errors.

The unit test uart_dma_stream_unittest covers the same rules on plain data, with a source check against the live
function.

Not tested on hardware: F4 and AT32 (no boards here). The rule is the same code on every family.

Size

Identical on every target whose UARTs have no stream named; TBS_LUCID_H7_WING, the only one that names one today,
+64 B of flash.

NAV-SIG (M9, M10) and NAV-SAT (M8) were requested at every navigation
epoch. They feed only the satellite list in the CLI, yet they are most of
what the receiver sends: NAV-SIG carries 16 bytes for each tracked signal,
several hundred bytes per epoch on a multi-constellation receiver, against
about 100 for the NAV-PVT that navigation runs on.

They are now requested every (gps_ublox_nav_hz + 1) / 2 epochs, which is
about twice a second at any navigation rate.
A receive buffer has to hold what arrives between two runs of the task
that drains it. For the GPS task, 20 ms apart, that is up to 230 bytes at
115200 and 460 at 230400, and a reply to a poll has to fit whole: MON-VER
alone can be 258 bytes. With the 256 bytes every port has, a NEO-F10N at
230400 was never identified, because its MON-VER reply was always cut.

The GPS port now gets a 512 byte buffer of its own, in FASTRAM, where
there is room: CCM on F405, RAM1 on AT32F43x. serialSetRxBuffer() swaps
it in right after the port is opened. Every other port keeps its 256
bytes.

The note that occupied sizes are returned as uint8_t no longer held: the
driver functions and the ring indices are all 32 bit.
The satellite details also feed the OSD's GPS extra stats, not only
gpssats, so the comment now says both. The comments are one line each,
the buffer states the rate it covers (230400; at 460800 and above a
NAV-PVT plus a large NAV-SIG can still overflow it), its size is asserted
to be a power of two because softserial masks with size - 1, and it only
exists where the u-blox provider does, the only one that opens a port.
The note in serial_uart.h about sending a UBLOX SVINFO was stale.
A UART receiving through a DMA stream costs no interrupt per byte, and keeps
the bytes that arrive while interrupts are held off. A target turns it on per
port with UARTx_RX_DMA; a port without one, and a target that names none,
build and behave exactly as before.

The stream fills the port's own ring, whose head is read back from the
transfer counter, so nothing above the driver changes. Ports whose owner
takes each byte through rxCallback (the serial receivers, which frame by
timing) stay on the interrupt even when a stream is named.

F4 and F7 wire each receiver to fixed streams, so a tag naming another is a
build error. H7 and AT32 route through the DMAMUX. On H7 the ring moves to
D2 SRAM, out of the data cache. A stream any timer output is mapped to is
left to the timers, since MSP ports open before the motors do.

On F7, H7 and AT32 the interrupt handler tested the RX flag without the
enable, so a port receiving through DMA could have lost a byte to the
interrupt raised for what it sends; it now leaves the data register alone.

Enabled on TBS_LUCID_H7_WING for UART2, on DMA2 stream 5.
serialSetRxBuffer() only swapped the ring's pointer and size, but a DMA
stream keeps writing to the memory it was started on, so a port receiving
through DMA would have gone on filling its old ring while the reader looked
at the new one. The serial vtable gets an optional setRxBuffer, which the
UARTs implement by swapping the ring and, if a stream is running, starting
it again on the new one.

The GPS ring must then be memory a stream can reach on targets that receive
through DMA: D2 SRAM on H7 rather than DTCM, and on F4 and AT32F43x plain
RAM rather than CCM or RAM1. Everywhere else it stays in FASTRAM, so a
target without UARTx_RX_DMA builds exactly as before.

On the TBS Lucid H7 Wing, GPS on UART2 through DMA2 stream 5, NEO-F10N:
identified with no errors or timeouts at 115200 and after autobaud to
230400, NAV-PVT at the configured 10 Hz. Over ten reboots, 1 error and 2
timeouts at startup, against 1 and 1 over nine with the byte interrupt.
A UART sends one byte per interrupt. A target can now name a stream for a
port's transmitter (UARTx_TX_DMA), as it can for the receiver: the stream
empties the transmit ring and the port takes one interrupt per transfer.
writeBuf() queues a message whole, so MSP and MAVLink send each in one
transfer; what is queued while one runs goes in the next.

On F4, F7, H7 and AT32. The transmit ring moves to D2 SRAM on H7, as the
receive ring does. The stream check the receiver used now serves both, and
F4/F7 targets naming a stream the transmitter is not wired to fail to
build. The TBS Lucid H7 Wing sends on UART2 through DMA2 stream 7.
iNavFlight#12119 turns the F7 D-cache on and makes DMA_RAM an uncached SRAM2
region. A ring left in cached RAM could then hand the CPU a line it
cached before the stream filled it. The rings go in DMA_RAM, as on H7;
on F7 that is plain RAM until iNavFlight#12119, so on its own this changes nothing.

Not seen to fail at 115200: FLYWOOF722PRO with iNavFlight#12119 and the GPS
sending on the interrupt had 0-1 errors per boot with the rings in
cached RAM and in DMA_RAM alike.
On F7 and H7, stopping the stream clears USART_CR3_DMAR and only
uartReconfigure() set it again. After serialSetRxBuffer() the stream ran
but the UART never fed it, and with the byte interrupt off for a DMA port
the port stayed deaf until the next baud, mode or option change. The GPS
got away with it because the u-blox driver changes the baud rate right
after swapping its ring. F4 and AT32 already set the request when the
stream starts.

With a test patch that swaps a larger GPS ring in 10 s after boot,
FLYWOOF722PRO and KAKUTEH7MINI had a timeout on every boot without this
and none with it.
# Conflicts:
#	src/main/drivers/serial_uart_stm32f7xx.c
MSP DisplayPort and the serial gimbal swap their own TX buffer into the port after opening it. On
H7 that buffer is in AXI SRAM, which the CPU caches, so the stream sends what is in RAM rather than
what was just written. Kakute H7 Mini with the GPS port given such a buffer (a test patch): the
u-blox never got its configuration (3 timeouts, no navigation messages); with this, a navigation
message every 120 ms and 0 errors over 3 reboots. On F7 every ring is cached once iNavFlight#12119 turns its
D-cache on: FLYWOOF722PRO with iNavFlight#12119 had 11-14 GPS errors and no fix on every boot, and 0 with this.

The lines the transfer covers are written back first. Without a D-cache, or on the uncached D2
rings, that does nothing.
The stream check refused every stream any timer output is mapped to, so
a target naming a UART stream on F4 or F7, where each UART has one or
two fixed streams, would find most of them taken. Now it refuses a
stream while DSHOT motors that may take it have not started, and the LED
strip's stream when that feature is on. Started motors already own their
streams, so a port opened after them gets the streams of outputs that
ended up as servos or unused, and every stream but the LED strip's when
the motors are not on DSHOT. The choice is made at each boot.
@qodo-code-review

Copy link
Copy Markdown
Contributor

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Add UART DMA with use-aware timer stream reservations

✨ Enhancement 🐞 Bug fix 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Add opt-in UART receive and transmit DMA, with interrupt fallback when a stream is unavailable.
Diagram

graph TD
  Config["Target DMA tags"] --> Open["UART open"] --> Timer{"Timer reserves?"} -->|No| Owner{"Stream available?"} -->|Yes| DMA["UART DMA"] --> Ring["Serial rings"]
  Timer -->|Yes| IRQ["Byte interrupts"]
  Owner -->|No| IRQ
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Reserve every mapped timer stream
  • ➕ Simple and conservative before motor initialization.
  • ➖ Excludes UART DMA from streams mapped only to unused outputs or servos.
2. Reassign streams after output initialization
  • ➕ Could make more streams available to ports opened early.
  • ➖ Requires switching active UART transfers and coordinating DMA ownership during initialization.

Recommendation: Keep the boot-time, use-aware reservation approach. It protects potential DSHOT and LED claims without disrupting active ports, while allowing unused mappings to serve UARTs. Review the stacked RX/TX DMA changes separately from the final reservation rule where possible.

Files changed (21) +1850 / -39

Enhancement (14) +1453 / -39
pwm_mapping.cReserve only timer streams that may still be claimed +23/-0

Reserve only timer streams that may still be claimed

• Tracks completion of motor initialization. Before DSHOT motors start, protects mapped output streams; afterward, relies on ownership for claimed streams while protecting the enabled LED strip's stream.

src/main/drivers/pwm_mapping.c

pwm_mapping.hExpose the timer DMA reservation query +2/-0

Expose the timer DMA reservation query

• Declares the reservation check used when a UART considers a DMA stream.

src/main/drivers/pwm_mapping.h

serial.cAllow serial clients to replace a receive ring +25/-0

Allow serial clients to replace a receive ring

• Adds an API to install a larger receive buffer, resetting its indices atomically or delegating to a driver-specific implementation.

src/main/drivers/serial.c

serial.hDeclare receive-buffer replacement support +4/-0

Declare receive-buffer replacement support

• Adds the serial buffer API and an optional vtable hook for drivers that must restart reception.

src/main/drivers/serial.h

serial_uart.cIntegrate DMA and buffered writes in the UART core +50/-9

Integrate DMA and buffered writes in the UART core

• Starts configured DMA directions when ports open, falls back to interrupts, and reads DMA receive progress. Adds whole-buffer write handling and a receive-buffer replacement hook.

src/main/drivers/serial_uart.c

serial_uart.hTrack UART RX and TX DMA state +10/-4

Track UART RX and TX DMA state

• Adds conditional DMA descriptors and an in-flight transmit count to each UART port. Updates comments about default ring sizes.

src/main/drivers/serial_uart.h

serial_uart_at32f43x.cImplement AT32F43x UART DMA transfers +239/-2

Implement AT32F43x UART DMA transfers

• Adds DMAMUX-backed circular receive DMA and queued transmit DMA with completion handling. Preserves byte-interrupt reception and transmission when DMA is not selected.

src/main/drivers/serial_uart_at32f43x.c

serial_uart_hal.cPreserve DMA requests across HAL UART reconfiguration +61/-9

Preserve DMA requests across HAL UART reconfiguration

• Restores RX/TX DMA request bits after HAL reinitialization and starts streams when opening a port. Adds DMA-aware receive accounting, buffered writes, and receive-buffer replacement.

src/main/drivers/serial_uart_hal.c

serial_uart_hal_at32f43x.cConnect AT32 HAL UART ports to DMA +49/-9

Connect AT32 HAL UART ports to DMA

• Selects DMA or interrupts per direction at port open. Adds DMA-aware receive accounting and queued whole-buffer writes.

src/main/drivers/serial_uart_hal_at32f43x.c

serial_uart_impl.hCentralize UART DMA eligibility and ring helpers +145/-0

Centralize UART DMA eligibility and ring helpers

• Validates fixed F4/F7 UART DMA mappings at build time and checks timer reservations plus existing ownership at runtime. Provides DMA state, receive-head, transmit-cache, and buffer-swap helpers.

src/main/drivers/serial_uart_impl.h

serial_uart_stm32f4xx.cImplement STM32F4 UART RX and TX DMA +226/-0

Implement STM32F4 UART RX and TX DMA

• Adds configured circular receive streams and completion-driven transmit streams. Checks stream availability and retains interrupt fallback.

src/main/drivers/serial_uart_stm32f4xx.c

serial_uart_stm32f7xx.cImplement cache-aware STM32F7 UART DMA +297/-2

Implement cache-aware STM32F7 UART DMA

• Adds RX/TX stream setup and transmit completion handling, with DMA-accessible receive buffers and transmit cache cleaning. Keeps UART byte handlers from consuming DMA-managed directions.

src/main/drivers/serial_uart_stm32f7xx.c

serial_uart_stm32h7xx.cImplement DMAMUX-backed STM32H7 UART DMA +314/-2

Implement DMAMUX-backed STM32H7 UART DMA

• Adds RX/TX stream setup, uncached D2 receive and transmit rings, and completion-driven sending. Keeps interrupt handling separate from DMA-managed directions.

src/main/drivers/serial_uart_stm32h7xx.c

gps_ublox.cReduce u-blox satellite-detail message frequency +8/-2

Reduce u-blox satellite-detail message frequency

• Requests NAV-SIG and NAV-SAT approximately twice per second instead of every navigation epoch, reducing serial traffic not needed for navigation.

src/main/io/gps_ublox.c

Bug fix (1) +20 / -0
gps.cGive u-blox GPS ports a larger receive ring +20/-0

Give u-blox GPS ports a larger receive ring

• Installs a 512-byte GPS receive buffer after opening the port so larger replies can fit. Selects memory appropriate to DMA and cache constraints when UART RX DMA is enabled.

src/main/io/gps.c

Tests (3) +259 / -0
gps_heartbeat_unittest.ccStub the new serial buffer API in GPS heartbeat tests +1/-0

Stub the new serial buffer API in GPS heartbeat tests

• Adds a test stub for the receive-buffer replacement call used during GPS initialization.

src/test/unit/gps_heartbeat_unittest.cc

gps_null_port_unittest.ccStub receive-buffer replacement in null-port tests +7/-0

Stub receive-buffer replacement in null-port tests

• Adds a test stub so GPS null-port tests accommodate the new serial API.

src/test/unit/gps_null_port_unittest.cc

uart_dma_stream_unittest.ccTest timer-aware UART DMA stream eligibility +251/-0

Test timer-aware UART DMA stream eligibility

• Covers pre- and post-initialization DSHOT behavior, non-DSHOT outputs, LED reservations, and DMA ownership. Source-sync checks detect divergence between the host-side model and the live reservation and availability functions.

src/test/unit/uart_dma_stream_unittest.cc

Documentation (1) +102 / -0
timer-dma-conflicts.mdDocument UART DMA configuration and stream conflicts +102/-0

Document UART DMA configuration and stream conflicts

• Explains opt-in RX/TX DMA tags, MCU stream constraints, ownership conflicts, and interrupt fallback. Documents how motor protocol, output assignment, and LED-strip settings affect stream availability after reboot.

docs/development/targets/timer-dma-conflicts.md

Other (2) +16 / -0
target.hEnable UART2 RX and TX DMA on TBS_LUCID_H7_WING +3/-0

Enable UART2 RX and TX DMA on TBS_LUCID_H7_WING

• Names DMA2 streams for UART2 reception and transmission, avoiding the documented output and ADC stream mappings.

src/main/target/TBS_LUCID_H7_WING/target.h

common_post.hEnable UART DMA code only for configured directions +13/-0

Enable UART DMA code only for configured directions

• Derives RX and TX DMA feature flags from per-port stream definitions, leaving targets without those definitions on their existing path.

src/main/target/common_post.h

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Motorless craft use slower serial ports 🐞 Bug ≡ Correctness
Description
pwmIsDmaStreamReserved() treats every timer-mapped stream as a future motor stream whenever DSHOT
is configured and motor initialization has not finished, without checking whether the mixer has any
motors. Serial ports open before mixer initialization, so a motorless configuration retaining DSHOT
falls back to byte interrupts on those streams even though no motor will claim them.
Code

src/main/drivers/pwm_mapping.c[548]

+    const bool motorsWillClaim = !motorsInitialised && getMotorProtocolProperties(motorConfig()->motorPwmProtocol)->isDSHOT;
Evidence
Serial initialization precedes mixerConfigInit() and pwmMotorAndServoInit(). The new predicate
reserves every matching timer tag during that interval, while motor initialization configures
outputs only by the mixer's motor count; UART availability rejects a reserved stream before checking
its ownership.

src/main/fc/fc_init.c[293-363]
src/main/drivers/pwm_mapping.c[426-460]
src/main/drivers/pwm_mapping.c[545-563]
src/main/drivers/serial_uart_impl.h[88-95]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Motorless configurations with DSHOT selected reserve timer DMA streams before startup even though no motors will use them.
## Fix Focus Areas
- src/main/drivers/pwm_mapping.c[545-563]
- src/main/fc/fc_init.c[293-363]
## Recommended Fix
Make motor availability known before serial ports acquire streams, then apply the pre-initialization DSHOT reservation only when motors can actually be assigned. Preserve the existing protection for motors that will start later.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

2. F7 receive ring comment promises an uncached buffer it lacks 🐞 Bug ⚙ Maintainability
Description
The F7 driver gives each named UART a separate DMA_RAM receive ring and says this keeps it
uncached once the D-cache is on, but build_config.h defines DMA_RAM as empty on STM32F7, so the
ring is ordinary .bss and the port's own uart->rxBuffer sits unused (256 B each). RX DMA on F7
is correct today only because SCB_EnableDCache() is commented out in system_stm32f7xx.c; if
someone turns the cache on, trusting this comment (and the matching assumption for gpsRxBuffer in
gps.c), the CPU would read stale bytes and nothing would warn.
Code

src/main/drivers/serial_uart_stm32f7xx.c[R295-297]

+// In DMA_RAM, which stays uncached once the D-cache is on: from the cache the CPU would not see what the stream wrote
+#ifdef UART1_RX_DMA
+static DMA_RAM uint8_t uart1RxDmaBuffer[UART_RX_BUFFER_SIZE];
Evidence
build_config.h defines DMA_RAM with a section attribute only for H7 and AT32F43x; every other
target, F7 included, gets an empty macro. The F7 system init has the D-cache enable commented out.
So the comment's claim that DMA_RAM keeps the buffer uncached does not hold on F7. The separate
buffer adds nothing over uart->rxBuffer, and correctness quietly depends on the cache staying off.

src/main/build/build_config.h[54-62]
src/main/target/system_stm32f7xx.c[303-303]
src/main/drivers/serial_uart_stm32f7xx.c[295-346]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
On STM32F7, `DMA_RAM` expands to nothing (build_config.h), so the per-UART `uartNRxDmaBuffer` arrays in serial_uart_stm32f7xx.c are plain .bss duplicates of `uart->rxBuffer`. The comment says they stay uncached once the D-cache is on, which is wrong. RX DMA works only because the F7 D-cache is disabled.
## Fix Focus Areas
- src/main/drivers/serial_uart_stm32f7xx.c[295-346]
- src/main/drivers/serial_uart_stm32f7xx.c[644-648]
- src/main/io/gps.c[98-106]
## Recommended Fix
Remove the F7 `uartRxDmaBuffer` arrays and keep `uart->rxBuffer`, saving 256 B for each named port. Change the comment (and the one in gps.c) to say that F7 runs with the D-cache disabled, so any SRAM buffer works. Optionally add a `#error` or STATIC_ASSERT guard to catch the D-cache being enabled on F7 while USE_UART_RX_DMA is defined.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can keep summaries lean with Findings visible per group, which tucks the rest behind a View link

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/main/drivers/pwm_mapping.c
Comment on lines +295 to +297
// In DMA_RAM, which stays uncached once the D-cache is on: from the cache the CPU would not see what the stream wrote
#ifdef UART1_RX_DMA
static DMA_RAM uint8_t uart1RxDmaBuffer[UART_RX_BUFFER_SIZE];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Informational

2. F7 receive ring comment promises an uncached buffer it lacks 🐞 Bug ⚙ Maintainability

The F7 driver gives each named UART a separate DMA_RAM receive ring and says this keeps it
uncached once the D-cache is on, but build_config.h defines DMA_RAM as empty on STM32F7, so the
ring is ordinary .bss and the port's own uart->rxBuffer sits unused (256 B each). RX DMA on F7
is correct today only because SCB_EnableDCache() is commented out in system_stm32f7xx.c; if
someone turns the cache on, trusting this comment (and the matching assumption for gpsRxBuffer in
gps.c), the CPU would read stale bytes and nothing would warn.
Agent Prompt
## Issue description
On STM32F7, `DMA_RAM` expands to nothing (build_config.h), so the per-UART `uartNRxDmaBuffer` arrays in serial_uart_stm32f7xx.c are plain .bss duplicates of `uart->rxBuffer`. The comment says they stay uncached once the D-cache is on, which is wrong. RX DMA works only because the F7 D-cache is disabled.

## Fix Focus Areas
- src/main/drivers/serial_uart_stm32f7xx.c[295-346]
- src/main/drivers/serial_uart_stm32f7xx.c[644-648]
- src/main/io/gps.c[98-106]

## Recommended Fix
Remove the F7 `uartRxDmaBuffer` arrays and keep `uart->rxBuffer`, saving 256 B for each named port. Change the comment (and the one in gps.c) to say that F7 runs with the D-cache disabled, so any SRAM buffer works. Optionally add a `#error` or STATIC_ASSERT guard to catch the D-cache being enabled on F7 while USE_UART_RX_DMA is defined.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On its own it is plain RAM: the rings are there for #12119, which turns the F7 D-cache on and makes DMA_RAM an uncached SRAM2 section. Until then each ring only duplicated the port's own, 256 B for every UART with a stream once #12129 is in. They are now compiled only where DMA_RAM is uncached (DMA_RAM_UNCACHED, set by #12119 together with the D-cache): d2cafb6 on #12033, 4d2c700 on #12119, so either can go in first. On #12129 that gives back 1280 B of RAM on MATEKF722SE and 1536 B on KAKUTEF7; with #12119 merged the rings are in SRAM2 again.

@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

RAM / Flash usage vs. base commit e87050f — commit b6e7d0c

Using the nearest available size baseline — the PR's exact base commit has no stored baseline yet.

Target Flash Δ RAM Δ
MATEKF405 +232 B (+0.03%) CCM: +512 B (+1.57%)
RAM: +8 B (+0.01%)
MATEKF722 +172 B (+0.04%) ITCM_RAM: +16 B (+0.13%)
RAM: +8 B (+0.01%)
TCM: +516 B (+2.04%)
MATEKF765 +512 B (+0.07%) DTCM_RAM: +512 B (+1.79%)
SRAM1: ±0 B (±0.00%)
MATEKH743 +336 B (+0.04%) D2_RAM: ±0 B (±0.00%)
DTCM_RAM: +512 B (+3.95%)
ITCM_RAM: ±0 B (±0.00%)
RAM: ±0 B (±0.00%)

See RAM/flash optimization guide for techniques to reduce usage.

@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Test firmware build ready — commit b6e7d0c

Download firmware for PR #12128

251 targets built. Find your board's .hex file by name on that page (e.g. MATEKF405SE.hex). Files are individually downloadable — no GitHub login required.

Development build for testing only. Use Full Chip Erase when flashing.

On F7 DMA_RAM is plain RAM until iNavFlight#12119 turns the D-cache on and makes
it an uncached SRAM2 section, so until then each ring only duplicated
the port's own, 256 B per UART with a receive stream. They are compiled
only where build_config.h says DMA_RAM is uncached (DMA_RAM_UNCACHED,
set together with the D-cache), so either PR can go in first.
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