Skip to content

Configured the LINFlexD console twice, because once is not enough at -O2 - #629

Merged
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:feature/r52-s32z280-console-guard
Aug 17, 2026
Merged

Configured the LINFlexD console twice, because once is not enough at -O2#629
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:feature/r52-s32z280-console-guard

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

The S32Z280 console driver runs its configuration sequence once, and that works only because this BSP is built without an optimisation flag (CMAKE_BUILD_TYPE is empty, so everything compiles at -O0). Compiled at -O2 the same sequence leaves the line corrupted — every character partially wrong, in exactly the pattern the file already documents for a module configured outside initialisation mode.

Why this is worth guarding against

The failure is invisible to the caller:

  • UARTCR reads back exactly the value written (0x33)
  • LINIBRR reads back 21, the value written
  • LINFBRR reads back 11, the value written
  • linflexd_init returns LINFLEXD_INIT_OK

The registers are right and the line is wrong. Nothing in the returned status says the console cannot be trusted, which is the worst property a console can have — it is the instrument every other bring-up result is read through.

How it was localised

By bisection rather than inspection:

build result
everything -O2, linflexd.c at -O0 clean
everything -O0, only linflexd_init at -O2 corrupted
everything -O0, only linflexd_putc at -O2 clean

So the fault is in the configuration sequence, not the per-byte transmit path. The putc DTF handshake — whose comment warns that its ordering is load-bearing in both directions — is innocent and untouched.

The register read-backs above were obtained by instrumenting a duplicate of the sequence forced to -O2 and reporting its observations through a console repaired afterwards by a known-good pass.

What this commit does not claim

The mechanism is not understood. Tested and rejected as explanations:

  • a 100× larger bound on the wait for initialisation mode
  • a settling delay before the first LINSR read
  • a settling delay after leaving initialisation mode
  • a barrier and read-back between the two UARTCR writes
  • waiting for LINSR to report the exit from initialisation mode

None makes a single pass work at -O2. A second pass does, reliably, at both optimisation levels. Since delays do not help but a second pass does, the evidence points away from timing, and the comment in the code says so and lists what was ruled out, so the next person does not repeat it.

Verification

On the S32Z280-594EVB:

  • boot image passes six of six probes, console status still 0x00000000
  • the standalone reproducer prints correctly at both -O0 and -O2, where previously -O2 was unreadable
  • builds clean with no warnings

The console driver runs its configuration sequence a single time, and that
works only because this BSP is built without an optimisation flag. Compiled
at -O2 the same sequence leaves the line corrupted: every character
partially wrong, in the pattern the file already describes for a
misconfigured module.

What makes it worth guarding against is that the failure is invisible.
UARTCR reads back exactly the value written. LINIBRR and LINFBRR read back
exactly the values written. linflexd_init returns LINFLEXD_INIT_OK. The
registers are right and the line is wrong, so nothing in the returned
status tells the caller the console cannot be trusted.

Localised by bisection: with every other file at -O2 and this one at -O0
the output is clean, and with only linflexd_init at -O2 it is corrupted,
so the fault is in the configuration sequence rather than in the per-byte
transmit path.

The mechanism is not understood, and this commit does not claim to explain
it. Tested and rejected: a 100x larger bound on the wait for
initialisation mode, a settling delay before the first LINSR read, a
settling delay after leaving initialisation mode, a barrier and read-back
between the two UARTCR writes, and waiting for LINSR to report the exit
from initialisation mode. None of those makes a single pass work at -O2.
A second pass does, at both optimisation levels, which is what this does.

Instrumented with a duplicate of the sequence forced to -O2 and reported
through a console repaired afterwards, which is how the register read-backs
above were obtained.

Verified on the S32Z280-594EVB. The boot image passes six of six probes
with the console status still reporting 0x00000000, and the reproducer
builds clean and prints correctly at both -O0 and -O2.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
@fdesbiens
fdesbiens merged commit ff638da into eclipse-threadx:dev Aug 17, 2026
4 checks passed
@fdesbiens
fdesbiens deleted the feature/r52-s32z280-console-guard branch August 17, 2026 11:59
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