Browse Source
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
8 changed files with 278 additions and 16 deletions
@ -1,4 +1,5 @@ |
|||||||
# Copyright (c) 2021 STMicroelectronics |
# Copyright (c) 2021 STMicroelectronics |
||||||
# SPDX-License-Identifier: Apache-2.0 |
# SPDX-License-Identifier: Apache-2.0 |
||||||
|
|
||||||
zephyr_sources(board_gpio_init.c) |
zephyr_sources(board_gpio_init.c board_info.c) |
||||||
|
zephyr_include_directories(.) |
||||||
|
@ -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)>; |
||||||
|
}; |
||||||
|
}; |
||||||
|
}; |
||||||
|
}; |
@ -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 */ |
@ -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; |
||||||
|
} |
@ -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 |
@ -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…
Reference in new issue