Skip to content

Commit 2221072

Browse files
fogzotdanieldegrasse
authored andcommitted
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 <[email protected]>
1 parent fc3cdb8 commit 2221072

File tree

8 files changed

+278
-16
lines changed

8 files changed

+278
-16
lines changed

boards/arduino/opta/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Copyright (c) 2021 STMicroelectronics
22
# SPDX-License-Identifier: Apache-2.0
33

4-
zephyr_sources(board_gpio_init.c)
4+
zephyr_sources(board_gpio_init.c board_info.c)
5+
zephyr_include_directories(.)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright (c) 2024 DNDG srl
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
&quadspi {
8+
qspi_flash: qspi-nor-flash@90000000 {
9+
10+
/delete-node/ partitions;
11+
12+
partitions {
13+
compatible = "fixed-partitions";
14+
#address-cells = <1>;
15+
#size-cells = <1>;
16+
17+
/* Partition 1: WiFi firmware and certificates 1MB - 4kB */
18+
wlan_partition: partition@1000 {
19+
label = "wlan";
20+
reg=<0x001000 DT_SIZE_K(1020)>;
21+
};
22+
23+
/* Partition 2: OTA 5MB */
24+
ota_partition: partition@100000 {
25+
label = "ota";
26+
reg=<0x100000 DT_SIZE_M(5)>;
27+
};
28+
29+
/* Partition 3: Provisioning KVStore 1MB */
30+
kvs_partition: partition@600000 {
31+
label = "kvs";
32+
reg=<0x600000 DT_SIZE_M(1)>;
33+
};
34+
35+
/* Partition 4: User data / OPTA PLC runtime 7MB (littlefs) */
36+
user_partition: partition@700000 {
37+
label = "user";
38+
reg=<0x00000 DT_SIZE_M(7)>;
39+
};
40+
};
41+
};
42+
};

boards/arduino/opta/arduino_opta_stm32h747xx_m7.dts

Lines changed: 67 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
zephyr,sram = &sram0;
2020
zephyr,flash = &flash0;
2121
zephyr,code-partition = &slot0_partition;
22+
zephyr,bt-hci = &bt_hci_uart;
2223
};
2324
};
2425

@@ -123,33 +124,84 @@ zephyr_udc0: &usbotg_fs {
123124
};
124125
};
125126

127+
/* Assign Bluetooth to M7 by default */
128+
&uart4 {
129+
pinctrl-0 = <
130+
&uart4_tx_pb9
131+
&uart4_rx_ph14
132+
&uart4_cts_pb15
133+
&uart4_rts_pa15
134+
>;
135+
pinctrl-names = "default";
136+
current-speed = <115200>;
137+
hw-flow-control;
138+
status = "okay";
139+
140+
bt_hci_uart: bt_hci_uart {
141+
compatible = "zephyr,bt-hci-uart";
142+
status = "okay";
143+
144+
murata-1dx {
145+
compatible = "infineon,cyw43xxx-bt-hci";
146+
bt-reg-on-gpios = <&gpioj 12 GPIO_ACTIVE_HIGH>;
147+
bt-host-wake-gpios = <&gpioj 13 GPIO_ACTIVE_HIGH>;
148+
bt-dev-wake-gpios = <&gpioj 14 GPIO_ACTIVE_HIGH>;
149+
};
150+
};
151+
};
152+
153+
/* Assign external flash to M7 by default */
126154
&quadspi {
127-
pinctrl-0 = < &quadspi_bk1_io0_pd11
128-
&quadspi_bk1_io1_pd12
129-
&quadspi_bk1_io2_pe2
130-
&quadspi_bk1_io3_pd13
131-
&quadspi_bk1_ncs_pg6
132-
&quadspi_clk_pb2 >;
155+
pinctrl-0 = <
156+
&quadspi_bk1_io0_pd11
157+
&quadspi_bk1_io1_pd12
158+
&quadspi_bk1_io2_pe2
159+
&quadspi_bk1_io3_pd13
160+
&quadspi_bk1_ncs_pg6
161+
&quadspi_clk_pb2
162+
>;
133163
pinctrl-names = "default";
134164
status = "okay";
135165

136-
at25sf128a: qspi-nor-flash@0 {
166+
qspi_flash: qspi-nor-flash@0 {
137167
compatible = "st,stm32-qspi-nor";
138168
reg = <0>;
139169
size = <DT_SIZE_M(128)>; /* 128 MBits */
140-
qspi-max-frequency = <DT_FREQ_M(70)>;
170+
qspi-max-frequency = <80000000>;
171+
jedec-id = [01 1f 89];
172+
spi-bus-width = <4>;
173+
quad-enable-requirements = "NONE";
141174
status = "okay";
142-
spi-bus-width = <2>;
143-
st,read-id-dummy-cycles = <16>;
144175

176+
/* The following partitions are valid only if the Opta external flash
177+
* has never been reformatted or repartitioned. Note the offset of the
178+
* first partition, due to the presence of the MBR.
179+
*/
145180
partitions {
146181
compatible = "fixed-partitions";
147-
#address-cells = < 1 >;
148-
#size-cells = < 1 >;
182+
#address-cells = <1>;
183+
#size-cells = <1>;
184+
185+
/* WiFi firmware and TLS certificates: 1MB - 4K for MBR using LBA */
186+
wlan_partition: partition@1000 {
187+
label = "wlan";
188+
reg=<0x001000 DT_SIZE_K(1020)>;
189+
};
190+
191+
/* Arduino OTA partition: 13MB */
192+
fs_partition: partition@100000 {
193+
label = "fs";
194+
reg=<0x100000 DT_SIZE_M(13)>;
195+
};
149196

150-
storage_partition: partition@0 {
151-
label = "storage";
152-
reg=< 0x0 DT_SIZE_K(15872) >;
197+
/* The final 2MB is used to keep a memory-mapped copy of the WiFi
198+
* firmware. The address of the firmware blob is 0xF80000 and the
199+
* size of the partition in the MBR is 0 but, given that we can't
200+
* specify a zero size in `reg` we just give the "correct" one.
201+
*/
202+
wifi_partition: partition@e00000 {
203+
label = "4343WA1";
204+
reg=<0xE00000 DT_SIZE_M(2)>;
153205
};
154206
};
155207
};

boards/arduino/opta/board.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright (c) 2024 DNDG srl
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef __ARDUINO_OPTA_BOARD_H
8+
#define __ARDUINO_OPTA_BOARD_H
9+
10+
#include <stdint.h>
11+
12+
#define OPTA_OTP_MAGIC 0xB5
13+
14+
#define OPTA_SERIAL_NUMBER_SIZE 24
15+
16+
struct __packed opta_board_info {
17+
uint8_t magic;
18+
uint8_t version;
19+
union {
20+
uint16_t board_functionalities;
21+
struct {
22+
uint8_t wifi: 1;
23+
uint8_t rs485: 1;
24+
uint8_t ethernet: 1;
25+
} _board_functionalities_bits;
26+
};
27+
uint16_t revision;
28+
uint8_t external_flash_size;
29+
uint16_t vid;
30+
uint16_t pid;
31+
uint8_t mac_address[6];
32+
uint8_t mac_address_wifi[6];
33+
};
34+
35+
const struct opta_board_info *const opta_get_board_info(void);
36+
37+
const char *const opta_get_serial_number(void);
38+
39+
#endif /* __ARDUINO_OPTA_BOARD_H */

boards/arduino/opta/board_info.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright (c) 2024 DNDG srl
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
#include <zephyr/devicetree.h>
9+
#include <zephyr/device.h>
10+
#include <zephyr/init.h>
11+
#include <zephyr/drivers/flash.h>
12+
#include <zephyr/drivers/flash/stm32_flash_api_extensions.h>
13+
#include <soc.h>
14+
#include <errno.h>
15+
#include <stdint.h>
16+
#include "board.h"
17+
18+
#define AT25SF128_READ_SECURITY_REGISTERS 0x48
19+
20+
static struct opta_board_info info;
21+
static char serial_number[OPTA_SERIAL_NUMBER_SIZE + 1];
22+
23+
#if defined(CONFIG_FLASH_STM32_QSPI_GENERIC_READ)
24+
25+
const struct device *const dev = DEVICE_DT_GET(DT_NODELABEL(qspi_flash));
26+
27+
static int board_info(void)
28+
{
29+
QSPI_CommandTypeDef cmd = {
30+
.Instruction = AT25SF128_READ_SECURITY_REGISTERS,
31+
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
32+
.Address = (1 << 13),
33+
.AddressSize = QSPI_ADDRESS_24_BITS,
34+
.AddressMode = QSPI_ADDRESS_1_LINE,
35+
.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE,
36+
.DataMode = QSPI_DATA_1_LINE,
37+
.NbData = sizeof(struct opta_board_info),
38+
.DummyCycles = 8,
39+
};
40+
41+
if (!device_is_ready(dev)) {
42+
return -ENODEV;
43+
}
44+
45+
int ret = flash_ex_op(dev, FLASH_STM32_QSPI_EX_OP_GENERIC_READ, (uintptr_t)&cmd, &info);
46+
47+
if (ret != 0) {
48+
return -EIO;
49+
}
50+
51+
return 0;
52+
}
53+
54+
SYS_INIT(board_info, APPLICATION, 0);
55+
56+
#endif /* CONFIG_FLASH_STM32_QSPI_GENERIC_READ */
57+
58+
static void uint32tohex(char *dst, uint32_t value)
59+
{
60+
int v;
61+
62+
for (int i = 0; i < 8; i++) {
63+
v = (value >> ((8 - i - 1) * 4)) & 0x0F;
64+
dst[i] = v <= 9 ? (0x30 + v) : (0x40 + v - 9);
65+
}
66+
}
67+
68+
const struct opta_board_info *const opta_get_board_info(void)
69+
{
70+
if (info.magic == OPTA_OTP_MAGIC) {
71+
return &info;
72+
}
73+
return NULL;
74+
}
75+
76+
const char *const opta_get_serial_number(void)
77+
{
78+
if (serial_number[0] == 0) {
79+
uint32tohex(&serial_number[0], HAL_GetUIDw0());
80+
uint32tohex(&serial_number[8], HAL_GetUIDw1());
81+
uint32tohex(&serial_number[16], HAL_GetUIDw2());
82+
}
83+
return serial_number;
84+
}

boards/arduino/opta/doc/index.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,16 @@ as well as by the main PLL clock. By default, the CPU2 (Cortex-M4) System clock
8080
is driven at 240MHz. PLL clock is fed by a 25MHz high speed external clock. The
8181
M7 clock is driven at 400MHz.
8282

83+
External flash
84+
==============
85+
86+
External flash (16MB on QSPI) access can be enabled by the ``CONFIG_FLASH``
87+
option. The ``partitions`` entry provided in the default device tree is meant
88+
as an example and is valid only if the Opta is fresh from the factory and the
89+
flash has not been repartitioned. As a second example, the partitioning scheme
90+
created by the new ``QSPIFormat.ino`` sketch from Arduino is available as a
91+
DTSI in ``arduino_opta-external-flash-partitioning.dtsi``.
92+
8393
Resources sharing
8494
=================
8595

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#
2+
# Copyright (c) 2025 DNDG srl
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
7+
# Usually, some files are already present on the first partition,
8+
# don't create new ones or format the partition in case of failure.
9+
CONFIG_FILE_SYSTEM_MKFS=n
10+
CONFIG_FS_SAMPLE_CREATE_SOME_ENTRIES=n
11+
CONFIG_FS_FATFS_MOUNT_MKFS=n
12+
13+
# Arduino format FAT volumes using a 4096 bytes sector size.
14+
CONFIG_FS_FATFS_MAX_SS=4096
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright (c) 2025 DNDG srl
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/ {
8+
flash_disk0 {
9+
status="okay";
10+
compatible = "zephyr,flash-disk";
11+
partition = <&wlan_partition>;
12+
disk-name = "SD";
13+
/* A sector size of 4096 is needed to correctly operate on partitions
14+
* formatted by Arduino example sketches. It is possible to reformat
15+
* the external flash and use a different sector size if needed.
16+
*/
17+
sector-size = <4096>;
18+
cache-size = <4096>;
19+
};
20+
};

0 commit comments

Comments
 (0)