Skip to content

boards/mps2-an521: Correct the swapped UART0 TX and RX interrupts#19538

Open
casaroli wants to merge 1 commit into
apache:masterfrom
casaroli:mps2-an521-uart-irq
Open

boards/mps2-an521: Correct the swapped UART0 TX and RX interrupts#19538
casaroli wants to merge 1 commit into
apache:masterfrom
casaroli:mps2-an521-uart-irq

Conversation

@casaroli

Copy link
Copy Markdown
Contributor

Summary

boards/arm/mps/mps2-an521/configs/nsh/defconfig has CONFIG_CMSDK_UART0_TX_IRQ
and CONFIG_CMSDK_UART0_RX_IRQ the wrong way round.

The SSE-200 subsystem the AN521 image implements lists the UART interrupts
receive first: UART0 RX is external interrupt 32 and UART0 TX is 33, which in
NuttX numbering are 48 and 49. The configuration had 49 for RX and 48 for TX, so
the TX interrupt was dispatched to uart_cmsdk_rx_interrupt().

That handler acknowledges only UART_INTSTATUS_RX:

static int uart_cmsdk_rx_interrupt(int irq, FAR void *context, FAR void *arg)
{
  ...
  uart_cmsdk_serialout(priv, UART_INTSTS_OFFSET, UART_INTSTATUS_RX);
  uart_recvchars(dev);
  return OK;
}

so the asserted TX status bit survived the acknowledgement and the interrupt
re-fired immediately. The board live-locked in the interrupt handler as soon as
the console emitted its first character.

Two things corroborate the ordering rather than just the symptom:

  • the overflow interrupt in the same configuration is already at 63, external
    47, which is where the SSE-200 map puts it only if the pair below it is
    receive first;
  • mps2-an500 already follows the same convention, RX at 16 and TX at 17.

Impact

mps2-an521:nsh only. No source changes, no API or build changes, and no other
board is touched.

Before this change the board is unusable at runtime under QEMU: the NSH greeting
appears and nothing runs afterwards, console input included. After it, NSH is
interactive. Anyone who has been building this configuration in CI would not
have noticed, since it was never run.

Testing

Host: macOS 15 (Darwin 25.5.0, arm64), arm-none-eabi-gcc 14.2.Rel1,
QEMU 10.1.0. Board: mps2-an521:nsh, run with

qemu-system-arm -M mps2-an521 -nographic -kernel ./nuttx

Before

The greeting is printed and the console is dead. Typing help produces nothing;
the run below sat for 30 s after the prompt:

NuttShell (NSH) NuttX-12.2.1

Attaching gdb shows why. The board is in an interrupt entered from the very
first console write, and stays there:

#0  exception_direct () at armv8-m/arm_doirq.c:48
#1  <signal handler called>
#2  setbasepri (basepri=0) at include/arch/armv8-m/irq.h:344
#3  0x100093ba in up_irq_restore (flags=0 '\000') at include/arch/armv8-m/irq.h:385
#4  0x100098b8 in uart_cmsdk_txint (dev=0x38000088 <g_uart0port>, enable=true)
    at serial/serial_cmsdk.c:653
#5  0x1000aae0 in uart_writev (filep=0x38003fb0, uio=0x380074f8) at serial/serial.c:1639
#6  0x1001bc5a in file_writev (filep=0x38003fb0, iov=0x38007568, iovcnt=1) at vfs/fs_write.c:202
#7  0x1001bca8 in nx_writev (fd=1, iov=0x38007568, iovcnt=1) at vfs/fs_write.c:301
#8  0x1001bcd0 in writev (fd=1, iov=0x38007568, iovcnt=1) at vfs/fs_write.c:401
#9  0x1001bd22 in write (fd=1, buf=0x1003fdb4 <g_nshgreeting>, nbytes=30) at vfs/fs_write.c:466

Sampling repeatedly always lands in the same place, and with the earlier build
the frame below exception_direct is uart_cmsdk_rx_interrupt (irq=49, ...),
which is the TX interrupt arriving at the RX handler.

After

The board reaches the idle loop and NSH is interactive. help was driven over a
pty three times in a row and produced its output every time:

nsh-fixed : help worked 3/3

and a gdb sample now lands in the idle loop rather than in the handler:

#0  0x10001a74 in nx_start () at init/nx_start.c:769
769	      up_idle();
#1  0x100002e4 in __start () at chip/mps_start.c:192

Wider run

The same corrected interrupt numbers were used to run a full filesystem test
suite on this board to completion, 90 checks including power-loss injection
sweeps, over the NSH console:

==== 90 passed, 0 failed ====

The identical suite passes on mps2-an500 with its existing, already-correct
interrupt numbers, which is the cross-check that the two boards now agree.

tools/checkpatch.sh -g origin/master..HEAD passes.

The SSE-200 subsystem the AN521 image implements lists the UART interrupts
receive first: UART0 RX is external interrupt 32 and UART0 TX is 33, which
in NuttX numbering are 48 and 49.  The configuration had those two the wrong
way round, so the TX interrupt was dispatched to uart_cmsdk_rx_interrupt.

That handler clears only UART_INTSTATUS_RX, so the asserted TX status bit
survived the acknowledgement and the interrupt re-fired immediately.  The
board live-locked in the interrupt handler as soon as the console emitted its
first character: the NSH banner appeared, and nothing ran afterwards, console
input included.

Note that the overflow interrupt already sits at 63, external 47, which is
where the SSE-200 map puts it only if the pair below it is receive first --
the two corrected values are the ones consistent with it.  mps2-an500 already
follows the same order with RX at 16 and TX at 17.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
@github-actions github-actions Bot added Size: XS The size of the change in this PR is very small Board: arm labels Jul 25, 2026
@github-actions

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

@acassis
acassis requested a review from xiaoxiang781216 July 25, 2026 23:17
@xiaoxiang781216

Copy link
Copy Markdown
Contributor

@anjiahao1 please review this patch.

@casaroli

Copy link
Copy Markdown
Contributor Author

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

Labels

Board: arm Size: XS The size of the change in this PR is very small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants