boards: opta: initial support for M7 core

Features enabled by this commit:

* M7 core available with or without the Arduino MCU-based bootloader by
  correctly initializing the external clock source.
* All LEDs, relays and the user button are mapped into the device tree
  (samples/common/blinky works out of the box).
* USB can be used in ACM mode (samples/subsys/usb/cdc_acm works without
  changes). The default Zephyr console is configured to use cdc_acm_uart0
  that in turn is assigned to the only USB port available.

Also enable USB stack to make sure that the console is available by default
and twister builds don't fail with missing device and added the default USB
vendor (0x35d1 Finder SpA) and product (0x0164) numbers to match the ones
used in the original product.

Signed-off-by: Federico Di Gregorio <fog@dndg.it>
This commit is contained in:
Federico Di Gregorio 2024-08-19 16:23:34 +02:00 committed by Anas Nashif
commit d5447a310e
14 changed files with 463 additions and 59 deletions

View file

@ -0,0 +1,4 @@
# Copyright (c) 2021 STMicroelectronics
# SPDX-License-Identifier: Apache-2.0
zephyr_sources(board_gpio_hse.c)

View file

@ -1,5 +1,7 @@
# Copyright (c) 2023 Felipe Neves
# Copyright (c) 2024 DNDG srl
# SPDX-License-Identifier: Apache-2.0
config BOARD_ARDUINO_OPTA
select SOC_STM32H747XX_M4
select SOC_STM32H747XX_M4 if BOARD_ARDUINO_OPTA_STM32H747XX_M4
select SOC_STM32H747XX_M7 if BOARD_ARDUINO_OPTA_STM32H747XX_M7

View file

@ -0,0 +1,37 @@
# Copyright 2024 Rahul Arasikere <arasikere.rahul@gmail.com>
# Copyright 2024 DNDG srl
# SPDX-License-Identifier: Apache-2.0
if BOARD_ARDUINO_OPTA
if USB_DEVICE_STACK
config USB_DEVICE_PRODUCT
default "Arduino Opta"
config USB_DEVICE_PID
default 0x0164
config USB_DEVICE_VID
default 0x35d1
config USB_DEVICE_INITIALIZE_AT_BOOT
default y
if LOG
# Logger cannot use itself to log
choice USB_CDC_ACM_LOG_LEVEL_CHOICE
default USB_CDC_ACM_LOG_LEVEL_OFF
endchoice
# Set USB log level to error only
choice USB_DEVICE_LOG_LEVEL_CHOICE
default USB_DEVICE_LOG_LEVEL_ERR
endchoice
endif # LOG
endif # USB_DEVICE_STACK
endif # BOARD_ARDUINO_OPTA

View file

@ -0,0 +1,89 @@
/*
* Copyright (c) 2023 Felipe Neves
* Copyright (c) 2024 DNDG srl
*
* SPDX-License-Identifier: Apache-2.0
*/
/ {
leds {
compatible = "gpio-leds";
status_led_1: led_1 {
gpios = <&gpioi 0 GPIO_ACTIVE_HIGH>;
};
status_led_2: led_2 {
gpios = <&gpioi 1 GPIO_ACTIVE_HIGH>;
};
status_led_3: led_3 {
gpios = <&gpioi 3 GPIO_ACTIVE_HIGH>;
};
status_led_4: led_4 {
gpios = <&gpioh 15 GPIO_ACTIVE_HIGH>;
};
led_reset: led_g {
gpios = <&gpioh 12 GPIO_ACTIVE_HIGH>;
};
led_reset_red: led_r {
gpios = <&gpioh 11 GPIO_ACTIVE_HIGH>;
};
led_user: led_b {
gpios = <&gpioe 5 GPIO_ACTIVE_HIGH>;
};
};
relays {
compatible = "gpio-power-switches";
output_d0: d0 {
gpios = <&gpioi 6 GPIO_ACTIVE_HIGH>;
};
output_d1: d1 {
gpios = <&gpioi 5 GPIO_ACTIVE_HIGH>;
};
output_d2: d2 {
gpios = <&gpioi 7 GPIO_ACTIVE_HIGH>;
};
output_d3: d3 {
gpios = <&gpioi 4 GPIO_ACTIVE_HIGH>;
};
};
gpio_keys {
compatible = "gpio-keys";
user_button: button {
gpios = <&gpioe 4 GPIO_ACTIVE_HIGH>;
zephyr,code = <INPUT_KEY_WAKEUP>;
};
};
aliases {
sw0 = &user_button;
led0 = &status_led_1;
led1 = &status_led_2;
led2 = &status_led_3;
led3 = &status_led_4;
relay1 = &output_d0;
relay2 = &output_d1;
relay3 = &output_d2;
relay4 = &output_d3;
};
};
&rcc {
d1cpre = <1>;
hpre = <2>;
d1ppre = <2>;
d2ppre1 = <2>;
d2ppre2 = <2>;
d3ppre = <2>;
};
&rtc {
status = "okay";
};
&mailbox {
status = "okay";
};

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2023 Felipe Neves
* Copyright (c) 2024 DNDG srl
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -8,6 +9,7 @@
#include <st/h7/stm32h747Xi_m4.dtsi>
#include <st/h7/stm32h747xihx-pinctrl.dtsi>
#include <zephyr/dt-bindings/input/input-event-codes.h>
#include "arduino_opta-common.dtsi"
/ {
model = "Arduino OPTA M4 core Programmable Logic Controller";
@ -18,36 +20,6 @@
zephyr,flash = &flash1;
zephyr,code-partition = &slot0_partition;
};
leds {
compatible = "gpio-leds";
status_led_1: led_1 {
gpios = <&gpioi 0 GPIO_ACTIVE_LOW>;
};
status_led_2: led_2 {
gpios = <&gpioi 1 GPIO_ACTIVE_LOW>;
};
status_led_3: led_3 {
gpios = <&gpioi 3 GPIO_ACTIVE_LOW>;
};
status_led_4: led_4 {
gpios = <&gpioh 15 GPIO_ACTIVE_LOW>;
};
};
gpio_keys {
compatible = "gpio-keys";
user_button: button {
gpios = <&gpioe 4 GPIO_ACTIVE_HIGH>;
zephyr,code = <INPUT_KEY_WAKEUP>;
};
};
aliases {
sw0 = &user_button;
led0 = &status_led_1;
};
};
&flash1 {
@ -64,11 +36,5 @@
};
&rcc {
d1cpre = <1>;
hpre = <2>;
d1ppre = <2>;
d2ppre1 = <2>;
d2ppre2 = <2>;
d3ppre = <2>;
clock-frequency = <DT_FREQ_M(240)>;
};

View file

@ -1,10 +1,10 @@
# Copyright (c) 2023 Felipe Neves
# SPDX-License-Identifier: Apache-2.0
# enable GPIO
# Enable GPIO
CONFIG_GPIO=y
# clock configuration
# Clock configuration
CONFIG_CLOCK_CONTROL=y
# Enable MPU
@ -13,6 +13,5 @@ CONFIG_ARM_MPU=y
# Enable HW stack protection
CONFIG_HW_STACK_PROTECTION=y
# Use zephyr,code-partition as flash offset
CONFIG_USE_DT_CODE_PARTITION=y

View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2022 Benjamin Björnsson <benjamin.bjornsson@gmail.com>.
* Copyright (c) 2024 DNDG srl
*
* SPDX-License-Identifier: Apache-2.0
*/
/dts-v1/;
#include <st/h7/stm32h747Xi_m7.dtsi>
#include <st/h7/stm32h747xihx-pinctrl.dtsi>
#include <zephyr/dt-bindings/input/input-event-codes.h>
#include "arduino_opta-common.dtsi"
/ {
model = "Arduino OPTA M7 core Programmable Logic Controller";
compatible = "arduino,opta-m7";
chosen {
zephyr,console = &cdc_acm_uart0;
zephyr,sram = &sram0;
zephyr,flash = &flash0;
zephyr,code-partition = &slot0_partition;
};
};
zephyr_udc0: &usbotg_fs {
pinctrl-0 = <&usb_otg_fs_dm_pa11 &usb_otg_fs_dp_pa12>;
pinctrl-names = "default";
status = "okay";
cdc_acm_uart0: cdc_acm_uart0 {
compatible = "zephyr,cdc-acm-uart";
};
};
&clk_hse {
clock-frequency = <DT_FREQ_M(25)>;
hse-bypass;
status = "okay";
};
&clk_lse {
clock-frequency = <32768>;
lse-bypass;
status = "okay";
};
&clk_hsi {
hsi-div = <1>;
status = "okay";
};
&clk_hsi48 {
/* HSI48 required for USB */
status = "okay";
};
&pll {
div-m = <5>;
mul-n = <160>;
div-p = <2>;
div-r = <2>;
div-q = <10>;
clocks = <&clk_hse>;
status = "okay";
};
&rcc {
clocks = <&pll>;
clock-frequency = <DT_FREQ_M(400)>;
};
&flash0 {
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
slot0_partition: partition@40000 {
label = "image-0";
reg = <0x00040000 DT_SIZE_K(768)>;
};
};
};
&usbotg_fs {
status = "okay";
};
&usbotg_hs {
status = "disabled";
};
&mac {
pinctrl-0 = <
&eth_ref_clk_pa1
&eth_mdio_pa2
&eth_crs_dv_pa7
&eth_mdc_pc1
&eth_rxd0_pc4
&eth_rxd1_pc5
&eth_tx_en_pg11
&eth_txd1_pg12
&eth_txd0_pg13
>;
pinctrl-names = "default";
};

View file

@ -0,0 +1,21 @@
identifier: arduino_opta/stm32h747xx/m7
name: ARDUINO OPTA (M7)
type: mcu
arch: arm
toolchain:
- zephyr
- gnuarmemb
- xtools
ram: 512
flash: 768
supported:
- gpio
testing:
ignore_tags:
- mpu
- nfc
- net
- flash
- input
- mcumgr
vendor: arduino

View file

@ -0,0 +1,33 @@
# Copyright (c) 2023 Felipe Neves
# Copyright (c) 2024 DNDG srl
# SPDX-License-Identifier: Apache-2.0
# Enable GPIO
CONFIG_GPIO=y
# Clock configuration
CONFIG_CLOCK_CONTROL=y
# Enable MPU
CONFIG_ARM_MPU=y
# Enable HW stack protection
CONFIG_HW_STACK_PROTECTION=y
# Use zephyr,code-partition as flash offset
CONFIG_USE_DT_CODE_PARTITION=y
# Enable correct power supply
CONFIG_POWER_SUPPLY_SMPS_1V8_SUPPLIES_EXT_AND_LDO=y
# Don't start M4 during the M7 boot (this is what the original Opta does)
CONFIG_STM32H7_BOOT_M4_AT_INIT=n
# Enable console
CONFIG_SERIAL=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_UART_LINE_CTRL=y
# Enable USB Stack (needed for the console to work)
CONFIG_USB_DEVICE_STACK=y

View file

@ -2,4 +2,17 @@
board_runner_args(dfu-util "--pid=2341:0364" "--alt=0" "--dfuse")
if(CONFIG_BOARD_ARDUINO_OPTA_STM32H747XX_M7)
board_runner_args(openocd "--config=${BOARD_DIR}/support/openocd_opta_stm32h747xx_m7.cfg")
board_runner_args(openocd --target-handle=_CHIPNAME.cpu0)
elseif(CONFIG_BOARD_ARDUINO_OPTA_STM32H747XX_M4)
board_runner_args(openocd "--config=${BOARD_DIR}/support/openocd_opta_stm32h747xx_m4.cfg")
board_runner_args(openocd --target-handle=_CHIPNAME.cpu1)
endif()
board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw")
# Give priority to dfu-util to flash, ST-Link to debug.
include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake)
include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake)
include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake)

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2024 DNDG srl
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/init.h>
#include <stm32h7xx_ll_bus.h>
#include <stm32h7xx_ll_gpio.h>
static int board_gpio_hse(void)
{
/* The external oscillator that drives the HSE clock should be enabled
* by setting the GPIOI1 pin. This function is registered at priority
* RE_KERNEL_1 to be executed before the standard STM clock
* setup code.
*/
LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOH);
LL_GPIO_SetPinMode(GPIOH, LL_GPIO_PIN_1, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinSpeed(GPIOH, LL_GPIO_PIN_1, LL_GPIO_SPEED_FREQ_LOW);
LL_GPIO_SetPinOutputType(GPIOH, LL_GPIO_PIN_1, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinPull(GPIOH, LL_GPIO_PIN_1, LL_GPIO_PULL_UP);
LL_GPIO_SetOutputPin(GPIOH, LL_GPIO_PIN_1);
return 0;
}
SYS_INIT(board_gpio_hse, PRE_KERNEL_1, 0);

View file

@ -1,7 +1,7 @@
.. _arduino_opta_m4_board:
Arduino OPTA M4-Core
####################
Arduino OPTA
############
Overview
********
@ -15,14 +15,17 @@ such as Ladder Diagram (LD), Sequential Function Chart (SFC),
Function Block Diagram (FBD), Structured Text (ST), and Instruction List (IL),
making it an ideal device for automation engineers.
For Zephyr RTOS, only the M4 is supported for now, making the M7 run the PLC
tasks while the M4 core under Zephyr acts as a coprocessor.
For Zephyr RTOS, both cores are supported. It is also possible to run only on
the M4 making the M7 run the PLC tasks while the M4 core under Zephyr acts as
a coprocessor.
Additionally, the device features:
- Ethernet compliant with IEEE802.3-2002
- 16MB QSPI Flash
- 4 x green color status LEDs
- 1 x green or red led over the reset push-button
- 1 x blue led over the user push-button (Opta Advanced only)
- 1 x user push-button
- 1 x reset push-button accessible via pinhole
- 8 x analog inputs
@ -42,7 +45,29 @@ More information about STM32H747XIH6 can be found here:
Supported Features
==================
The current Zephyr arduino_opta_m4 board configuration supports the following hardware features:
The ``arduino_opta/stm32h747xx/m7`` board target
supports the following hardware features:
+-----------+------------+-------------------------------------+
| Interface | Controller | Driver/Component |
+===========+============+=====================================+
| NVIC | on-chip | nested vector interrupt controller |
+-----------+------------+-------------------------------------+
| PINMUX | on-chip | pinmux |
+-----------+------------+-------------------------------------+
| GPIO | on-chip | gpio |
+-----------+------------+-------------------------------------+
| FLASH | on-chip | flash memory |
+-----------+------------+-------------------------------------+
| RNG | on-chip | True Random number generator |
+-----------+------------+-------------------------------------+
| IPM | on-chip | virtual mailbox based on HSEM |
+-----------+------------+-------------------------------------+
| USB | on-board | usb-fs |
+-----------+------------+-------------------------------------+
The ``arduino_opta/stm32h747xx/m4`` board target
supports the following hardware features:
+-----------+------------+-------------------------------------+
| Interface | Controller | Driver/Component |
@ -62,32 +87,41 @@ The current Zephyr arduino_opta_m4 board configuration supports the following ha
Other hardware features are not yet supported on Zephyr porting.
The default configuration per core can be found in the defconfig file:
:zephyr_file:`boards/arduino/opta/arduino_opta_stm32h747xx_m4_defconfig`
The default configuration per core can be found in the defconfig files:
:zephyr_file:`boards/arduino/opta/arduino_opta_stm32h747xx_m4_defconfig` and
:zephyr_file:`boards/arduino/opta/arduino_opta_stm32h747xx_m7_defconfig`.
Pin Mapping
===========
ARDUINO OPTA M4 has access to the 9 GPIO controllers. These controllers are responsible for pin muxing,
input/output, pull-up, etc.
Both the M7 and M4 cores have access to the 9 GPIO controllers. These
controllers are responsible for pin muxing, input/output, pull-up, etc.
For more details please refer to `ARDUINO-OPTA website`_.
Default Zephyr Peripheral Mapping
---------------------------------
- Status LED1 : PI0
- Status LED2 : PI1
- Status LED3 : PI3
- Status LED4 : PH15
- User button : PE4
- Status LED1: PI0
- Status LED2: PI1
- Status LED3: PI3
- Status LED4: PH15
- Green "reset" LED: PH12
- Red "reset" LED: PH11
- Blue LED: PE5
- User button: PE4
- Relay 1: PI6
- Relay 2: PI5
- Relay 3: PI7
- Relay 4: PI4
System Clock
============
The STM32H747I System Clock can be driven by an internal or external oscillator,
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.
is driven at 240MHz. PLL clock is fed by a 25MHz high speed external clock. The
M7 clock is driven at 400MHz.
Resources sharing
=================
@ -121,9 +155,30 @@ indicating the board is in bootloader mode.
By default:
- CPU2 (Cortex-M4) boot address is set to 0x08180000 (OB: BOOT_CM4_ADD0)
- CPU1 (Cortex-M7) boot address is set to 0x08040000
- CPU2 (Cortex-M4) boot address is set to 0x08180000
Zephyr flash configuration has been set to meet these default settings.
Zephyr flash configuration has been set to be compatible with the
"Flash split: 1.5MB M7 + 0.5MB M4" option in the Arduino IDE. The flash is
partitioned as follows:
- 0x08000000-0x0803FFFF (256k) Arduino MCUboot-derived bootloader
- 0x08040000-0x0817FFFF (768k) M7 application
- 0x08040000-0x0817FFFF (512k) M4 application
Flashing an application to ARDUINO OPTA M7
------------------------------------------
First, connect the device to your host computer using
the USB port to prepare it for flashing. Then build and flash your application.
Here is an example for the :zephyr:code-sample:`blinky` application on M7 core.
.. zephyr-app-commands::
:zephyr-app: samples/basic/blinky
:board: arduino_opta/stm32h747xx/m7
:goals: build flash
Flashing an application to ARDUINO OPTA M4
------------------------------------------
@ -141,6 +196,9 @@ Here is an example for the :zephyr:code-sample:`blinky` application on M4 core.
Starting the application on the ARDUINO OPTA M4
-----------------------------------------------
If you also flashed an application to M7 the M4 processor is started at boot.
If not you will need to start the processor from an Arduino sketch.
Make sure the option bytes are set to prevent the M4 from auto-starting, and
that the M7 side starts the M4 at the correct Flash address.
@ -161,8 +219,9 @@ at least the following code:
Debugging
=========
Debugging is not yet supported by this board, since the debug port does
not have an easy access.
The debug port does not have an easy access but it is possible to open the
case and solder a standard 10-pin SWD connector to the board. After that
both flashing and debugging are available via ST-LINK (M7 core only).
.. _ARDUINO-OPTA website:
https://docs.arduino.cc/hardware/opta

View file

@ -0,0 +1,16 @@
# Copyright (c) 2024 DNDG srl
# SPDX-License-Identifier: Apache-2.0
description: |
This allows to define a group of relays (like in the original Opta)
or other kinds of power switches controlled by a GPIO. Each power
switch is defined in a child node of the gpio-power-switches node.
compatible: "gpio-power-switches"
child-binding:
description: GPIO power switch child node
properties:
gpios:
type: phandle-array
required: true

View file

@ -0,0 +1,28 @@
source [find interface/stlink.cfg]
transport select hla_swd
source [find target/stm32h7x.cfg]
# Use connect_assert_srst here to be able to program
# even when core is in sleep mode
reset_config srst_only srst_nogate connect_assert_srst
$_CHIPNAME.cpu0 configure -event gdb-attach {
echo "Debugger attaching: halting execution"
gdb_breakpoint_override hard
}
$_CHIPNAME.cpu0 configure -event gdb-detach {
echo "Debugger detaching: resuming execution"
resume
}
# Due to the use of connect_assert_srst, running gdb requires
# to reset halt just after openocd init.
rename init old_init
proc init {} {
old_init
reset halt
}