Skip to content

Gd32vw553k examples and fixes (i2c, pwm, sdcard, adc).#19524

Merged
cederom merged 4 commits into
apache:masterfrom
JorgeGzm:gd32vw553k-start-examples-and-fixes
Jul 26, 2026
Merged

Gd32vw553k examples and fixes (i2c, pwm, sdcard, adc).#19524
cederom merged 4 commits into
apache:masterfrom
JorgeGzm:gd32vw553k-start-examples-and-fixes

Conversation

@JorgeGzm

Copy link
Copy Markdown
Contributor

Summary

Fixes two GD32VW55x driver bugs and adds four gd32vw553k-start examples on
top of the nsh base.

Driver fixes

  • gd32vw55x_i2c.c: the I2C master never completed a transfer. It is clocked
    by the kernel clock in RCU_CFG1.I2C0SEL, not APB1; the driver left it at
    the APB1 default, so the computed TIMING put SDADEL/SCLDEL below the IP
    analog-filter minimum and SCL was never driven. Now routes I2C0 to IRC16M
    and floors the prescaler (matching the vendor BSP). Also honours the
    CONFIG_GD32VW55X_I2C_TIMEOTICKS=0 "derive from time" contract (the
    #ifndef never fired, so the timeout was 0) and hardens the ISR wait.
  • gd32vw55x_adc.c: adc_shutdown() gates the ADC clock on close, but
    adc_setup() never re-enabled it (only the one-shot adc_reset() did), so
    a second open() hung. adc_setup() now re-enables the clock.

New configurations

config what pins (J1)
sht3x I2C0 + i2ctool + SHT3x (/dev/i2c0, /dev/temp0) SCL PA2, SDA PA3 (AF4)
pwm PWM on TIMER1 (/dev/pwm0) PA0 (AF1)
sdcard SD card on SPI0 + FAT, auto-mounted /mnt/sd SCK PA2, MISO PA1, MOSI PA0, CS PA4
adc ADC (/dev/adc0) + adc example PB0 = ADC_IN8

Pin routing is in board.h, device registration in gd32_bringup.c, each
example is a standalone defconfig, and the board index.rst documents all
four.

Commits (4) -- each driver fix is folded into the example that exercises it:

  1. fix I2C master and add gd32vw553k-start sht3x example -- fixes the I2C
    clock/timeout bugs and adds the sht3x config.
  2. add pwm example to gd32vw553k-start -- adds the pwm config (TIMER1 on
    PA0).
  3. add sdcard (SPI/FAT) example to gd32vw553k-start -- adds the sdcard
    config with the SPI chip-select glue and FAT auto-mount.
  4. fix ADC reopen and add gd32vw553k-start adc example -- fixes the ADC
    clock re-enable on open and adds the adc config.

Impact

  • New feature: four opt-in board configs. Also two driver bug fixes.
  • Build/API/compat: no new default built, no Kconfig or public API change,
    backward compatible.
  • Hardware (positive): I2C now works and the ADC can be reopened on all boards
    of the arch. Only periph enables these peripherals; nsh, wapi,
    sta_softap, ble, ostest, littlefs are unaffected (every change is
    preprocessed out for them).
  • Docs: index.rst gains sht3x, pwm, sdcard, adc sections.

Testing

Verified on real hardware: gd32vw553k-start (GD32VW553KMQ, Nuclei N307),
riscv-none-elf-gcc 14.2.0, flashed over GD-Link/OpenOCD. All four configs
build clean; nxstyle/checkpatch clean on every touched file.

Before the I2C fix (gd32vw553k-start:sht3x): every transfer times out,
the master is stuck with BUSY set and never drives SCL:

nsh> i2c dev 0x03 0x77
gd32_i2c_transfer: ERROR: Timed out: STAT=0x00008001
... (repeats for every address; no device detected)

After the change:

sht3x -- SHT3x on I2C0 (SCL PA2, SDA PA3):

nsh> i2c dev -z 0x03 0x77
40: -- -- -- -- 44 -- -- -- -- -- -- -- -- -- -- --   # SHT3x at 0x44
nsh> sht3x
Temperature = 26.530098
Humidity    = 47.998001

(The default one-byte-read probe is NACKed by the SHT3x when no measurement is
pending, so -z is used to detect it.)

pwm -- scope/LED on PA0:

nsh> pwm
pwm_main: starting output with frequency: 100 channel: 1 duty: 00007fff
pwm_main: stopping output

sdcard -- microSD-over-SPI breakout on SPI0:

nsh> ls /dev/
/dev:
 console
 mmcsd0
 null
 ttyS0
 zero
nsh> mount
  /mnt/sd type vfat
nsh> echo "GD32 on NuttX" > /mnt/sd/hello.txt
nsh> cat /mnt/sd/hello.txt
GD32 on NuttX

The card is auto-mounted on /mnt/sd and writes persist across a reboot. The
breakout must be powered from 5 V (its 3.3 V regulator needs the headroom for
the card's power-up current bursts, otherwise it hangs in the ACMD41 loop).

adc -- ADC_IN8 on PB0, with 1.65 V (half of the 3.3 V full scale) applied:

nsh> adc
adc_main: g_adcstate.count: 20
adc_main: Hardware initialized. Opening the ADC device: /dev/adc0
Sample:
1: channel: 8 value: 2108
Sample:
1: channel: 8 value: 2115
Sample:
1: channel: 8 value: 2112
... (20 groups)

1.65 V lands at mid-scale (~2048); ~2110 is within the tolerance of an
uncalibrated ADC.

@github-actions github-actions Bot added Area: Documentation Improvements or additions to documentation Arch: risc-v Issues related to the RISC-V (32-bit or 64-bit) architecture Size: L The size of the change in this PR is large Board: risc-v labels Jul 24, 2026
@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

@JorgeGzm
JorgeGzm force-pushed the gd32vw553k-start-examples-and-fixes branch from 6ac8149 to 0a1fe13 Compare July 24, 2026 23:02
acassis
acassis previously approved these changes Jul 24, 2026
@JorgeGzm
JorgeGzm force-pushed the gd32vw553k-start-examples-and-fixes branch from 0a1fe13 to f40c364 Compare July 25, 2026 00:13
@github-actions github-actions Bot added Arch: arm Issues related to ARM (32-bit) architecture Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces. Board: arm Board: simulator and removed Size: L The size of the change in this PR is large labels Jul 25, 2026

@cederom cederom left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you @JorgeGzm great work and perfect reporting / documenting :-)

@cederom cederom changed the title Gd32vw553k start examples and fixes Gd32vw553k examples and fixes (i2c, pwm, sdcard, adc). Jul 25, 2026
@cederom

cederom commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Note: next time please put changes like "arch/arm: Reserve r10 via ARCHCFLAGS and hoist the PIC module flags." into a separate PR as it impacts many ARM devices and is out of scope of GD32 update :-)

@acassis acassis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@JorgeGzm please analyze the impact of changing other architectures. Ideally a PR for a specific arch shouldn't modify all others like here, could be some AI issue. Double check

Comment thread arch/arm/src/common/Toolchain.defs
@cederom

cederom commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Would it be a lot of work to move out ARM R10 changes into a separate PR @JorgeGzm ?

@acassis

acassis commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Would it be a lot of work to move out ARM R10 changes into a separate PR @JorgeGzm ?

@cederom it seems like a BUG, it didn't come from his PR, probably it happened during some rebase

@cederom cederom left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please move out "arch/arm: Reserve r10 via ARCHCFLAGS and hoist the PIC module flags." commit into a separate PR @JorgeGzm :-)

JorgeGzm added 4 commits July 25, 2026 17:41
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>
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>
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>
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>
@JorgeGzm
JorgeGzm force-pushed the gd32vw553k-start-examples-and-fixes branch from f40c364 to bc0b7d8 Compare July 25, 2026 20:46
@github-actions github-actions Bot added Size: L The size of the change in this PR is large and removed Arch: arm Issues related to ARM (32-bit) architecture Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces. Board: arm Board: simulator labels Jul 25, 2026

@cederom cederom left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for the updates @JorgeGzm great job! :-)

@cederom
cederom merged commit 5ecdf31 into apache:master Jul 26, 2026
31 checks passed
@JorgeGzm
JorgeGzm deleted the gd32vw553k-start-examples-and-fixes branch July 26, 2026 12:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: risc-v Issues related to the RISC-V (32-bit or 64-bit) architecture Area: Documentation Improvements or additions to documentation Board: risc-v Size: L The size of the change in this PR is large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants