diff --git a/Documentation/platforms/risc-v/gd32vw55x/boards/gd32vw553k-start/index.rst b/Documentation/platforms/risc-v/gd32vw55x/boards/gd32vw553k-start/index.rst index 1b933fde525..f21730c4027 100644 --- a/Documentation/platforms/risc-v/gd32vw55x/boards/gd32vw553k-start/index.rst +++ b/Documentation/platforms/risc-v/gd32vw55x/boards/gd32vw553k-start/index.rst @@ -256,6 +256,50 @@ duty (100 Hz, 50 % by default):: duration for a single run. Put an LED (with a series resistor) or a scope on PA0 to see it. +sdcard +------ + +NSH plus an SD card on SPI0 with a FAT filesystem. The card is registered as +``/dev/mmcsd0`` and ``gd32_bringup()`` mounts it on ``/mnt/sd``. + +Wire the card (or a microSD-over-SPI breakout) to the J1 header: + +======== ========== +Signal Pin +======== ========== +SCK PA2 +MISO PA1 +MOSI PA0 +CS PA4 +======== ========== + +.. note:: + Power the breakout from **5 V**, not 3.3 V. These breakouts carry their + own 3.3 V regulator, and the SD card draws current bursts while it powers + up; feeding 3.3 V directly leaves the card stuck in the ACMD41 init loop + (it answers CMD0/CMD8 but never leaves the idle state). A decoupling + capacitor close to the card and short leads help too. + +The SPI runs its initialisation at ~625 kHz (PCLK2 / 256), slightly above the +400 kHz of the SD spec, which the vast majority of cards tolerate. + +The block device shows up as ``/dev/mmcsd0`` and the bringup already mounts it +on ``/mnt/sd``, so no manual ``mount`` is needed:: + + 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 + nsh> ls -l /mnt/sd + littlefs -------- diff --git a/boards/risc-v/gd32vw55x/gd32vw553k-start/configs/sdcard/defconfig b/boards/risc-v/gd32vw55x/gd32vw553k-start/configs/sdcard/defconfig new file mode 100644 index 00000000000..c67a13b06b8 --- /dev/null +++ b/boards/risc-v/gd32vw55x/gd32vw553k-start/configs/sdcard/defconfig @@ -0,0 +1,55 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_LEDS is not set +# CONFIG_MMCSD_MMCSUPPORT is not set +CONFIG_ARCH="risc-v" +CONFIG_ARCH_BOARD="gd32vw553k-start" +CONFIG_ARCH_BOARD_GD32VW553K_START=y +CONFIG_ARCH_CHIP="gd32vw55x" +CONFIG_ARCH_CHIP_GD32VW553KM=y +CONFIG_ARCH_CHIP_GD32VW55X=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_RISCV=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_LOOPSPERMSEC=16000 +CONFIG_BUILTIN=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_FS_FAT=y +CONFIG_FS_PROCFS=y +CONFIG_GD32VW55X_SPI=y +CONFIG_GD32VW55X_UART2=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=3072 +CONFIG_INTELHEX_BINARY=y +CONFIG_LIBC_PERROR_STDOUT=y +CONFIG_LIBC_STRERROR=y +CONFIG_MMCSD=y +CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6 +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=64 +CONFIG_NSH_READLINE=y +CONFIG_NSH_STRERROR=y +CONFIG_RAM_SIZE=294400 +CONFIG_RAM_START=0x20000200 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_STACK_COLORATION=y +CONFIG_START_DAY=13 +CONFIG_START_MONTH=7 +CONFIG_START_YEAR=2026 +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=12 +CONFIG_UART2_RXBUFSIZE=128 +CONFIG_UART2_SERIAL_CONSOLE=y +CONFIG_UART2_TXBUFSIZE=128 diff --git a/boards/risc-v/gd32vw55x/gd32vw553k-start/include/board.h b/boards/risc-v/gd32vw55x/gd32vw553k-start/include/board.h index da55b089268..9f0be66d09c 100644 --- a/boards/risc-v/gd32vw55x/gd32vw553k-start/include/board.h +++ b/boards/risc-v/gd32vw55x/gd32vw553k-start/include/board.h @@ -71,6 +71,15 @@ # define GPIO_SPI_SCK GPIO_SPI_SCK_1 /* PA2, AF5 */ # define GPIO_SPI_MISO GPIO_SPI_MISO_1 /* PA1, AF5 */ # define GPIO_SPI_MOSI GPIO_SPI_MOSI_1 /* PA0, AF5 */ + +/* SPI0 chip select for the SD card: a plain GPIO output on PA4 (J1), + * driven by gd32_spi0select(). Active low, idles high. + */ + +# define GPIO_SPI0_CSPIN (GPIO_CFG_MODE_OUTPUT | GPIO_CFG_PUPD_NONE | \ + GPIO_CFG_PP | GPIO_CFG_SPEED_MAX | \ + GPIO_CFG_OUTPUT_SET | GPIO_CFG_PORT_A | \ + GPIO_CFG_PIN_4) #endif /* I2C0 uses PA2 (SCL) / PA3 (SDA) on AF4, the pins broken out on the J1 diff --git a/boards/risc-v/gd32vw55x/gd32vw553k-start/src/Makefile b/boards/risc-v/gd32vw55x/gd32vw553k-start/src/Makefile index 5c24706c83c..7c2b813abe9 100644 --- a/boards/risc-v/gd32vw55x/gd32vw553k-start/src/Makefile +++ b/boards/risc-v/gd32vw55x/gd32vw553k-start/src/Makefile @@ -38,4 +38,8 @@ ifeq ($(CONFIG_BOARDCTL_RESET),y) CSRCS += gd32_reset.c endif +ifeq ($(CONFIG_GD32VW55X_SPI),y) +CSRCS += gd32_spi.c +endif + include $(TOPDIR)/boards/Board.mk diff --git a/boards/risc-v/gd32vw55x/gd32vw553k-start/src/gd32_bringup.c b/boards/risc-v/gd32vw55x/gd32vw553k-start/src/gd32_bringup.c index 939e36e8c74..6426b0028cf 100644 --- a/boards/risc-v/gd32vw55x/gd32vw553k-start/src/gd32_bringup.c +++ b/boards/risc-v/gd32vw55x/gd32vw553k-start/src/gd32_bringup.c @@ -37,6 +37,9 @@ #ifdef CONFIG_SPI_DRIVER # include #endif +#ifdef CONFIG_MMCSD_SPI +# include +#endif #ifdef CONFIG_GD32VW55X_ADC # include #endif @@ -171,19 +174,47 @@ int gd32_bringup(void) #endif #ifdef CONFIG_GD32VW55X_SPI - /* The family has a single SPI instance: bus 0 */ + /* The family has a single SPI instance: bus 0. Configure the chip select + * GPIOs first, then bring the bus up. + */ + + gd32_spidev_initialize(); spi = gd32_spibus_initialize(0); if (spi == NULL) { ferr("ERROR: failed to initialize SPI0\n"); } -#ifdef CONFIG_SPI_DRIVER - else if (spi_register(spi, 0) < 0) + else { - ferr("ERROR: failed to register /dev/spi0\n"); - } +#ifdef CONFIG_SPI_DRIVER + if (spi_register(spi, 0) < 0) + { + ferr("ERROR: failed to register /dev/spi0\n"); + } #endif + +#ifdef CONFIG_MMCSD_SPI + /* Bind SPI0 to the MMC/SD SPI slot (/dev/mmcsd0) and mount it as FAT. + * The SD card is wired to SPI0 (SCK PA2, MISO PA1, MOSI PA0) with the + * chip select on PA4 -- all on the J1 header. + */ + + ret = mmcsd_spislotinitialize(0, 0, spi); + if (ret < 0) + { + ferr("ERROR: failed to bind SPI0 to the MMC/SD slot: %d\n", ret); + } + else + { + ret = nx_mount("/dev/mmcsd0", "/mnt/sd", "vfat", 0, NULL); + if (ret < 0) + { + ferr("ERROR: failed to mount /mnt/sd: %d\n", ret); + } + } +#endif + } #endif #ifdef CONFIG_GD32VW55X_ADC diff --git a/boards/risc-v/gd32vw55x/gd32vw553k-start/src/gd32_spi.c b/boards/risc-v/gd32vw55x/gd32vw553k-start/src/gd32_spi.c new file mode 100644 index 00000000000..2f6cd3a8448 --- /dev/null +++ b/boards/risc-v/gd32vw55x/gd32vw553k-start/src/gd32_spi.c @@ -0,0 +1,113 @@ +/**************************************************************************** + * boards/risc-v/gd32vw55x/gd32vw553k-start/src/gd32_spi.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#include + +#include "gd32vw55x_gpio.h" +#include "gd32vw553k-start.h" + +#ifdef CONFIG_GD32VW55X_SPI + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: gd32_spidev_initialize + * + * Description: + * Configure the SPI chip select GPIO(s). The bus itself is brought up by + * gd32_spibus_initialize(). + * + ****************************************************************************/ + +void gd32_spidev_initialize(void) +{ + /* The SD card chip select on SPI0, idle (de-asserted, high) */ + + gd32_gpio_config(GPIO_SPI0_CSPIN); + gd32_gpio_write(GPIO_SPI0_CSPIN, true); +} + +/**************************************************************************** + * Name: gd32_spi0select and gd32_spi0status + * + * Description: + * The board-specific select and status methods of the SPI interface (see + * include/nuttx/spi/spi.h). Chip select is active low. + * + ****************************************************************************/ + +void gd32_spi0select(struct spi_dev_s *dev, uint32_t devid, bool selected) +{ + spiinfo("devid: %" PRIu32 " CS: %s\n", devid, + selected ? "assert" : "de-assert"); + + gd32_gpio_write(GPIO_SPI0_CSPIN, !selected); +} + +uint8_t gd32_spi0status(struct spi_dev_s *dev, uint32_t devid) +{ + uint8_t status = 0; + + if (devid == SPIDEV_MMCSD(0)) + { + /* There is no card-detect line wired, so assume the card is present */ + + status |= SPI_STATUS_PRESENT; + } + + return status; +} + +#ifdef CONFIG_SPI_CALLBACK +/**************************************************************************** + * Name: gd32_spi0register + * + * Description: + * Register a media-change callback. This board has no card-detect line, + * so there is nothing to notify; the slot is reported present by + * gd32_spi0status(). + * + ****************************************************************************/ + +int gd32_spi0register(struct spi_dev_s *dev, spi_mediachange_t callback, + void *arg) +{ + return OK; +} +#endif + +#endif /* CONFIG_GD32VW55X_SPI */ diff --git a/boards/risc-v/gd32vw55x/gd32vw553k-start/src/gd32vw553k-start.h b/boards/risc-v/gd32vw55x/gd32vw553k-start/src/gd32vw553k-start.h index 9188115254a..5e2af344b18 100644 --- a/boards/risc-v/gd32vw55x/gd32vw553k-start/src/gd32vw553k-start.h +++ b/boards/risc-v/gd32vw55x/gd32vw553k-start/src/gd32vw553k-start.h @@ -37,4 +37,16 @@ int gd32_bringup(void); +/**************************************************************************** + * Name: gd32_spidev_initialize + * + * Description: + * Configure the SPI chip select GPIO(s) used by the board. + * + ****************************************************************************/ + +#ifdef CONFIG_GD32VW55X_SPI +void gd32_spidev_initialize(void); +#endif + #endif /* __BOARDS_RISCV_GD32VW55X_GD32VW553K_START_SRC_GD32VW553K_START_H */