From 22210724c706e36c5e7134c2c1d1ba6d997f124d Mon Sep 17 00:00:00 2001 From: Federico Di Gregorio Date: Fri, 16 May 2025 18:30:48 +0200 Subject: [PATCH] boards: opta: external flash and BLE support This set of changes adds support for QSPI-based external flash and Bluetooth to the device tree. This make it possible to correctly build and execute the fatfs and several Bluetooth samples out of the box. Also added a function to read the external flash OTP to extract information about the Opta model and hardware features and a second function to retrieve the "official" Opta serial number. Signed-off-by: Federico Di Gregorio --- boards/arduino/opta/CMakeLists.txt | 3 +- ...uino_opta-external-flash-partitioning.dtsi | 42 ++++++++++ .../opta/arduino_opta_stm32h747xx_m7.dts | 82 ++++++++++++++---- boards/arduino/opta/board.h | 39 +++++++++ boards/arduino/opta/board_info.c | 84 +++++++++++++++++++ boards/arduino/opta/doc/index.rst | 10 +++ .../boards/arduino_opta_stm32h747xx_m7.conf | 14 ++++ .../arduino_opta_stm32h747xx_m7.overlay | 20 +++++ 8 files changed, 278 insertions(+), 16 deletions(-) create mode 100644 boards/arduino/opta/arduino_opta-external-flash-partitioning.dtsi create mode 100644 boards/arduino/opta/board.h create mode 100644 boards/arduino/opta/board_info.c create mode 100644 samples/subsys/fs/fs_sample/boards/arduino_opta_stm32h747xx_m7.conf create mode 100644 samples/subsys/fs/fs_sample/boards/arduino_opta_stm32h747xx_m7.overlay diff --git a/boards/arduino/opta/CMakeLists.txt b/boards/arduino/opta/CMakeLists.txt index 07d2bfea9bc..0e06493c1d2 100644 --- a/boards/arduino/opta/CMakeLists.txt +++ b/boards/arduino/opta/CMakeLists.txt @@ -1,4 +1,5 @@ # Copyright (c) 2021 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 -zephyr_sources(board_gpio_init.c) +zephyr_sources(board_gpio_init.c board_info.c) +zephyr_include_directories(.) diff --git a/boards/arduino/opta/arduino_opta-external-flash-partitioning.dtsi b/boards/arduino/opta/arduino_opta-external-flash-partitioning.dtsi new file mode 100644 index 00000000000..2a9908aee50 --- /dev/null +++ b/boards/arduino/opta/arduino_opta-external-flash-partitioning.dtsi @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 DNDG srl + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&quadspi { + qspi_flash: qspi-nor-flash@90000000 { + + /delete-node/ partitions; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Partition 1: WiFi firmware and certificates 1MB - 4kB */ + wlan_partition: partition@1000 { + label = "wlan"; + reg=<0x001000 DT_SIZE_K(1020)>; + }; + + /* Partition 2: OTA 5MB */ + ota_partition: partition@100000 { + label = "ota"; + reg=<0x100000 DT_SIZE_M(5)>; + }; + + /* Partition 3: Provisioning KVStore 1MB */ + kvs_partition: partition@600000 { + label = "kvs"; + reg=<0x600000 DT_SIZE_M(1)>; + }; + + /* Partition 4: User data / OPTA PLC runtime 7MB (littlefs) */ + user_partition: partition@700000 { + label = "user"; + reg=<0x00000 DT_SIZE_M(7)>; + }; + }; + }; +}; diff --git a/boards/arduino/opta/arduino_opta_stm32h747xx_m7.dts b/boards/arduino/opta/arduino_opta_stm32h747xx_m7.dts index 79278d17f0b..7bedf04db4b 100644 --- a/boards/arduino/opta/arduino_opta_stm32h747xx_m7.dts +++ b/boards/arduino/opta/arduino_opta_stm32h747xx_m7.dts @@ -19,6 +19,7 @@ zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,code-partition = &slot0_partition; + zephyr,bt-hci = &bt_hci_uart; }; }; @@ -123,33 +124,84 @@ zephyr_udc0: &usbotg_fs { }; }; +/* Assign Bluetooth to M7 by default */ +&uart4 { + pinctrl-0 = < + &uart4_tx_pb9 + &uart4_rx_ph14 + &uart4_cts_pb15 + &uart4_rts_pa15 + >; + pinctrl-names = "default"; + current-speed = <115200>; + hw-flow-control; + status = "okay"; + + bt_hci_uart: bt_hci_uart { + compatible = "zephyr,bt-hci-uart"; + status = "okay"; + + murata-1dx { + compatible = "infineon,cyw43xxx-bt-hci"; + bt-reg-on-gpios = <&gpioj 12 GPIO_ACTIVE_HIGH>; + bt-host-wake-gpios = <&gpioj 13 GPIO_ACTIVE_HIGH>; + bt-dev-wake-gpios = <&gpioj 14 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +/* Assign external flash to M7 by default */ &quadspi { - pinctrl-0 = < &quadspi_bk1_io0_pd11 - &quadspi_bk1_io1_pd12 - &quadspi_bk1_io2_pe2 - &quadspi_bk1_io3_pd13 - &quadspi_bk1_ncs_pg6 - &quadspi_clk_pb2 >; + pinctrl-0 = < + &quadspi_bk1_io0_pd11 + &quadspi_bk1_io1_pd12 + &quadspi_bk1_io2_pe2 + &quadspi_bk1_io3_pd13 + &quadspi_bk1_ncs_pg6 + &quadspi_clk_pb2 + >; pinctrl-names = "default"; status = "okay"; - at25sf128a: qspi-nor-flash@0 { + qspi_flash: qspi-nor-flash@0 { compatible = "st,stm32-qspi-nor"; reg = <0>; size = ; /* 128 MBits */ - qspi-max-frequency = ; + qspi-max-frequency = <80000000>; + jedec-id = [01 1f 89]; + spi-bus-width = <4>; + quad-enable-requirements = "NONE"; status = "okay"; - spi-bus-width = <2>; - st,read-id-dummy-cycles = <16>; + /* The following partitions are valid only if the Opta external flash + * has never been reformatted or repartitioned. Note the offset of the + * first partition, due to the presence of the MBR. + */ partitions { compatible = "fixed-partitions"; - #address-cells = < 1 >; - #size-cells = < 1 >; + #address-cells = <1>; + #size-cells = <1>; + + /* WiFi firmware and TLS certificates: 1MB - 4K for MBR using LBA */ + wlan_partition: partition@1000 { + label = "wlan"; + reg=<0x001000 DT_SIZE_K(1020)>; + }; + + /* Arduino OTA partition: 13MB */ + fs_partition: partition@100000 { + label = "fs"; + reg=<0x100000 DT_SIZE_M(13)>; + }; - storage_partition: partition@0 { - label = "storage"; - reg=< 0x0 DT_SIZE_K(15872) >; + /* The final 2MB is used to keep a memory-mapped copy of the WiFi + * firmware. The address of the firmware blob is 0xF80000 and the + * size of the partition in the MBR is 0 but, given that we can't + * specify a zero size in `reg` we just give the "correct" one. + */ + wifi_partition: partition@e00000 { + label = "4343WA1"; + reg=<0xE00000 DT_SIZE_M(2)>; }; }; }; diff --git a/boards/arduino/opta/board.h b/boards/arduino/opta/board.h new file mode 100644 index 00000000000..edab2a74f3f --- /dev/null +++ b/boards/arduino/opta/board.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 DNDG srl + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __ARDUINO_OPTA_BOARD_H +#define __ARDUINO_OPTA_BOARD_H + +#include + +#define OPTA_OTP_MAGIC 0xB5 + +#define OPTA_SERIAL_NUMBER_SIZE 24 + +struct __packed opta_board_info { + uint8_t magic; + uint8_t version; + union { + uint16_t board_functionalities; + struct { + uint8_t wifi: 1; + uint8_t rs485: 1; + uint8_t ethernet: 1; + } _board_functionalities_bits; + }; + uint16_t revision; + uint8_t external_flash_size; + uint16_t vid; + uint16_t pid; + uint8_t mac_address[6]; + uint8_t mac_address_wifi[6]; +}; + +const struct opta_board_info *const opta_get_board_info(void); + +const char *const opta_get_serial_number(void); + +#endif /* __ARDUINO_OPTA_BOARD_H */ diff --git a/boards/arduino/opta/board_info.c b/boards/arduino/opta/board_info.c new file mode 100644 index 00000000000..b4c42fc4c50 --- /dev/null +++ b/boards/arduino/opta/board_info.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024 DNDG srl + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "board.h" + +#define AT25SF128_READ_SECURITY_REGISTERS 0x48 + +static struct opta_board_info info; +static char serial_number[OPTA_SERIAL_NUMBER_SIZE + 1]; + +#if defined(CONFIG_FLASH_STM32_QSPI_GENERIC_READ) + +const struct device *const dev = DEVICE_DT_GET(DT_NODELABEL(qspi_flash)); + +static int board_info(void) +{ + QSPI_CommandTypeDef cmd = { + .Instruction = AT25SF128_READ_SECURITY_REGISTERS, + .InstructionMode = QSPI_INSTRUCTION_1_LINE, + .Address = (1 << 13), + .AddressSize = QSPI_ADDRESS_24_BITS, + .AddressMode = QSPI_ADDRESS_1_LINE, + .AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE, + .DataMode = QSPI_DATA_1_LINE, + .NbData = sizeof(struct opta_board_info), + .DummyCycles = 8, + }; + + if (!device_is_ready(dev)) { + return -ENODEV; + } + + int ret = flash_ex_op(dev, FLASH_STM32_QSPI_EX_OP_GENERIC_READ, (uintptr_t)&cmd, &info); + + if (ret != 0) { + return -EIO; + } + + return 0; +} + +SYS_INIT(board_info, APPLICATION, 0); + +#endif /* CONFIG_FLASH_STM32_QSPI_GENERIC_READ */ + +static void uint32tohex(char *dst, uint32_t value) +{ + int v; + + for (int i = 0; i < 8; i++) { + v = (value >> ((8 - i - 1) * 4)) & 0x0F; + dst[i] = v <= 9 ? (0x30 + v) : (0x40 + v - 9); + } +} + +const struct opta_board_info *const opta_get_board_info(void) +{ + if (info.magic == OPTA_OTP_MAGIC) { + return &info; + } + return NULL; +} + +const char *const opta_get_serial_number(void) +{ + if (serial_number[0] == 0) { + uint32tohex(&serial_number[0], HAL_GetUIDw0()); + uint32tohex(&serial_number[8], HAL_GetUIDw1()); + uint32tohex(&serial_number[16], HAL_GetUIDw2()); + } + return serial_number; +} diff --git a/boards/arduino/opta/doc/index.rst b/boards/arduino/opta/doc/index.rst index 4b131659355..7f16e81c20f 100644 --- a/boards/arduino/opta/doc/index.rst +++ b/boards/arduino/opta/doc/index.rst @@ -80,6 +80,16 @@ as well as by the main PLL clock. By default, the CPU2 (Cortex-M4) System clock is driven at 240MHz. PLL clock is fed by a 25MHz high speed external clock. The M7 clock is driven at 400MHz. +External flash +============== + +External flash (16MB on QSPI) access can be enabled by the ``CONFIG_FLASH`` +option. The ``partitions`` entry provided in the default device tree is meant +as an example and is valid only if the Opta is fresh from the factory and the +flash has not been repartitioned. As a second example, the partitioning scheme +created by the new ``QSPIFormat.ino`` sketch from Arduino is available as a +DTSI in ``arduino_opta-external-flash-partitioning.dtsi``. + Resources sharing ================= diff --git a/samples/subsys/fs/fs_sample/boards/arduino_opta_stm32h747xx_m7.conf b/samples/subsys/fs/fs_sample/boards/arduino_opta_stm32h747xx_m7.conf new file mode 100644 index 00000000000..5c137d60740 --- /dev/null +++ b/samples/subsys/fs/fs_sample/boards/arduino_opta_stm32h747xx_m7.conf @@ -0,0 +1,14 @@ +# +# Copyright (c) 2025 DNDG srl +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Usually, some files are already present on the first partition, +# don't create new ones or format the partition in case of failure. +CONFIG_FILE_SYSTEM_MKFS=n +CONFIG_FS_SAMPLE_CREATE_SOME_ENTRIES=n +CONFIG_FS_FATFS_MOUNT_MKFS=n + +# Arduino format FAT volumes using a 4096 bytes sector size. +CONFIG_FS_FATFS_MAX_SS=4096 diff --git a/samples/subsys/fs/fs_sample/boards/arduino_opta_stm32h747xx_m7.overlay b/samples/subsys/fs/fs_sample/boards/arduino_opta_stm32h747xx_m7.overlay new file mode 100644 index 00000000000..0e881395b95 --- /dev/null +++ b/samples/subsys/fs/fs_sample/boards/arduino_opta_stm32h747xx_m7.overlay @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 DNDG srl + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + flash_disk0 { + status="okay"; + compatible = "zephyr,flash-disk"; + partition = <&wlan_partition>; + disk-name = "SD"; + /* A sector size of 4096 is needed to correctly operate on partitions + * formatted by Arduino example sketches. It is possible to reformat + * the external flash and use a different sector size if needed. + */ + sector-size = <4096>; + cache-size = <4096>; + }; +};