JorgeGzm opened a new pull request, #20998:
URL: https://github.com/apache/nuttx/pull/20998
## Summary
This PR improves the GD32VW55x port (RISC-V Nuclei N307, board
GD32VW553K-START). It is the companion of apache/nuttx#20997, which brings
the same DMA, power management and RTC work to the GD32W51x port
(Cortex-M33, board GD-xD-W515-EVAL). The two GigaDevice Wi-Fi SoCs have
different cores but the same generation of peripherals: their USART, SPI,
DMA, RTC, RCU and PMU blocks are the same IP, so these features are
implemented the same way in both ports.
**Commits:**
1. **SPI DMA fix.** The SPI driver enabled every DMA channel interrupt,
and its callback wakes the waiter on any of them.
- The half transfer interrupt ended the exchange while its second half
was still on the wire.
- The single data mode exception, raised when a receive request waits
for the bus, ended it at a random point. It does not stop the
transfer (user manual 10.5.2).
- The SPI driver now enables only the full transfer and access error
interrupts. The DMA driver clears the exception flags and calls back
only along with another event.
- The case labels of the SPI mode switch are also indented as nxstyle
expects (no functional change).
2. **Clock.**
- The clock tree is set up as the firmware library V1.6.0 does: when
the system still runs from the PLL, as after a bootloader, the AHB
clock is lowered in steps before going back to the IRC16M.
- The setup waits 1 ms for the 40 MHz crystal before starting the PLL.
The HXTAL stable flag never sets on this chip, and the firmware
library does not wait. The PLL locked to the starting crystal runs
about 12 % slow for about 0.5 ms, which matters on every deep-sleep
wake-up.
3. **RTC.** At boot, the IRC32K is measured against the system clock,
which comes from the crystal, over about 100 ms. The synchronous
prescaler of the RTC is then set from that frequency. On this board the
IRC32K runs at about 35.2 kHz (+10 %), and before this change the
calendar gained 17 s in 3 minutes.
4. **UART DMA.** `CONFIG_<port>_RXDMA` and `CONFIG_<port>_TXDMA` move the
UART data through the DMA, for reception, transmission or both.
- Reception: the DMA writes to a circular buffer. Its contents are
handed to the serial driver on the idle line interrupt and on the half
and full transfer interrupts.
- Transmission: each contiguous part of the transmit buffer is sent
with one DMA transfer. The full transfer interrupt frees the space and
starts the next transfer.
- The console starts its DMA from `riscv_serialinit()`, since it is not
set up again when it is opened.
5. **Power management.** With `CONFIG_PM`, the `PM_STANDBY` state of the
IDLE domain is the PMU deep-sleep mode. It is entered from a custom
`up_idle()` (`ARCH_IDLE_CUSTOM`), with `WFI` and the SLEEPVALUE CSR set.
- The RTC wake-up timer (EXTI line 21) ends the deep-sleep at the next
alarm of the system timer, at most `CONFIG_GD32VW55X_PM_WAKEUP_MS`
later, so the timers keep their time.
- The system timer (mtime) stops in deep-sleep. On wake-up it is
advanced by the time spent asleep, measured on the RTC calendar.
- The calendar is read from its counters (BPSHAD), not from the shadow
registers, which are not updated in deep-sleep. Both readings are
taken at the start of a sub-second unit: the wake-up comes at a fixed
point of a unit, so a reading anywhere in a unit would bias every
sleep.
- The asynchronous prescaler of the RTC is lowered from 32 to 2, for
sub-second units of about 60 us.
- The debugger connection is kept in deep-sleep (`DBG_CTL0.DSLP_HOLD`).
- Received characters are reported as PM activity.
- New `pm` configuration.
## Impact
- New Kconfig options, all off by default:
- PM support: `GD32VW55X_PM_WAKEUP_MS`, `GD32VW55X_PM_SERIAL_ACTIVITY`;
- `CONFIG_<port>_RXDMA` and `CONFIG_<port>_TXDMA`, with
`GD32VW55X_SERIAL_RXDMA_BUFFER_SIZE`.
- New configuration: `gd32vw553k-start:pm`.
- Default behaviour changes, on all configurations:
- the IRC32K is calibrated at every boot, which takes about 100 ms;
- the clock setup waits 1 ms for the crystal;
- the RTC asynchronous prescaler is 2 instead of 32 (the calendar still
runs at 1 Hz);
- the DMA driver no longer calls back on a single data mode or FIFO
exception alone;
- the chip selects `ARCH_IDLE_CUSTOM`. Without `CONFIG_PM`, its
`up_idle()` waits for an interrupt as the common one does.
- Things to know when enabling the new options:
- The activity governor needs the periodic tick: with
`CONFIG_SCHED_TICKLESS` it never leaves `PM_NORMAL`.
- A character received while the chip sleeps is lost, since the UART is
not clocked; the following ones keep the chip awake.
- The debug module does not answer while the core is in deep-sleep. To
program a sleeping board, keep it awake from the console or press
RESET just before (documented).
- The radios are not supported in deep-sleep (documented).
- Only `arch/risc-v/src/gd32vw55x`, `arch/risc-v/Kconfig`, the board and
its documentation change.
## Testing
Host: Ubuntu 24.04 (Linux x86_64), xPack RISC-V GCC 14.2.0. Board:
GD32VW553K-START (GD32VW553KMQ7).
**Build:**
- every commit builds `gd32vw553k-start:nsh`;
- the head builds the 12 configurations of the board without warnings:
`nsh`, `ostest`, `periph`, `pwm`, `adc`, `littlefs`, `sdcard`, `sht3x`,
`wapi`, `sta_softap`, `ble` and `pm`;
- `tools/checkpatch.sh -c -u -m -g` passes.
**SPI DMA:** MOSI wired to MISO (PA0-PA1), 50 exchanges of 24 bytes with
`spi exch`. All 50 return the sent data; before this change, 9 of 50 did,
and the others missed the end of the data.
**Clock:** direct boot, `sleep 10` lasts 10.05 s on the host.
**RTC:** with the asynchronous prescaler of 32 of that commit, the
synchronous prescaler is 1100 instead of 1000. After 180 s and a reboot,
the calendar is within the 1 s resolution of the host.
**UART DMA** (console on UART2, with Rx and Tx DMA):
- A 4 KiB burst at 115200 baud arrives intact.
- 2 KiB sent to the board are read back unchanged.
- Larger bursts from the host make the virtual COM port of the on-board
GD-Link drop off the USB bus, with or without the DMA.
**Power management** (`pm` configuration, NSH left idle):
```
nsh> cat /proc/pm/state0
DOMAIN0 WAKE SLEEP TOTAL
normal 18s 10% 9s 5% 27s 15%
idle 9s 5% 0s 0% 9s 5%
standby 134s 78% 0s 0% 134s 78%
```
- NSH answers within 0.2 s.
- `sleep 3` takes 3.00 s on the host (±8 ms), while the chip sleeps
between ticks.
- System clock against the host: -0.074 s after 125 s of standby. Before
the crystal wait it was -0.93 s. The remaining error is the IRC32K,
since the board has no 32.768 kHz crystal.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]