From 3eaffdc74ac5a9752c2ce43e580a738ce7746cbe Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Thu, 27 Mar 2025 07:07:21 -0700 Subject: [PATCH] Portenta H7: SPI, WIre, PWM, ADC, Video as wip This is a replacement for PR: #71 and #82. All of the earlier commits were squashed into one. Then this was converted a few times during the #85 pr time frame as things kept changing and moving around. It has now been updated to the released .3 version. We defined the additional SPI ports and Wire ports. We defined an initial setup for Analog pins. Have similar hack to GIGA version for pure Analog. Added additional hacks for duplicated pins. That is two of the analog Pins are the exact same pin as some other digital pins... Added some PWM support. Also added WIP: camera support. Co-Authored-By: Mike S <5366213+mjs513@users.noreply.github.com> --- .../arduino_portenta_h7_stm32h747xx_m7.conf | 21 +- ...arduino_portenta_h7_stm32h747xx_m7.overlay | 327 +++++++++++++++++- .../pure_analog_pins.cpp | 23 ++ .../pure_analog_pins.h | 62 ++++ .../variant.h | 1 + 5 files changed, 413 insertions(+), 21 deletions(-) create mode 100644 variants/arduino_portenta_h7_stm32h747xx_m7/pure_analog_pins.cpp create mode 100644 variants/arduino_portenta_h7_stm32h747xx_m7/pure_analog_pins.h diff --git a/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.conf b/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.conf index acee48b1..b0d99951 100644 --- a/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.conf +++ b/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.conf @@ -11,6 +11,9 @@ CONFIG_CDC_ACM_DTE_RATE_CALLBACK_SUPPORT=y CONFIG_LLEXT_STORAGE_WRITABLE=n +CONFIG_SHARED_MULTI_HEAP=y +CONFIG_HEAP_MEM_POOL_SIZE=2048 + CONFIG_FPU=y CONFIG_ICACHE=y CONFIG_DCACHE=y @@ -24,8 +27,12 @@ CONFIG_SHELL_STACK_SIZE=32768 CONFIG_MAIN_STACK_SIZE=32768 CONFIG_LLEXT_HEAP_SIZE=128 -#CONFIG_ADC=y -#CONFIG_PWM=y +CONFIG_ADC=y +CONFIG_PWM=y +CONFIG_DMA=y +CONFIG_MEMC=y +CONFIG_SPI_ASYNC=y +CONFIG_SPI_STM32_INTERRUPT=y CONFIG_NET_CORE_LOG_LEVEL_DBG=y @@ -78,3 +85,13 @@ CONFIG_MBEDTLS_HEAP_SIZE=60000 CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=7168 CONFIG_MBEDTLS_HASH_ALL_ENABLED=y CONFIG_MBEDTLS_CMAC=y + +CONFIG_VIDEO=y +CONFIG_VIDEO_LOG_LEVEL_DBG=y +CONFIG_VIDEO_STM32_DCMI=y +CONFIG_VIDEO_BUFFER_POOL_NUM_MAX=3 +CONFIG_VIDEO_BUFFER_POOL_SZ_MAX=614400 +CONFIG_VIDEO_BUFFER_POOL_ALIGN=32 +CONFIG_VIDEO_BUFFER_USE_SHARED_MULTI_HEAP=y +CONFIG_VIDEO_BUFFER_SMH_ATTRIBUTE=2 +CONFIG_FLASH=y diff --git a/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.overlay b/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.overlay index 88485a23..ba7e1684 100644 --- a/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.overlay +++ b/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.overlay @@ -14,20 +14,253 @@ status = "okay"; }; +&i2c3 { + status = "okay"; + + gc2145: gc2145@3c { + compatible = "galaxycore,gc2145"; + reg = <0x3c>; + status = "okay"; + + reset-gpios = <&gpioe 3 GPIO_ACTIVE_LOW>; + pwdn-gpios = <&gpiod 5 GPIO_ACTIVE_LOW>; + + port { + gc2145_ep_out: endpoint { + remote-endpoint = <&dcmi_ep_in>; + }; + }; + }; + + ov7670: ov7670@21 { + compatible = "ovti,ov7670"; + reg = <0x21>; + + reset-gpios = <&gpioe 3 GPIO_ACTIVE_LOW>; + pwdn-gpios = <&gpiod 5 GPIO_ACTIVE_LOW>; + + port { + ov7670_ep_out: endpoint { + remote-endpoint = <&dcmi_ep_in>; + }; + }; + }; +}; + +&i2c1 { + status = "okay"; +}; + &i2c4 { status = "okay"; }; +&spi2 { + status = "okay"; + pinctrl-0 = <&spi2_sck_pi1 + &spi2_miso_pc2 &spi2_mosi_pc3>; + pinctrl-names = "default"; +}; + +&timers1 { + status = "okay"; + st,prescaler = <0>; + + pwm1: pwm { + status = "okay"; + pinctrl-0 = <&tim1_ch1_pa8 &tim1_ch2_pj11>; + pinctrl-names = "default"; + }; +}; + +&timers3 { + status = "okay"; + st,prescaler = <100>; + + pwm3: pwm { + status = "okay"; + pinctrl-0 = <&tim3_ch1_pc6 &tim3_ch2_pc7>; + pinctrl-names = "default"; + }; +}; + +&timers8 { + status = "okay"; + st,prescaler = <100>; + + pwm8: pwm { + status = "okay"; + pinctrl-0 = <&tim8_ch3n_ph15 &tim8_ch2_pj10 &tim8_ch2n_pj7>; + pinctrl-names = "default"; + }; +}; + +&timers12 { + status = "okay"; + st,prescaler = <100>; + + pwm12: pwm { + status = "okay"; + pinctrl-0 = <&tim12_ch1_ph6>; + pinctrl-names = "default"; + }; +}; + +&pwm1 { + /* Camera source clock */ + pwmclock: pwmclock { + status = "okay"; + compatible = "pwm-clock"; + clock-frequency = <0>; + #clock-cells = <1>; + pwms = <&pwm1 1 PWM_HZ(12000000) PWM_POLARITY_NORMAL>; + /* 12MHz for 7670, default is also 12MHz */ + }; +}; + &rng { status = "okay"; }; +&dmamux1 { + status = "okay"; +}; + +&dma1 { + status = "okay"; +}; + +&dcmi { + status = "okay"; + sensor = <&gc2145>; + /* sensor = <&ov7670>; */ + /* ext-sdram = <&sdram1>; */ + pinctrl-0 = <&dcmi_hsync_pa4 &dcmi_pixclk_pa6 &dcmi_vsync_pi5 + &dcmi_d0_ph9 &dcmi_d1_ph10 &dcmi_d2_ph11 &dcmi_d3_ph12 + &dcmi_d4_ph14 &dcmi_d5_pi4 &dcmi_d6_pi6 &dcmi_d7_pi7>; + pinctrl-names = "default"; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <0>; + pixelclk-active = <0>; + capture-rate = <1>; + dmas = <&dma1 0 75 (STM32_DMA_PERIPH_TO_MEMORY | STM32_DMA_PERIPH_NO_INC | + STM32_DMA_MEM_INC | STM32_DMA_PERIPH_32BITS | STM32_DMA_MEM_32BITS | + STM32_DMA_PRIORITY_HIGH) STM32_DMA_FIFO_FULL>; //FULL for 7670, default FIFO_1_4 + + port { + dcmi_ep_in: endpoint { + remote-endpoint = <&gc2145_ep_out>; + //remote-endpoint = <&ov7670_ep_out>; + }; + }; +}; + + +&adc1 { + pinctrl-0 = <&adc1_inp12_pc2 + &adc1_inp13_pc3 + &adc1_inp18_pa4 + &adc1_inp3_pa6 + &adc1_inp0_pa0_c + &adc1_inp1_pa1_c>; + pinctrl-names = "default"; + st,adc-clock-source = "SYNC"; + st,adc-prescaler = <4>; + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + + channel@c { + reg = <12>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <16>; + }; + channel@d { + reg = <13>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <16>; + }; + channel@12 { + reg = <18>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <16>; + }; + channel@3 { + reg = <3>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <16>; + }; + + /* PA0_C and PA1_C */ + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <16>; + }; + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <16>; + }; +}; + +&adc3 { + pinctrl-0 = <&adc3_inp0_pc2_c + &adc3_inp1_pc3_c>; + pinctrl-names = "default"; + st,adc-clock-source = "SYNC"; + st,adc-prescaler = <4>; + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <16>; + }; + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <16>; + }; +}; + / { chosen { + zephyr,camera = &dcmi; zephyr,console = &usart6; zephyr,shell-uart = &usart6; zephyr,cdc-acm-uart0 = &usart6; }; + + /* used to overcome problems with _C analog pins */ + gpioz: gpio@deadbeef { + compatible = "vnd,gpio"; + gpio-controller; + reg = <0xdeadbeef 0x1000>; + #gpio-cells = <0x2>; + status = "okay"; + }; }; / { @@ -59,29 +292,85 @@ / { zephyr,user { - digital-pin-gpios = <&gpioh 15 GPIO_ACTIVE_LOW>, - <&gpiok 1 GPIO_ACTIVE_LOW>, - <&gpioj 11 GPIO_ACTIVE_LOW>, - <&gpiog 7 GPIO_ACTIVE_LOW>, - <&gpioc 7 GPIO_ACTIVE_LOW>, - <&gpioc 6 GPIO_ACTIVE_LOW>, - <&gpioa 8 GPIO_ACTIVE_LOW>, - <&gpioi 0 GPIO_ACTIVE_LOW>, - <&gpioc 3 GPIO_ACTIVE_LOW>, - <&gpioi 1 GPIO_ACTIVE_LOW>, - <&gpioc 2 GPIO_ACTIVE_LOW>, - <&gpioh 8 GPIO_ACTIVE_LOW>, - <&gpioh 7 GPIO_ACTIVE_LOW>, - <&gpioa 10 GPIO_ACTIVE_LOW>, - <&gpioa 9 GPIO_ACTIVE_LOW>, - <&gpiok 5 GPIO_ACTIVE_LOW>; // LEDR + digital-pin-gpios = <&gpioh 15 GPIO_ACTIVE_LOW>, /* D0 */ + <&gpiok 1 GPIO_ACTIVE_LOW>, /* D1 */ + <&gpioj 11 GPIO_ACTIVE_LOW>, /* D2 */ + <&gpiog 7 GPIO_ACTIVE_LOW>, /* D3 */ + <&gpioc 7 GPIO_ACTIVE_LOW>, /* D4 */ + <&gpioc 6 GPIO_ACTIVE_LOW>, /* D5 */ + <&gpioa 8 GPIO_ACTIVE_LOW>, /* D6 */ + <&gpioi 0 GPIO_ACTIVE_LOW>, /* D7 */ + <&gpioc 3 GPIO_ACTIVE_LOW>, /* D8 */ + <&gpioi 1 GPIO_ACTIVE_LOW>, /* D9 */ + <&gpioc 2 GPIO_ACTIVE_LOW>, /* D10 */ + <&gpioh 8 GPIO_ACTIVE_LOW>, /* D11 */ + <&gpioh 7 GPIO_ACTIVE_LOW>, /* D12 */ + <&gpioa 10 GPIO_ACTIVE_LOW>, /* D13 */ + <&gpioa 9 GPIO_ACTIVE_LOW>, /* D14 */ + + <&gpioz 0 GPIO_ACTIVE_LOW>, /* A0 ADC2_INP0 */ + <&gpioz 1 GPIO_ACTIVE_LOW>, /* A1 ADC2_INP1 */ + <&gpioz 2 GPIO_ACTIVE_LOW>, /* A2 ADC3_INP0 */ + <&gpioz 3 GPIO_ACTIVE_LOW>, /* A3 ADC3_INP1 */ + <&gpioz 4 GPIO_ACTIVE_LOW>, /* A4 hack for duplicate PC_2 */ + <&gpioz 5 GPIO_ACTIVE_LOW>, /* A5 hack for duplicate PC_3 */ + /* <&gpioc 2 GPIO_ACTIVE_LOW>, A4 _ALT0? ADC1_INP12 */ + /* <&gpioc 3 GPIO_ACTIVE_LOW>, A5 _ALT0? ADC1_INP13 */ + <&gpioa 4 GPIO_ACTIVE_LOW>, /* A6 ADC1_INP18 */ + <&gpioa 6 GPIO_ACTIVE_LOW>, /* A7 ADC1_INP7 */ + + <&gpiok 5 GPIO_ACTIVE_LOW>, /* LEDR */ + <&gpiok 6 GPIO_ACTIVE_LOW>, /* LEDG */ + <&gpiok 7 GPIO_ACTIVE_LOW>; /* LEDB */ builtin-led-gpios = <&gpiok 5 GPIO_ACTIVE_LOW>, - <&gpiok 6 GPIO_ACTIVE_LOW>, - <&gpiok 7 GPIO_ACTIVE_LOW>; + <&gpiok 6 GPIO_ACTIVE_LOW>, + <&gpiok 7 GPIO_ACTIVE_LOW>; + + pwm-pin-gpios = <&gpioa 8 0>, + <&gpioc 6 0>, + <&gpioc 7 0>, + //<&gpiog 7 0>, + <&gpioj 11 0>, + //<&gpiok 1 0>, + <&gpioh 15 0>, + <&gpioj 7 0>, + <&gpioj 10 0>, + <&gpioh 6 0>; + + adc-pin-gpios = <&gpioz 0 0>, /* analog only */ + <&gpioz 1 0>, /* analog only */ + <&gpioz 2 0>, /* analog only */ + <&gpioz 3 0>, /* analog only */ + <&gpioc 2 0>, + <&gpioc 3 0>, + <&gpioa 4 0>, + <&gpioa 6 0>, + <&gpioz 4 0>, /* Hack for D19 */ + <&gpioz 5 0>; /* Hack for D20 */ serials = <&board_cdc_acm_uart>,<&usart6>, <&usart1>, <&uart4>; cdc-acm = <&board_cdc_acm_uart>; - i2cs = <&i2c4>; + i2cs = <&i2c3>, <&i2c1>, <&i2c4>; + spis = <&spi2>; + pwms = <&pwm1 1 PWM_HZ(12000000) PWM_POLARITY_NORMAL>, /* Camera */ + <&pwm3 1 PWM_HZ(500) PWM_POLARITY_NORMAL>, + <&pwm3 2 PWM_HZ(500) PWM_POLARITY_NORMAL>, + <&pwm1 2 PWM_HZ(5000) PWM_POLARITY_NORMAL>, + <&pwm8 3 PWM_HZ(500) PWM_POLARITY_INVERTED>, + <&pwm8 2 PWM_HZ(500) PWM_POLARITY_INVERTED>, + <&pwm8 2 PWM_HZ(500) PWM_POLARITY_NORMAL>, + <&pwm12 1 PWM_HZ(500) PWM_POLARITY_NORMAL>; + + io-channels = <&adc1 0>, + <&adc1 1>, + <&adc3 0>, + <&adc3 1>, + <&adc1 12>, + <&adc1 13>, + <&adc1 18>, + <&adc1 3>, + <&adc1 12>, /* Hack for D19 */ + <&adc1 13>; /* Hack for D20 */ }; }; diff --git a/variants/arduino_portenta_h7_stm32h747xx_m7/pure_analog_pins.cpp b/variants/arduino_portenta_h7_stm32h747xx_m7/pure_analog_pins.cpp new file mode 100644 index 00000000..a6ba41b2 --- /dev/null +++ b/variants/arduino_portenta_h7_stm32h747xx_m7/pure_analog_pins.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "pure_analog_pins.h" + +#undef A0 +#undef A1 +#undef A2 +#undef A3 + +PureAnalogPin A0_PURE(0); +PureAnalogPin A1_PURE(1); +PureAnalogPin A2_PURE(2); +PureAnalogPin A3_PURE(3); + +int getAnalogReadResolution(); + +int analogRead(PureAnalogPin pin) { + return ::analogRead(A0 + pin.get()); +} diff --git a/variants/arduino_portenta_h7_stm32h747xx_m7/pure_analog_pins.h b/variants/arduino_portenta_h7_stm32h747xx_m7/pure_analog_pins.h new file mode 100644 index 00000000..9df13056 --- /dev/null +++ b/variants/arduino_portenta_h7_stm32h747xx_m7/pure_analog_pins.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _PURE_ANALOG_PINS_ +#define _PURE_ANALOG_PINS_ + +/****************************************************************************** + * INCLUDE + ******************************************************************************/ + +#include "Arduino.h" + +/****************************************************************************** + * PREPROCESSOR-MAGIC + ******************************************************************************/ + +#define PURE_ANALOG_AS_DIGITAL_ATTRIBUTE __attribute__ ((error("Can't use pins A0-A3 as digital"))) + +/****************************************************************************** + * TYPEDEF + ******************************************************************************/ + +class PureAnalogPin { +public: + PureAnalogPin(int _pin) : pin(_pin) {}; + int get() { + return pin; + }; + bool operator== (PureAnalogPin const & other) const { + return pin == other.pin; + } + //operator int() = delete; + __attribute__ ((error("Change me to a #define"))) operator int(); +private: + int pin; +}; + +extern PureAnalogPin A0_PURE; +extern PureAnalogPin A1_PURE; +extern PureAnalogPin A2_PURE; +extern PureAnalogPin A3_PURE; + +#define A0 A0_PURE +#define A1 A1_PURE +#define A2 A2_PURE +#define A3 A3_PURE + +/****************************************************************************** + * FUNCTION DECLARATION + ******************************************************************************/ + +void PURE_ANALOG_AS_DIGITAL_ATTRIBUTE pinMode (PureAnalogPin pin, PinMode mode); +PinStatus PURE_ANALOG_AS_DIGITAL_ATTRIBUTE digitalRead (PureAnalogPin pin); +void PURE_ANALOG_AS_DIGITAL_ATTRIBUTE digitalWrite(PureAnalogPin pin, PinStatus value); +int analogRead (PureAnalogPin pin); +void PURE_ANALOG_AS_DIGITAL_ATTRIBUTE analogWrite (PureAnalogPin pin, int value); + +#undef PURE_ANALOG_AS_DIGITAL_ATTRIBUTE + +#endif /* _PURE_ANALOG_PINS_ */ diff --git a/variants/arduino_portenta_h7_stm32h747xx_m7/variant.h b/variants/arduino_portenta_h7_stm32h747xx_m7/variant.h index 68c33a89..9c1abf2e 100644 --- a/variants/arduino_portenta_h7_stm32h747xx_m7/variant.h +++ b/variants/arduino_portenta_h7_stm32h747xx_m7/variant.h @@ -3,6 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include "pure_analog_pins.h" // TODO: correctly handle these legacy defines #define MOSI 0