From ec3355a5182db336f8d0be61cc48d46d6408ce59 Mon Sep 17 00:00:00 2001 From: Denis Tolstov Date: Mon, 3 Apr 2023 06:57:57 +0300 Subject: [PATCH] boards/stm32f411-minimum: Add support for USB mass storage (gadget) * Bind smartfs0 to LUN 0 instead of mmcsd0 * Use USB composite code from similar boards * Pull in CDC/ACM code as well boards/stm32f411-minimum: composite: style refactor * Unalign `int strbase = ` text, use single spaces * Rename `int n` to `int dev_idx` like in newer `_composite.c` board code * Add composite defconfig with CDC/ACM and MSC for build-testing --- boards/arm/stm32/stm32f411-minimum/README.txt | 4 + .../configs/composite/defconfig | 66 +++++ .../configs/usbmsc/defconfig | 57 ++++ .../arm/stm32/stm32f411-minimum/src/Make.defs | 8 + .../stm32f411-minimum/src/stm32_composite.c | 276 ++++++++++++++++++ .../stm32f411-minimum/src/stm32_usbmsc.c | 70 +++++ 6 files changed, 481 insertions(+) create mode 100644 boards/arm/stm32/stm32f411-minimum/configs/composite/defconfig create mode 100644 boards/arm/stm32/stm32f411-minimum/configs/usbmsc/defconfig create mode 100644 boards/arm/stm32/stm32f411-minimum/src/stm32_composite.c create mode 100644 boards/arm/stm32/stm32f411-minimum/src/stm32_usbmsc.c diff --git a/boards/arm/stm32/stm32f411-minimum/README.txt b/boards/arm/stm32/stm32f411-minimum/README.txt index 20c98a6e1b..d7b9729d22 100644 --- a/boards/arm/stm32/stm32f411-minimum/README.txt +++ b/boards/arm/stm32/stm32f411-minimum/README.txt @@ -88,6 +88,10 @@ as well as 5k pull-downs on USB-C CC1/CC2 pins (not affecting USB-A adapters). Because of this we are not considering USBOTG-FS Host configurations and do not map OTG_VBUS, OTG_ID pins to FS PHY, also no OVER/PWRON GPIOs. +If using USB and USART1 simultaneously, make sure to check +CONFIG_OTG_ID_GPIO_DISABLE, else stm32_otgfsdev driver code remaps PA10 pin from +USART1_RX to OTG_ID, and you'll lose keyboard/console input! + SPI NOR Flash ============= diff --git a/boards/arm/stm32/stm32f411-minimum/configs/composite/defconfig b/boards/arm/stm32/stm32f411-minimum/configs/composite/defconfig new file mode 100644 index 0000000000..df298c23ba --- /dev/null +++ b/boards/arm/stm32/stm32f411-minimum/configs/composite/defconfig @@ -0,0 +1,66 @@ +# +# 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_FPU is not set +# CONFIG_DISABLE_OS_API is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +# CONFIG_NSH_DISABLE_IFCONFIG is not set +# CONFIG_NSH_DISABLE_PS is not set +# CONFIG_STM32_SYSCFG is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="stm32f411-minimum" +CONFIG_ARCH_BOARD_STM32F411_MINIMUM=y +CONFIG_ARCH_CHIP="stm32" +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_CHIP_STM32F411CE=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LOOPSPERMSEC=8499 +CONFIG_BUILTIN=y +CONFIG_CDCACM=y +CONFIG_CDCACM_COMPOSITE=y +CONFIG_COMPOSITE_IAD=y +CONFIG_COMPOSITE_PRODUCTID=0x2022 +CONFIG_COMPOSITE_VENDORID=0x03eb +CONFIG_HAVE_CXX=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_DISABLE_LOSMART=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_OTG_ID_GPIO_DISABLE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=131072 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=02 +CONFIG_START_MONTH=04 +CONFIG_START_YEAR=2023 +CONFIG_STM32F411MINIMUM_FLASH=y +CONFIG_STM32_FLASH_CONFIG_E=y +CONFIG_STM32_FLASH_PREFETCH=y +CONFIG_STM32_JTAG_SW_ENABLE=y +CONFIG_STM32_OTGFS=y +CONFIG_STM32_USART1=y +CONFIG_SYSTEM_CDCACM=y +CONFIG_SYSTEM_COMPOSITE=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_USBMSC=y +CONFIG_SYSTEM_USBMSC_DEVPATH1="/dev/smart0" +CONFIG_TASK_NAME_SIZE=15 +CONFIG_USART1_SERIAL_CONSOLE=y +CONFIG_USBDEV=y +CONFIG_USBDEV_BUSPOWERED=y +CONFIG_USBDEV_COMPOSITE=y +CONFIG_USBMSC=y +CONFIG_USBMSC_COMPOSITE=y diff --git a/boards/arm/stm32/stm32f411-minimum/configs/usbmsc/defconfig b/boards/arm/stm32/stm32f411-minimum/configs/usbmsc/defconfig new file mode 100644 index 0000000000..3b7623cf2d --- /dev/null +++ b/boards/arm/stm32/stm32f411-minimum/configs/usbmsc/defconfig @@ -0,0 +1,57 @@ +# +# 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_FPU is not set +# CONFIG_DISABLE_OS_API is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +# CONFIG_NSH_DISABLE_IFCONFIG is not set +# CONFIG_NSH_DISABLE_PS is not set +# CONFIG_STM32_SYSCFG is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="stm32f411-minimum" +CONFIG_ARCH_BOARD_STM32F411_MINIMUM=y +CONFIG_ARCH_CHIP="stm32" +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_CHIP_STM32F411CE=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LOOPSPERMSEC=8499 +CONFIG_BUILTIN=y +CONFIG_HAVE_CXX=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_DISABLE_LOSMART=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_OTG_ID_GPIO_DISABLE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=131072 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=02 +CONFIG_START_MONTH=04 +CONFIG_START_YEAR=2023 +CONFIG_STM32F411MINIMUM_FLASH=y +CONFIG_STM32_FLASH_CONFIG_E=y +CONFIG_STM32_FLASH_PREFETCH=y +CONFIG_STM32_JTAG_SW_ENABLE=y +CONFIG_STM32_OTGFS=y +CONFIG_STM32_USART1=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_USBMSC=y +CONFIG_SYSTEM_USBMSC_DEVPATH1="/dev/smart0" +CONFIG_TASK_NAME_SIZE=15 +CONFIG_USART1_SERIAL_CONSOLE=y +CONFIG_USBDEV=y +CONFIG_USBDEV_BUSPOWERED=y +CONFIG_USBMSC=y diff --git a/boards/arm/stm32/stm32f411-minimum/src/Make.defs b/boards/arm/stm32/stm32f411-minimum/src/Make.defs index 1a310baf7a..2052579943 100644 --- a/boards/arm/stm32/stm32f411-minimum/src/Make.defs +++ b/boards/arm/stm32/stm32f411-minimum/src/Make.defs @@ -42,6 +42,14 @@ ifeq ($(CONFIG_STM32_OTGFS),y) CSRCS += stm32_usb.c endif +ifeq ($(CONFIG_USBDEV_COMPOSITE),y) + CSRCS += stm32_composite.c +endif + +ifeq ($(CONFIG_USBMSC),y) +CSRCS += stm32_usbmsc.c +endif + DEPPATH += --dep-path board VPATH += :board CFLAGS += $(shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)board) diff --git a/boards/arm/stm32/stm32f411-minimum/src/stm32_composite.c b/boards/arm/stm32/stm32f411-minimum/src/stm32_composite.c new file mode 100644 index 0000000000..107b1a4ad7 --- /dev/null +++ b/boards/arm/stm32/stm32f411-minimum/src/stm32_composite.c @@ -0,0 +1,276 @@ +/**************************************************************************** + * boards/arm/stm32/stm32f411-minimum/src/stm32_composite.c + * + * 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 + +#if defined(CONFIG_BOARDCTL_USBDEVCTRL) && defined(CONFIG_USBDEV_COMPOSITE) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static void *g_mschandle; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_mscclassobject + * + * Description: + * If the mass storage class driver is part of composite device, then + * its instantiation and configuration is a multi-step, board-specific, + * process (See comments for usbmsc_configure below). In this case, + * board-specific logic must provide board_mscclassobject(). + * + * board_mscclassobject() is called from the composite driver. It must + * encapsulate the instantiation and configuration of the mass storage + * class and the return the mass storage device's class driver instance + * to the composite driver. + * + * Input Parameters: + * classdev - The location to return the mass storage class' device + * instance. + * + * Returned Value: + * 0 on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static int board_mscclassobject(int minor, + struct usbdev_devinfo_s *devinfo, + struct usbdevclass_driver_s **classdev) +{ + int ret; + + DEBUGASSERT(g_mschandle == NULL); + + /* Configure the mass storage device */ + + uinfo("Configuring with NLUNS=1\n"); + ret = usbmsc_configure(1, &g_mschandle); + if (ret < 0) + { + uerr("ERROR: usbmsc_configure failed: %d\n", -ret); + return ret; + } + + uinfo("MSC handle=%p\n", g_mschandle); + + /* Bind the LUN(s) */ + + uinfo("Bind LUN=0 to /dev/smart0\n"); + ret = usbmsc_bindlun(g_mschandle, "/dev/smart0", 0, 0, 0, false); + if (ret < 0) + { + uerr("ERROR: usbmsc_bindlun failed for LUN 1 at /dev/smart0: %d\n", + ret); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; + return ret; + } + + /* Get the mass storage device's class object */ + + ret = usbmsc_classobject(g_mschandle, devinfo, classdev); + if (ret < 0) + { + uerr("ERROR: usbmsc_classobject failed: %d\n", -ret); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: board_mscuninitialize + * + * Description: + * Un-initialize the USB storage class driver. + * This is just an application specific wrapper for usbmsc_unitialize() + * that is called form the composite device logic. + * + * Input Parameters: + * classdev - The class driver instrance previously give to the composite + * driver by board_mscclassobject(). + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static void board_mscuninitialize(struct usbdevclass_driver_s *classdev) +{ + if (g_mschandle) + { + usbmsc_uninitialize(g_mschandle); + } + + g_mschandle = NULL; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_composite_initialize + * + * Description: + * Perform architecture specific initialization of a composite USB device. + * + ****************************************************************************/ + +int board_composite_initialize(int port) +{ + return OK; +} + +/**************************************************************************** + * Name: board_composite_connect + * + * Description: + * Connect the USB composite device on the specified USB device port using + * the specified configuration. The interpretation of the configid is + * board specific. + * + * Input Parameters: + * port - The USB device port. + * configid - The USB composite configuration + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +void *board_composite_connect(int port, int configid) +{ + /* Here we are composing the configuration of the usb composite device. + * + * The standard is to use one CDC/ACM and one USB mass storage device. + */ + + if (configid == 0) + { + struct composite_devdesc_s dev[2]; + int ifnobase = 0; + int strbase = COMPOSITE_NSTRIDS; + int dev_idx = 0; + +#ifdef CONFIG_USBMSC_COMPOSITE + /* Configure the mass storage device device */ + + /* Ask the usbmsc driver to fill in the constants we didn't + * know here. + */ + + usbmsc_get_composite_devdesc(&dev[dev_idx]); + + /* Overwrite and correct some values... */ + + /* The callback functions for the USBMSC class */ + + dev[dev_idx].classobject = board_mscclassobject; + dev[dev_idx].uninitialize = board_mscuninitialize; + + /* Interfaces */ + + dev[dev_idx].devinfo.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[dev_idx].minor = 0; /* The minor interface number */ + + /* Strings */ + + dev[dev_idx].devinfo.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[dev_idx].devinfo.epno[USBMSC_EP_BULKIN_IDX] = 3; + dev[dev_idx].devinfo.epno[USBMSC_EP_BULKOUT_IDX] = 3; + + /* Count up the base numbers */ + + ifnobase += dev[dev_idx].devinfo.ninterfaces; + strbase += dev[dev_idx].devinfo.nstrings; + dev_idx++; +#endif + +#ifdef CONFIG_CDCACM_COMPOSITE + /* Configure the CDC/ACM device */ + + /* Ask the cdcacm driver to fill in the constants we didn't + * know here. + */ + + cdcacm_get_composite_devdesc(&dev[dev_idx]); + + /* Overwrite and correct some values... */ + + /* The callback functions for the CDC/ACM class */ + + dev[dev_idx].classobject = cdcacm_classobject; + dev[dev_idx].uninitialize = cdcacm_uninitialize; + + /* Interfaces */ + + dev[dev_idx].devinfo.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[dev_idx].minor = 0; /* The minor interface number */ + + /* Strings */ + + dev[dev_idx].devinfo.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[dev_idx].devinfo.epno[CDCACM_EP_INTIN_IDX] = 1; + dev[dev_idx].devinfo.epno[CDCACM_EP_BULKIN_IDX] = 2; + dev[dev_idx].devinfo.epno[CDCACM_EP_BULKOUT_IDX] = 2; + dev_idx++; +#endif + + return composite_initialize(dev_idx, dev); + } + else + { + return NULL; + } +} + +#endif /* CONFIG_BOARDCTL_USBDEVCTRL && CONFIG_USBDEV_COMPOSITE */ diff --git a/boards/arm/stm32/stm32f411-minimum/src/stm32_usbmsc.c b/boards/arm/stm32/stm32f411-minimum/src/stm32_usbmsc.c new file mode 100644 index 0000000000..bf742e7f9a --- /dev/null +++ b/boards/arm/stm32/stm32f411-minimum/src/stm32_usbmsc.c @@ -0,0 +1,70 @@ +/**************************************************************************** + * boards/arm/stm32/stm32f411-minimum/src/stm32_usbmsc.c + * + * 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 "stm32.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifndef CONFIG_SYSTEM_USBMSC_DEVMINOR1 +# define CONFIG_SYSTEM_USBMSC_DEVMINOR1 0 +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_usbmsc_initialize + * + * Description: + * Perform architecture specific initialization of the USB MSC device. + * + ****************************************************************************/ + +int board_usbmsc_initialize(int port) +{ + /* If system/usbmsc is built as an NSH command, then SD slot should + * already have been initialized in board_app_initialize() + * (see stm32_appinit.c). + * In this case, there is nothing further to be done here. + */ + +#ifndef CONFIG_NSH_BUILTIN_APPS + return stm32_w25initialize(CONFIG_SYSTEM_USBMSC_DEVMINOR1); +#else + return OK; +#endif +}