sim_head.c is linked separately from libarch, so it was omitted from the
source and dependency lists. Track its source independently so
configuration and header changes rebuild sim_head.o while preserving its
link behavior.
Assisted-by: Codex:gpt-5.6 Sol
Signed-off-by: hanzhijian <hanzhijian@zepp.com>
The rp23xx common board sources reference rp23xx_st7735.c from both
Make.defs and CMakeLists.txt under CONFIG_LCD_ST7735, but the file was
never added. Enabling CONFIG_LCD_ST7735 on any rp23xx board therefore
fails the build on the missing source.
Add the file, modelled on the existing RP2040 sibling
boards/arm/rp2040/common/src/rp2040_st7735.c and retargeted to
rp23xx/SPI1. It implements board_lcd_initialize(), board_lcd_getdev()
and board_lcd_uninitialize(): bring up SPI1, claim the D/C (shared with
the unused SPI1 RX pad, per the rp23xx common convention), RST and BL
pads as GPIO, pulse the panel reset and bind the ST7735 driver.
Validated on silicon on a Waveshare RP2350-LCD-0.96 (RP2350A + ST7735S
160x80 IPS): the panel powers up and displays correctly, painted at boot
with no console interaction. Build-tested raspberrypi-pico-2:nsh with
CONFIG_LCD_ST7735=y (compiles and links).
Assisted-by: Claude (Anthropic Claude Code)
Signed-off-by: Ricard Rosson <ricard@groundbits.com>
A task does not necessarily own an address environment. tcb->addrenv_own is
set only by addrenv_attach(), which is reached only from addrenv_allocate();
a kernel thread never allocates one, and in a protected build nothing does --
there is a single address space for the whole system and the architecture's
up_addrenv_*() are stubs. addrenv_own is then NULL for every task, always.
That a task may have no address environment is already an expected state.
addrenv_switch() returns OK when tcb->addrenv_curr is NULL and addrenv_drop()
returns early, and every caller of addrenv_select() checks addrenv_own != NULL
before calling in: nxsched_get_stateinfo(), nxtask_argvstr(), proc_groupenv()
and the arm, arm64, risc-v and tricore up_check_tcbstack().
addrenv_take() and addrenv_give() are the only two that dereference
unconditionally. addrenv_join() calls addrenv_take(ptcb->addrenv_own) without
a check, so pthread_create() faults on &((struct addrenv_s *)NULL)->refs
whenever the calling task has no address environment. With
CONFIG_DEBUG_ASSERTIONS off the same access silently corrupts low memory
instead.
Handle NULL in both, the way the rest of the file already does.
addrenv_give() returns a non-zero count for the NULL case so that callers
never conclude an absent address environment has become unreferenced and
should be destroyed.
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
intel64_timer_start_absolute() computed "expected - current_us" unsigned. A
watchdog started with a delay of zero asks for a deadline that is already
current, the subtraction wraps to nearly 2^64, and the comparator is set so
far ahead that the timer never fires. The CONFIG_INTEL64_HPET_MIN_DELAY
clamp in intel64_oneshot_start() cannot help: the wrapped value is enormous,
not small.
Ask for the shortest delay the hardware can take instead of wrapping, and let
that existing minimum-delay logic pick it.
It presents as ostest hanging in wdog_test with no output and no fault.
apps/testing/ostest/wdog.c:281 calls wdtest_once(&test_wdog, param, 0), and
NSEC2TICK() takes the next few delays (1ns, 10ns, ...) to zero ticks as well;
wdtest_once() then spins forever in its "wait until the callback is triggered
exactly once" loop.
Impact: runtime, ARCH_INTEL64_HPET_ALARM only.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
copy_kernel_mappings() copies exactly one PDPT entry, the 1GB linear window
that maps physical 0-1GB at 4GB-5GB. The boot identity mapping of the low
4GB, which lives in PDPT entries 0-3 of g_pdpt_low (intel64_head.S:756, one
page directory per 1GB) and is where every MMIO register is reached, is not
carried over.
A kernel thread never gets an address environment of its own and
addrenv_switch() leaves the last one in place for it, so as soon as any
process exists, kernel code touching MMIO faults. The HPET at 0xfed00000
finds it immediately -- CR2=fed000f0, in intel64_hpet_getreg() under
clock_systime_ticks() on the lpwork thread -- and any MMIO driver would.
Inherit the four boot PDPT entries. They point at the boot page directories
rather than at copies, so anything intel64_map_region() adds later is
inherited too, and they carry no X86_PAGE_USER, so user code still cannot
reach them.
Impact: runtime, CONFIG_ARCH_ADDRENV builds only. User-space access is
unchanged; the entries added are supervisor-only.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
mm_pginitialize() documents heap_start as "the physical address of the start
of memory region", and every x86_64 consumer of mm_pgalloc() agrees:
create_spgtables(), x86_64_get_pgtable() and up_addrenv_create() all put the
result through x86_64_pgvaddr() before touching it. x86_64_pgvaddr() in turn
range-checks against CONFIG_ARCH_PGPOOL_PBASE (arch/x86_64/src/common/
pgalloc.h:67). arm64's equivalent passes CONFIG_ARCH_PGPOOL_PBASE.
up_allocate_pgheap() passed CONFIG_ARCH_PGPOOL_VBASE instead, and in the
other branch X86_64_PGPOOL_BASE + X86_64_LOAD_OFFSET, which is the same
mistake spelled out. Every page handed out was therefore a virtual address
that fell outside the pool's physical window, x86_64_pgvaddr() returned 0,
and the first x86_64_pgwipe() memset NULL.
It presents as a page fault in memset() under create_spgtables() the first
time a process address environment is created, which is loading the init
program. qemu-intel64:knsh_romfs sets PGPOOL_PBASE=0x00c000000 and
PGPOOL_VBASE=0x10c000000, so the value passed was off by the 4GB load
offset.
Impact: runtime, CONFIG_ARCH_ADDRENV builds only (CONFIG_MM_PGALLOC).
Assisted-by: Claude:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
794c325947 ("arch/x64:Syscall support is enabled by default", 2025-05-27)
changed nine guards from CONFIG_LIB_SYSCALL to CONFIG_ARCH_HAVE_SYSCALL but
never added the Kconfig symbol. Only ARCH_HAVE_SYSCALL_HOOKS exists in tree;
ARCH_HAVE_SYSCALL itself is defined nowhere, so it is always unset and since
that commit x86_64 has had no x86_64_syscall_entry(), no x86_64_syscall(), no
IA32_LSTAR/IA32_STAR programming and no syscall stub layer in any
configuration:
arch/x86_64/src/common/Make.defs:37 x86_64_syscall.c not compiled
arch/x86_64/src/common/CMakeLists.txt:41 likewise
arch/x86_64/include/irq.h:86
arch/x86_64/src/intel64/intel64_cpu.c:247, :386
arch/x86_64/src/intel64/intel64_head.S:83, :351, :538
arch/x86_64/src/intel64/intel64_saveusercontext.S:108
qemu-intel64:knsh_romfs and qemu-intel64:knsh_romfs_pci are the two
CONFIG_BUILD_KERNEL configurations in tree, and neither can have worked in
that time. They still link -- nothing references the missing pieces, so
libstubs.a is simply never pulled in -- and then die the first time user code
executes SYSCALL.
Define the symbol with the condition the code had before that commit, which
is LIB_SYSCALL: every protected and every kernel build needs the interface,
and a flat build is left exactly as it is today.
Impact: restores the system call interface for CONFIG_BUILD_KERNEL and
CONFIG_BUILD_PROTECTED on x86_64. CONFIG_BUILD_FLAT is unaffected --
qemu-intel64:nsh still builds with ARCH_HAVE_SYSCALL unset.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
g_x86_64_timer_freq is assigned only under ARCH_INTEL64_TSC_DEADLINE or
ARCH_INTEL64_TSC, and is read only by the two intel64_tsc_*.c files those
options build. With the HPET as the system clock it stays 0, which is
correct and harmless -- but x86_64_timer_calibrate_freq() panics on 0
unconditionally, so the board dies during x86_64_lowsetup().
Require a frequency only where something needs one, which is
ARCH_INTEL64_HAVE_TSC.
The failure mode is worth recording, because it gives nothing to work from:
the PANIC() happens before x86_64_earlyserialinit(), and the panic handler
itself then triple-faults, because _assert() reads up_interrupt_context() --
a %gs-relative load -- and the GS base is not programmed until
x86_64_cpu_priv_set(). The console stays completely empty and the machine
resets.
Impact: runtime, ARCH_INTEL64_HPET_ALARM only. Configurations with a TSC
are unchanged -- the PANIC() is still compiled for them.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
ARCH_INTEL64_HPET_ALARM is one of the three members of the "System Timer
Source" choice, but selecting it does not build. Taking qemu-intel64:nsh on
master and moving the choice off ARCH_INTEL64_TSC_DEADLINE onto it:
intel64/intel64_hpet_alarm.c:41:24: error:
'CONFIG_ARCH_INTEL64_HPET_ALARM_CHAN' undeclared
ARCH_INTEL64_HPET_ALARM_CHAN lives inside "if INTEL64_HPET" and nothing
selects INTEL64_HPET. Enabling that by hand moves the failure to link time,
because intel64_oneshot_lower.c is built only when INTEL64_ONESHOT is set:
undefined reference to `oneshot_initialize'
Enabling INTEL64_ONESHOT as well finally reaches the real problem.
intel64_oneshot_lower.c implements the counter flavour of struct
oneshot_operations_s, which exists only with ONESHOT_COUNT:
intel64_oneshot_lower.c: error: 'const struct oneshot_operations_s' has no
member named 'start_absolute'
intel64_oneshot_lower.c: error: implicit declaration of function
'oneshot_count_init'
intel64_oneshot_lower.c: error: initialization of
'int (*)(struct oneshot_lowerhalf_s *, const struct timespec *)' from
incompatible pointer type ... (four more of these)
ONESHOT, ONESHOT_COUNT and ONESHOT_FAST_DIVISION were selected by
ARCH_INTEL64_TSC_DEADLINE and by nothing else, so the other members of the
same choice could never be built.
Select the four from ARCH_INTEL64_HPET_ALARM as well. INTEL64_ONESHOT
selects INTEL64_HPET in turn, which is what brings
ARCH_INTEL64_HPET_ALARM_CHAN into existence, so one added select closes all
three stages.
Impact: build only, and only for a configuration that could not be built
before. No existing defconfig selects ARCH_INTEL64_HPET_ALARM.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Update the NXDoom configuration to make use of the new PWM audio
support. Now RTTL music is played over the audio jack.
Signed-off-by: Matteo Golin <matteo.golin@gmail.com>
Fix build error where PWM0 pinout selection checks would still be
compiled even when PWM0 was not enabled.
Signed-off-by: Matteo Golin <matteo.golin@gmail.com>
The TRNG driver waited for EHR_VALID and copied the block out without
checking the CryptoCell health-test result, so a sample that failed the
on-chip von-Neumann, CRNGT or autocorrelation test was served as entropy.
Check RNG_ISR before consuming a block: on a health-test error, discard
the block and re-arm the source; only a block that passed is returned.
Add a small startup self-test that draws a few conditioned blocks and, if
the source is stuck (identical blocks), latches /dev/random and /dev/urandom
to fail with -EIO rather than emit predictable output that would silently
weaken every derived key.
Builds on the driver added in 52e84e0c0a.
Signed-off-by: Ricard Rosson <ricard@groundbits.com>
Assisted-by: Claude (Anthropic Claude Code)
Signed-off-by: Ricard Rosson <ricard@groundbits.com>
nxstyle checks one file per invocation. nxstyle_sweep.sh runs it over
the directories given, or the whole repository, and collects what it
reports.
Signed-off-by: raiden00pl <raiden00@railab.me>
Assisted-by: Claude Code
Extract the chip-specific UART constants (controller count, register
bases, NVIC vectors, APBPeriph function/clock masks and crossbar TX/RX
pad-mux codes) out of the shared driver into a new per-chip header,
arch/arm/src/rtl8721dx/ameba_uart_chip.h, and include it from
arch/arm/src/common/ameba/ameba_uart.c. This drops the
#if CONFIG_ARCH_CHIP_RTL8721DX block from the shared source: other Ameba
ARM chips port UART by supplying a same-named header on their chip
include path.
The RCC clock argument is split from a single "clk" into separate
"periph" and "clk" APBPeriph masks so RCC_PeriphClockCmd() gets its two
distinct arguments; the two lists are equal on RTL8721Dx but differ on
chips such as amebasmart.
No functional change: the macros expand to the same values previously
hard-coded in the driver.
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
Add a shared Ameba high-speed UART driver on top of the GPIO driver's
common/ameba/ infrastructure, exposing UART0/UART1 through the NuttX
serial upper half.
- arch/arm/src/common/ameba/ameba_uart.c/.h: serial lower-half driver
built on the SDK fwlib UART register layer (ROM symbol table). RX/TX
dispatch through NuttX-native interrupts; TERMIOS get/set supported.
The pins are muxed to the direction-specific UART crossbar function
codes (TXD/RXD per controller) required by the amebadplus pinmux, and
RX is pulled high through the SDK ROM.
- arch/arm/src/common/ameba/Kconfig: AMEBA_UART option (selects SERIAL
and ARCH_HAVE_SERIAL_TERMIOS) plus RX/TX buffer-size knobs.
- arch/arm/src/rtl8721dx: wire ameba_uart.c into the Make/CMake builds
and pull the fwlib ram_common UART table into the fwlib link set.
- boards/arm/rtl8721dx/pke8721daf: board UART port table registering
UART0 at /dev/ttyS1 (PB18/PB19, 115200), bring-up hook, and a uart
NSH config with the serialrx/serialblaster examples.
- Documentation: describe the driver and the uart board config.
Verified on hardware (PKE8721DAF): pinmux routing, TX/RX and interrupt
paths, and the TERMIOS ioctl path via loopback.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
Bugs fixed:
1. BUILD_FLAT/BUILD_PROTECTED: the interrupt-context self backtrace
printed the same frames twice.
2. BUILD_KERNEL: a cross-tcb backtrace never included the target
task's kernel stack, so frames on it were missing.
Also reworked the implementation around a list of independent
starting points, each carrying every stack range its fp chain may
cross into, splicing them into one backtrace.
Assisted-by: Claude Code:claude-sonnet-5
Signed-off-by: liang.huang <liang.huang@houmo.ai>
When riscv_fault_handler() kills a user task with SIGSEGV, it previously
produced no stack trace, making the crash hard to diagnose. Call
sched_dumpstack() on the killed task when SCHED_BACKTRACE is enabled.
Assisted-by: Claude Code:claude-sonnet-5
Signed-off-by: liang.huang <liang.huang@houmo.ai>
up_idle() is a leaf function; with frame pointers enabled the compiler
skips spilling ra, corrupting the fp chain. Clobber "ra" in the WFI
inline asm so backtrace can walk past the idle frame correctly.
Assisted-by: Claude Code:claude-sonnet-5
Signed-off-by: liang.huang <liang.huang@houmo.ai>
The Pimoroni Pico Plus 2 W is a Pico form-factor board built around the
RP2350B, the 80-pin part with 48 GPIOs, carrying 16MB of flash, 8MB of PSRAM
and a Raspberry Pi RM2 module for 2.4GHz WiFi. The RM2 houses an Infineon
CYW43439, wired to the same pins the Raspberry Pi Pico W uses: GPIO 23 for
power enable, 24 for the shared gSPI data and interrupt line, 25 for chip
select and 29 for the clock.
Three configurations are provided: nsh and usbnsh without the wireless chip,
and wifi, which brings up wlan0 in station mode with WAPI, a DHCP client and
ping. The CYW43439 firmware and CLM blob are linked in from the pico-sdk at
build time, as on the Pico W; CONFIG_CYW43439_FIRMWARE_BIN_PATH selects the
file and the board documentation covers converting it out of the C header that
pico-sdk 2.x ships in place of the binary. rp23xx_firmware.c is placed in the
common source directory so that a future board with the same chip can reuse
it, and unlike rp2040 the blob is staged for the CMake build as well.
Two board details are worth calling out:
- The only LED is wired to GPIO 0 of the CYW43439 rather than to a pin of
the RP2350, so driving it means an iovar request over the gSPI bus. That
works for CONFIG_USERLED but not for CONFIG_ARCH_LEDS, whose
board_autoled_on() is called from interrupt handlers and from assertion
handling, so a build selecting CONFIG_ARCH_LEDS is rejected with an
explicit message. The LED also only responds once wlan0 has been brought
up, because that is when the chip's firmware is downloaded.
- The BOOT button is also wired to GPIO 45, so it can be read as an ordinary
user button once NuttX is running. Its internal pull-up is enabled
deliberately: erratum RP2350-E9 means a floating Bank 0 input on RP2350 A2
leaks enough current to settle around 2.2V, which the internal pull-down
cannot overcome.
Tested on the board with a Raspberry Pi Debug Probe: nsh and wifi boot on
UART0, wlan0 reports the MAC read from the chip, wapi scan lists access
points, and association to a WPA2 network followed by DHCP gives a working
route with ping succeeding to both a literal address and a resolved name.
The LED and the BOOT button were confirmed by hand.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Provide the transport half of the bcmf FullMAC driver on RP2350, so that
boards carrying an Infineon CYW43439 (or the Raspberry Pi RM2 module that
houses one) can bring up a wlan0 interface. The chip's half-duplex gSPI bus
is driven by a six-instruction PIO program with DMA in both directions, and
the driver fills in the gspi_dev_t operations that bcmf_gspi_initialize()
expects.
This is a port of the equivalent rp2040 driver. Three differences in the
RP2350 hardware and its NuttX support had to be accounted for:
- The GPIO_STATUS register no longer has an OEFROMPERI field, so the wait
for the PIO program to release the shared data line watches OETOPAD
instead. No override is configured on that pad, so the two fields carry
the same value.
- rp23xx GPIO interrupt modes are enumerated as indices rather than as the
bitmask rp2040 uses, so passing the rp2040 constant would have selected
the wrong trigger.
- RP23XX_PIO_NUM is three, and the DREQ definitions live in
hardware/rp23xx_dreq.h.
The data and clock lines are also explicitly pulled down rather than left on
the reset default. The data line doubles as the chip's active-high interrupt
request and is serviced with a level-high interrupt, so it must read low
whenever the CYW43439 has released it.
Finally, the state machine returned by rp23xx_pio_claim_unused_sm() is
collected in a signed temporary before being stored, so that the "no state
machine available" test is not defeated by an unsigned comparison.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Add boot commands.rst section describing its syntax and behavior,
including relative image path resolution against the NSH
current working directory, and boot command config.rst dependency-table entry
mapping CONFIG_BOARDCTL_BOOT_IMAGE and CONFIG_NSH_DISABLE_BOOT.
Signed-off-by: Junbo Zheng <zhengjunbo1@xiaomi.com>
nuttx_add_application() encoded SCHED_PRIORITY_DEFAULT as a zero-valued nx_priority linker symbol. A zero priority is invalid for a runnable ELF application task.
Do not emit nx_priority for the symbolic default. When the symbol is absent, the ELF loader retains its scheduler default. Continue emitting nx_priority for explicit numeric priorities.
Companion to apache/nuttx-apps#3667.
Assisted-by: Zed:GPT-5.6 Terra
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
The rp2350 holds 4096 rows of 24 bit one-time-programmable memory, which
the port did not expose at all. This adds a driver on the NuttX efuse
interface, registered by the common board bringup as /dev/efuse.
The driver uses the ECC interpretation of a row, in which 16 bits carry
data and the remaining 8 carry a Hamming code, so the OTP appears as a
flat space of 4096 * 16 bits for the efuse field descriptors to index: a
descriptor at bit offset N refers to bit N % 16 of row N / 16. That
matches the row numbers already listed in hardware/rp23xx_otp_data.h.
Reads come from the chip's ECC-translated window and have no side
effects. Rows are locked in pages of 64; a page locked against reads
would raise a bus fault, so the lock is checked first and reported as an
error instead.
Programming needs the separate RP23XX_OTP_WRITE option, which defaults to
off; without it a write returns EPERM and no programming code is built at
all. When enabled, a row is programmed as a whole through the bootrom,
since the ECC bits cover the whole row. For the same reason a row that
already holds data cannot be modified, and such a write is rejected
rather than left to corrupt the row's ECC.
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
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>
on_hci() ran the host upcall with g_sdc_dev.lock held. On nrf53 this
deadlocks the BLE link: the upcall waits for the app core,
which cannot answer while bt_hci_send() blocks on the same lock.
nrf52 modified for consistency, deadlock is not possible there.
Signed-off-by: raiden00pl <raiden00@railab.me>
Assisted-by: Claude Code
When enabling CONFIG_READLINE_EDIT the CI fails because it reports
there is not left space in this device.
Signed-off-by: Alan C. Assis <acassis@gmail.com>
The rp23xx hardware headers define a register address macro for every
register, then a block of register bit definitions. In three headers a bit
definition reuses the name of a register address macro, so the register
address is silently redefined as a bit mask:
RP23XX_POWMAN_BADPASSWD address 0x40100000 -> (1 << 0)
RP23XX_POWMAN_BOD_CTRL address 0x40100018 -> (1 << 12)
RP23XX_POWMAN_DBG_PWRCFG address 0x401000a4 -> (1 << 0)
RP23XX_BUSCTRL_BUS_PRIORITY_ACK address 0x40068004 -> (1 << 0)
RP23XX_BUSCTRL_PERFCTR_EN address 0x40068008 -> (1 << 0)
RP23XX_PADS_QSPI_VOLTAGE_SELECT address 0x40040000 -> (1 << 0)
None of these headers has an in-tree user yet, which is why this has gone
unnoticed; each clash appears as a "macro redefined" warning as soon as a
driver includes the header. Code that included one of them and used the
register by name would have dereferenced 1 or 0x1000 instead of the register.
Two of the POWMAN clashes were plain duplicates. Per the RP2350 datasheet
BOD_CTRL bit 12 is ISOLATE and DBG_PWRCFG bit 0 is IGNORE, and the correctly
named RP23XX_POWMAN_BOD_CTRL_ISOLATE and RP23XX_POWMAN_DBG_PWRCFG_IGNORE were
already defined with the same values on the following lines, so the bare names
are simply removed. The blank line separating the VREG_LP_EXIT and BOD_CTRL
groups is restored at the same time; its absence is what let the duplicate
hide inside the preceding group.
The other four are single field registers whose field carries no separate name
(the datasheet and the SDK describe each as a one bit register), so their bit
definitions are renamed to <REGISTER>_MASK, following the _MASK spelling these
headers already use for a field extent, and written in hex like their peers.
The rp23xx-rv copies of the three headers are identical to the arm ones and
carry the same clashes, so they get the same change and stay in sync.
No functional change: none of the six names has any user in the tree.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Add a reference section for the NSH `du` command, covering the -h,
-s, -a, and -d N options, default-to-current-directory behavior,
and an example showing recursive directory output.
Options are rendered as an RST simple table to match the style of
other NSH command sections (ls, umount, uptime). Sizes are noted as
apparent sizes (st_size) and -h as integer-arithmetic, one-decimal
output that needs no float printf support.
Signed-off-by: Junbo Zheng <zhengjunbo1@xiaomi.com>
Add DMA support for DAC output with configurable double-buffering
via ioctl interface:
- ANIOC_DAC_DMABUFF_INIT: Copy full buffer into DMA buffer (memcpy)
- ANIOC_DAC_DMA_START: Start DMA with optional half-transfer interrupts
- ANIOC_DAC_DMA_STOP: Stop DMA and timer
- ANIOC_DAC_DMA_GET_EVENT: Wait for half-transfer complete event
- ANIOC_DAC_DMA_WRITE_HBUF: Write half-buffer into DMA buffer
- ANIOC_DAC_INFO: Query DAC capabilities (resolution, DMA, buffer size)
Stream mode: when halfint=1, both HTIF and TCIF generate events
via a ring buffer and semaphore. User writes the completed half
while DMA fills the other half. TCIF indicates h=1, HTIF h=0.
DMA priority is configurable per-channel via Kconfig choice
(Low/Medium/High/VeryHigh), defaulting to Medium.
Signed-off-by: Andrey Sobol <andrey.sobol.nn@gmail.com>
Expose the bundled LAME and libmad headers to the sim:alsa arch target and include LAME through its installed public header name. This lets the CMake build compile sim_offload.c without relying on host codec development packages.
Assisted-by: Zed:GPT-5.6 Terra
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
adc_shutdown() gates the ADC clock (RCU_APB2EN.ADCEN) when the device is
closed, but the one-shot adc_reset() that first enabled it only runs at
registration and adc_setup() never re-enabled it. A second open() then drove
a clock-gated peripheral whose conversions never completed, so a second run of
a reader such as the adc example hung after opening the device. adc_setup()
now re-enables the ADC clock; clock gating preserves the register
configuration, so nothing else has to be re-programmed.
Add an "adc" configuration that exercises the driver. It is the nsh base plus
the ADC driver, registered as /dev/adc0 and read by the adc example. ADC
channel 8 (ADC_IN8) is routed to PB0 on the J1 header so an analog voltage
applied there is sampled. The board bringup samples that channel when the pin
is routed, and PB0 is only claimed for the ADC when SPI is off (with SPI on it
belongs to the I2C0 fallback), so the periph configuration is unaffected.
The GD32VW55x ADC converts on demand rather than continuously, so the example
uses the software trigger (CONFIG_EXAMPLES_ADC_SWTRIG) and is bounded to 20
sample groups so it returns to the prompt.
Signed-off-by: Jorge Guzman <jorge.gzm@gmail.com>
Add an "sdcard" configuration that mounts an SD card over SPI0 with a FAT
filesystem. The board provides the SPI chip-select glue (gd32_spi0select,
gd32_spi0status and gd32_spi0register in a new gd32_spi.c) and gd32_bringup()
binds the slot with mmcsd_spislotinitialize() and mounts /dev/mmcsd0 on
/mnt/sd.
The card is wired to the J1 header: SCK PA2, MISO PA1, MOSI PA0, and a
software chip select on PA4. CONFIG_MMCSD_MMCSUPPORT is left off (its MMC
CMD1 probe upsets SD cards).
Signed-off-by: Jorge Guzman <jorge.gzm@gmail.com>
Add a "pwm" configuration that exercises the PWM driver on TIMER1. It is the
nsh base plus the PWM driver, registered as /dev/pwm0 and driven by the pwm
example (100 Hz, 50 % duty by default).
TIMER1 channel 0 is routed to PA0 on the J1 header (AF1) so the waveform can
be probed there; the other channels stay unrouted.
Signed-off-by: Jorge Guzman <jorge.gzm@gmail.com>
The GD32VW55x I2C master (the STM32-style "v2" IP) never completed a real
transfer. Two bugs:
1. Wrong kernel clock. The protocol state machine is clocked by the I2C
kernel clock selected in RCU_CFG1.I2C0SEL, not by the APB1 bus clock that
only feeds the register interface. The driver left it at the APB1 default
and computed TIMING for PCLK1 (~80 MHz); the resulting prescaled period is
so short that the SDADEL/SCLDEL setup and hold times fall below the
analog-filter minimum of the IP, so the master latches START but never
drives SCL (STAT stuck with BUSY set). Route I2C0 to IRC16M (16 MHz) and
use it as clk_freq, and never let the prescaler drop below the value that
keeps the prescaled clock at/under 4 MHz (250 ns) so SDADEL/SCLDEL stay in
spec. This matches the vendor BSP (IRC16M, PSC=3).
2. Transfer timeout was zero. CONFIG_GD32VW55X_I2C_TIMEOTICKS has a Kconfig
default of 0 ("override when non-zero"), but the driver derived the timeout
with a plain #ifndef, which never triggers because the symbol is always
defined. The polled wait loop therefore ran a single iteration and gave
up. Address probes (NACK on the first pass) still worked and masked it;
only multi-byte transfers exercised the loop. Honour the "0 means derive
from seconds/milliseconds" contract.
Also make the interrupt wait immune to the ISR completing between startmsg()
and the wait (do not clobber a posted DONE), and drop a redundant cast.
To exercise this on hardware, add an "sht3x" configuration to the
gd32vw553k-start: the nsh base plus I2C0, the i2ctool and the Sensirion SHT3x
temperature/humidity driver, registered as /dev/i2c0 and /dev/temp0. I2C0 is
routed to PA2 (SCL) / PA3 (SDA) on AF4, the pins broken out on the J1 header
(datasheet Table 2-5); when SPI is enabled it claims PA2, so I2C0 falls back
to PB0/PB1, whose SDA pin is not broken out (the periph case).
Signed-off-by: Jorge Guzman <jorge.gzm@gmail.com>
The RP2350 has no dedicated RTC block (the RP2040 one was removed). Use the
POWMAN always-on timer instead: a 64-bit millisecond counter clocked from the
low-power oscillator, so it keeps running across warm resets.
Enabling CONFIG_RP23XX_RTC selects CONFIG_RTC and builds the driver, which
implements the simple up_rtc_initialize()/up_rtc_time()/up_rtc_settime()
interface backing the system clock (seconds resolution). up_rtc_initialize()
sources the timer from the low-power oscillator at a 1 kHz tick and starts it,
preserving the value when the timer is already running. POWMAN register writes
carry the required 0x5afe password.
Document the RTC on the rp23xx platform page: an "RTC" section explaining how
the POWMAN always-on timer is used (LPOSC clocking, the 0x5afe password and the
four 16-bit time registers, stopping the counter to reload it), with reference
links to the RP2350 datasheet Power chapter and the pico-sdk hardware_powman /
pico_aon_timer implementation the driver mirrors. The same references are
noted in the driver header.
Assisted-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Adds a driver for the external QSPI PSRAM hanging off QMI chip select 1,
such as the 8 MiB APS6404 fitted on the Pimoroni Pico Plus 2.
rp23xx_psramconfig() assigns the CS1 pin, reads the device ID over the QMI
direct interface to confirm an APS6404-family part (KGD 0x5D), resets it
into quad mode and programs the QMI M1 timing/read/write formats so the
region at 0x11000000 becomes directly addressable and writable. Because
driving the QMI in direct mode stalls execute-in-place from the flash, the
detection and (re)configuration code runs from RAM (.time_critical) with
interrupts disabled; the command bytes are selected with immediates rather
than a .rodata table for the same reason. The register values follow the
Raspberry Pi Pico SDK setup_psram().
The detection routine only keeps the QMI DIRECT_CSR synchronization that is
strictly necessary. Each candidate busy-wait was removed one at a time and
re-verified on hardware: the post-enable "cooldown" waits, the READ_ID
TXEMPTY wait (redundant with the BUSY wait after it), and a fixed nop delay
proved unnecessary and are omitted. The three BUSY waits that remain -- after
the quad-mode nudge, after each READ_ID byte, and after each reset/quad-enable
command -- are required and carry a comment explaining that the frame must
finish shifting before the chip select is deasserted, and what breaks
otherwise (garbage ID reads, or the shared QMI bus wedging).
rp23xx_psram_restore() re-applies the M1 configuration and is meant to be
called from the flash write path, which goes through the bootrom and
reconfigures the shared QMI for chip select 0.
rp23xx_heaps.c is wired into the build and now uses the detected size, so
the PSRAM is exposed to the memory manager (added to the main heap, used as
a separate heap, or as the user heap) and is skipped cleanly when no PSRAM
is present.
Enabled by default on the pimoroni-pico-2-plus:nsh configuration, where it
adds the 8 MiB to the main heap. A documentation page for the Pimoroni Pico
Plus 2 is added alongside the other rp23xx boards, covering its serial
console, LED, the external PSRAM and how it is exposed to the heap, the
supported capabilities and the available configurations, with a photo of the
board.
Tested on Pimoroni Pico Plus 2 hardware: detection reports the 8 MiB
APS6404, the region is read/write across its whole range (ramtest word,
half-word and byte passes, marching/pattern/address-in-address), and the
heap reports the extra 8 MiB.
Assisted-by: Claude Code:claude-opus-4-8
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
The port could only run with a periodic ARM SysTick tick. Add an alarm/
oneshot lower-half backed by an RP2350 system timer block so the scheduler
can run tickless, waking the CPU only when a timer actually expires.
rp23xx_oneshot.c implements the ONESHOT_COUNT lower-half (mirroring the
RISC-V mtimer driver). A timer block is a free-running 64-bit microsecond
counter (clocked by the TICKS block, independent of the SysTick), which serves
directly as the monotonic time base returned by current(), so timekeeping is
exact to 1 us. The one adaptation versus a full 64-bit compare timer is that
the RP2350 ALARM registers match only the low 32 bits of the counter:
max_delay() is therefore capped below 2^32 counts (~71.5 minutes) so the
scheduler never asks for a longer interval, and any deadline that is already
due -- or that the counter reaches while the alarm is being armed -- is
raised immediately through the INTF force register instead of waiting a full
32-bit wrap for the compare to match again.
Enabled with CONFIG_RP23XX_SYSTIMER_TICKLESS (mutually exclusive with
RP23XX_SYSTIMER_SYSTICK), which selects ONESHOT, ONESHOT_COUNT and
ALARM_ARCH; up_timer_initialize() then hands the oneshot to
up_alarm_set_lowerhalf(). ARCH_CHIP_RP23XX now selects ARCH_HAVE_TICKLESS.
The block is selectable with CONFIG_RP23XX_SYSTIMER_TICKLESS_TIMER0 (default)
or _TIMER1; the chosen block is claimed exclusively by the scheduler and is
excluded from the /dev/timer driver (CONFIG_RP23XX_TIMER) in Kconfig, so the
tickless clock and a /dev/timer device can coexist on different blocks.
Tested on Pimoroni Pico Plus 2 (RP2350B) hardware with CONFIG_SCHED_TICKLESS
and CONFIG_SCHED_TICKLESS_ALARM: the image boots to nsh and keeps accurate
time -- "uptime" advances at real-time rate (17 s over a measured 17.4 s) and
"sleep 4" blocks for 4.25 s of wall time -- confirming the oneshot both drives
the scheduler and provides a correct 1 MHz monotonic clock.
Assisted-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>