Browse Source

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 <fog@dndg.it>
pull/90956/merge
Federico Di Gregorio 2 months ago committed by Daniel DeGrasse
parent
commit
22210724c7
  1. 3
      boards/arduino/opta/CMakeLists.txt
  2. 42
      boards/arduino/opta/arduino_opta-external-flash-partitioning.dtsi
  3. 82
      boards/arduino/opta/arduino_opta_stm32h747xx_m7.dts
  4. 39
      boards/arduino/opta/board.h
  5. 84
      boards/arduino/opta/board_info.c
  6. 10
      boards/arduino/opta/doc/index.rst
  7. 14
      samples/subsys/fs/fs_sample/boards/arduino_opta_stm32h747xx_m7.conf
  8. 20
      samples/subsys/fs/fs_sample/boards/arduino_opta_stm32h747xx_m7.overlay

3
boards/arduino/opta/CMakeLists.txt

@ -1,4 +1,5 @@ @@ -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(.)

42
boards/arduino/opta/arduino_opta-external-flash-partitioning.dtsi

@ -0,0 +1,42 @@ @@ -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)>;
};
};
};
};

82
boards/arduino/opta/arduino_opta_stm32h747xx_m7.dts

@ -19,6 +19,7 @@ @@ -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 { @@ -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 = <DT_SIZE_M(128)>; /* 128 MBits */
qspi-max-frequency = <DT_FREQ_M(70)>;
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)>;
};
};
};

39
boards/arduino/opta/board.h

@ -0,0 +1,39 @@ @@ -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 <stdint.h>
#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 */

84
boards/arduino/opta/board_info.c

@ -0,0 +1,84 @@ @@ -0,0 +1,84 @@
/*
* Copyright (c) 2024 DNDG srl
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/devicetree.h>
#include <zephyr/device.h>
#include <zephyr/init.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/drivers/flash/stm32_flash_api_extensions.h>
#include <soc.h>
#include <errno.h>
#include <stdint.h>
#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;
}

10
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 @@ -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
=================

14
samples/subsys/fs/fs_sample/boards/arduino_opta_stm32h747xx_m7.conf

@ -0,0 +1,14 @@ @@ -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

20
samples/subsys/fs/fs_sample/boards/arduino_opta_stm32h747xx_m7.overlay

@ -0,0 +1,20 @@ @@ -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>;
};
};
Loading…
Cancel
Save