From ede3ab18896cd9a9a96d82c657004159fb3a55e3 Mon Sep 17 00:00:00 2001 From: vrmay23 Date: Sun, 15 Feb 2026 15:59:53 +0100 Subject: [PATCH] boards/arm/stm32h7: Add support for ST Nucleo-H753ZI board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add board support for the ST Nucleo-H753ZI (MB1364) development board featuring the STM32H753ZIT6 microcontroller (Arm Cortex-M7, 2 MB Flash, 1 MB RAM). This port was initially based on the linum-stm32h753bi board support, with a corrected clock tree and a substantially redesigned board architecture aimed at improving usability, scalability, and maintainability. Clock Tree ---------- Both HSE configurations (8 MHz ST-LINK MCO and 25 MHz external crystal) produce identical system performance: SYSCLK = 400 MHz (VOS1), HCLK = 200 MHz, PCLK = 100 MHz The original linum-based clock tree was corrected to fix PLL input range registers, VCO frequency calculations, and peripheral kernel clock assignments. FDCAN kernel clock is 25 MHz in both configurations (PLL2Q for 8 MHz HSE; HSE direct for 25 MHz HSE), ensuring compliance with standard CAN bitrates (125/250/500 kbps, 1 Mbps). Menuconfig-Driven Architecture ------------------------------- The central design goal of this port is to make NuttX more approachable for developers working with real hardware. The intent is to expose as many hardware options as practical through Kconfig/menuconfig, reducing the need to manually edit source files for routine board bring-up tasks. This is a proposed direction that could establish a new pattern for NuttX board ports -- one that prioritizes developer agility and user-friendliness alongside the existing coding standards. This is a deliberate departure from the pattern found in most existing NuttX board ports, where pin assignments, bus selections, and peripheral options are hardcoded. The intent is not to break convention for its own sake, but to demonstrate that a menuconfig-driven board layer reduces friction substantially -- particularly for developers new to NuttX or porting it to derivative hardware. Specifically, this port provides menuconfig control over: - HSE clock source (8 MHz ST-LINK MCO or 25 MHz external crystal) - SPI bus enable/disable and alternative pin set selection (SPI1-SPI6, 2-4 pin sets each); CS pins are registered per-peripheral at runtime - I2C bus enable/disable, alternative pin set selection (I2C1-I2C4, 2-5 pin sets each), and default bus frequency per bus; conflicting pin assignments (e.g. I2C1 pinset 1 vs I2C4 pinset 4) are prevented at compile time via Kconfig dependency rules - LED control mode: automatic (kernel OS state), user (/dev/userleds), or disabled - Button driver: number of buttons (1-32), built-in button (PC13) inclusion, additional button GPIO pins specified as a string (e.g. "PB1,PD0,PG4"), with compile-time EXTI conflict validation - ST7796 SPI LCD: bus, CS/DC/RESET/LED pins, CS polarity, color depth, orientation, rotation, SPI frequency, framebuffer size - MFRC522 RFID: bus, CS pin, CS polarity, IRQ pin, IRQ trigger type - SSD1306 OLED: bus, I2C address, frequency, brightness, resolution, device path Scope of This Port ------------------ This is not a minimal board port. Separating a clean minimal port from the full implementation was not practical at this stage, so the complete board support is submitted as-is -- following the same approach taken by the linum-stm32h753bi port. While the Nucleo-H753ZI is a development board rather than an OEM product, the port is fully functional: anyone with the hardware can build and run NuttX on it immediately using the provided configurations. Source Organization ------------------- The src/ directory uses a layered subdirectory structure to separate concerns and make the codebase easier to navigate and extend. This is a deliberate organizational choice that differs from the flat src/ layout common in other NuttX board ports. If the project prefers the traditional flat layout, all files can be moved directly into src/ with no functional changes required -- the Makefile and CMakeLists.txt are the only files that would need updating. src/ ├── stm32_boot.c ├── stm32_bringup.c ├── stm32_appinitialize.c ├── stm32_boot_image.c ├── nucleo-h753zi.h └── drivers/ ├── driver_bus/ (SPI, I2C bus initialization) ├── driver_generic/ (ADC, buttons, GPIO, PWM, LEDs) ├── driver_middleware/ (USB, ROMFS, progmem, autoleds, UID) └── driver_modules/ (peripheral drivers: displays, sensors, wireless, storage) Supported Peripheral Modules ----------------------------- - ST7796 SPI LCD 320x480 IPS with framebuffer (/dev/fb0, LVGL-ready) - SSD1306 I2C OLED 128x64/128x32 - MFRC522 SPI RFID 13.56 MHz (/dev/rfid0) - NRF24L01 SPI 2.4 GHz transceiver - MMC/SD card over SPI - LSM6DSL, LSM303AGR, LSM9DS1 IMU sensors (I2C) - LPS22HB pressure sensor (I2C) - PCA9635 I2C LED controller - PWM output (TIM1, CH1-CH4 + complementary) - PROGMEM MTD, RTC, USB OTG FS (device/host), USB MSC, ROMFS Configurations -------------- nsh - NuttShell, user LEDs, GPIO driver button_driver - 11-button demo (PC13 + 10 external), IRQ-driven, auto LEDs socketcan - FDCAN1 as SocketCAN, 500 kbps, candump/cansend Testing ------- The following drivers were validated on real hardware (Nucleo-H753ZI): - buttons (IRQ-driven, 11-button configuration) - leds (user and automatic modes) - gpio (/dev/gpioN) - mfrc522 (SPI RFID, /dev/rfid0) - socketcan (FDCAN1, 500 kbps, candump/cansend) - st7796 (SPI LCD, framebuffer, LVGL) - ssd1306 (I2C OLED) The ST7796 framebuffer driver (boards/.../stm32_st7796.c) and the FDCAN SocketCAN driver fix (arch/arm/src/stm32h7/stm32_fdcan_sock.c) were both developed and validated using this board. Signed-off-by: Vinicius May --- boards/Kconfig | 13 + .../arm/stm32h7/nucleo-h753zi/CMakeLists.txt | 23 + boards/arm/stm32h7/nucleo-h753zi/Kconfig | 1285 ++++++++++++++ .../configs/button_driver/defconfig | 70 + .../nucleo-h753zi/configs/nsh/defconfig | 54 + .../nucleo-h753zi/configs/socketcan/defconfig | 74 + .../arm/stm32h7/nucleo-h753zi/include/board.h | 1309 ++++++++++++++ .../stm32h7/nucleo-h753zi/include/readme.txt | 420 +++++ .../arm/stm32h7/nucleo-h753zi/kernel/Makefile | 94 + .../nucleo-h753zi/kernel/stm32_userspace.c | 102 ++ .../stm32h7/nucleo-h753zi/scripts/Make.defs | 50 + .../scripts/flash-mcuboot-app.ld | 203 +++ .../scripts/flash-mcuboot-loader.ld | 203 +++ .../stm32h7/nucleo-h753zi/scripts/flash.ld | 203 +++ .../nucleo-h753zi/scripts/kernel.space.ld | 112 ++ .../stm32h7/nucleo-h753zi/scripts/memory.ld | 54 + .../nucleo-h753zi/scripts/user-space.ld | 101 ++ .../stm32h7/nucleo-h753zi/src/CMakeLists.txt | 127 ++ boards/arm/stm32h7/nucleo-h753zi/src/Makefile | 107 ++ .../stm32h7/nucleo-h753zi/src/nucleo-h753zi.h | 1236 +++++++++++++ .../arm/stm32h7/nucleo-h753zi/src/stm32_adc.c | 270 +++ .../nucleo-h753zi/src/stm32_appinitialize.c | 78 + .../nucleo-h753zi/src/stm32_autoleds.c | 179 ++ .../stm32h7/nucleo-h753zi/src/stm32_boot.c | 93 + .../nucleo-h753zi/src/stm32_boot_image.c | 185 ++ .../stm32h7/nucleo-h753zi/src/stm32_bringup.c | 1547 +++++++++++++++++ .../stm32h7/nucleo-h753zi/src/stm32_buttons.c | 806 +++++++++ .../nucleo-h753zi/src/stm32_composite.c | 349 ++++ .../stm32h7/nucleo-h753zi/src/stm32_gpio.c | 953 ++++++++++ .../arm/stm32h7/nucleo-h753zi/src/stm32_i2c.c | 646 +++++++ .../nucleo-h753zi/src/stm32_lsm303agr.c | 85 + .../stm32h7/nucleo-h753zi/src/stm32_lsm6dsl.c | 91 + .../stm32h7/nucleo-h753zi/src/stm32_lsm9ds1.c | 107 ++ .../stm32h7/nucleo-h753zi/src/stm32_mfrc522.c | 270 +++ .../stm32h7/nucleo-h753zi/src/stm32_mmcsd.c | 90 + .../nucleo-h753zi/src/stm32_nrf24l01.c | 123 ++ .../stm32h7/nucleo-h753zi/src/stm32_pca9635.c | 84 + .../stm32h7/nucleo-h753zi/src/stm32_progmem.c | 254 +++ .../arm/stm32h7/nucleo-h753zi/src/stm32_pwm.c | 110 ++ .../stm32h7/nucleo-h753zi/src/stm32_reset.c | 64 + .../stm32h7/nucleo-h753zi/src/stm32_romfs.h | 63 + .../src/stm32_romfs_initialize.c | 139 ++ .../arm/stm32h7/nucleo-h753zi/src/stm32_spi.c | 1037 +++++++++++ .../stm32h7/nucleo-h753zi/src/stm32_ssd1306.c | 760 ++++++++ .../stm32h7/nucleo-h753zi/src/stm32_st7796.c | 700 ++++++++ .../arm/stm32h7/nucleo-h753zi/src/stm32_uid.c | 69 + .../arm/stm32h7/nucleo-h753zi/src/stm32_usb.c | 322 ++++ .../stm32h7/nucleo-h753zi/src/stm32_usbmsc.c | 61 + .../nucleo-h753zi/src/stm32_userleds.c | 129 ++ 49 files changed, 15504 insertions(+) create mode 100644 boards/arm/stm32h7/nucleo-h753zi/CMakeLists.txt create mode 100644 boards/arm/stm32h7/nucleo-h753zi/Kconfig create mode 100644 boards/arm/stm32h7/nucleo-h753zi/configs/button_driver/defconfig create mode 100644 boards/arm/stm32h7/nucleo-h753zi/configs/nsh/defconfig create mode 100644 boards/arm/stm32h7/nucleo-h753zi/configs/socketcan/defconfig create mode 100644 boards/arm/stm32h7/nucleo-h753zi/include/board.h create mode 100644 boards/arm/stm32h7/nucleo-h753zi/include/readme.txt create mode 100644 boards/arm/stm32h7/nucleo-h753zi/kernel/Makefile create mode 100644 boards/arm/stm32h7/nucleo-h753zi/kernel/stm32_userspace.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/scripts/Make.defs create mode 100644 boards/arm/stm32h7/nucleo-h753zi/scripts/flash-mcuboot-app.ld create mode 100644 boards/arm/stm32h7/nucleo-h753zi/scripts/flash-mcuboot-loader.ld create mode 100644 boards/arm/stm32h7/nucleo-h753zi/scripts/flash.ld create mode 100644 boards/arm/stm32h7/nucleo-h753zi/scripts/kernel.space.ld create mode 100644 boards/arm/stm32h7/nucleo-h753zi/scripts/memory.ld create mode 100644 boards/arm/stm32h7/nucleo-h753zi/scripts/user-space.ld create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/CMakeLists.txt create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/Makefile create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/nucleo-h753zi.h create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_adc.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_appinitialize.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_autoleds.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_boot.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_boot_image.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_bringup.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_buttons.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_composite.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_gpio.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_i2c.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_lsm303agr.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_lsm6dsl.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_lsm9ds1.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_mfrc522.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_mmcsd.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_nrf24l01.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_pca9635.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_progmem.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_pwm.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_reset.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_romfs.h create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_romfs_initialize.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_spi.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_ssd1306.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_st7796.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_uid.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_usb.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_usbmsc.c create mode 100644 boards/arm/stm32h7/nucleo-h753zi/src/stm32_userleds.c diff --git a/boards/Kconfig b/boards/Kconfig index e84a90b2d57e6..36ba935921353 100644 --- a/boards/Kconfig +++ b/boards/Kconfig @@ -1916,6 +1916,15 @@ config ARCH_BOARD_NUCLEO_H743ZI ---help--- STMicro Nucleo H743ZI board based on the STMicro STM32H743ZI MCU. +config ARCH_BOARD_NUCLEO_H753ZI + bool "STM32H753 Nucleo H753ZI" + depends on ARCH_CHIP_STM32H753ZI + select ARCH_HAVE_LEDS + select ARCH_HAVE_BUTTONS + select ARCH_HAVE_IRQBUTTONS + ---help--- + STMicro Nucleo H753ZI board based on the STMicro STM32H753ZI MCU. + config ARCH_BOARD_NUCLEO_H743ZI2 bool "STM32H743 Nucleo H743ZI2" depends on ARCH_CHIP_STM32H743ZI @@ -3690,6 +3699,7 @@ config ARCH_BOARD default "weact-stm32h743" if ARCH_BOARD_WEACT_STM32H743 default "weact-stm32h750" if ARCH_BOARD_WEACT_STM32H750 default "nucleo-h743zi" if ARCH_BOARD_NUCLEO_H743ZI + default "nucleo-h753zi" if ARCH_BOARD_NUCLEO_H753ZI default "nucleo-h743zi2" if ARCH_BOARD_NUCLEO_H743ZI2 default "nucleo-h745zi" if ARCH_BOARD_NUCLEO_H745ZI default "stm32h745i-disco" if ARCH_BOARD_STM32H745I_DISCO @@ -4425,6 +4435,9 @@ endif if ARCH_BOARD_NUCLEO_H743ZI source "boards/arm/stm32h7/nucleo-h743zi/Kconfig" endif +if ARCH_BOARD_NUCLEO_H753ZI +source "boards/arm/stm32h7/nucleo-h753zi/Kconfig" +endif if ARCH_BOARD_NUCLEO_H743ZI2 source "boards/arm/stm32h7/nucleo-h743zi2/Kconfig" endif diff --git a/boards/arm/stm32h7/nucleo-h753zi/CMakeLists.txt b/boards/arm/stm32h7/nucleo-h753zi/CMakeLists.txt new file mode 100644 index 0000000000000..694928209ac02 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/CMakeLists.txt @@ -0,0 +1,23 @@ +# ############################################################################## +# boards/arm/stm32h7/nucleo-h753zi/CMakeLists.txt +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. The ASF licenses this +# file to you under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# ############################################################################## + +add_subdirectory(src) diff --git a/boards/arm/stm32h7/nucleo-h753zi/Kconfig b/boards/arm/stm32h7/nucleo-h753zi/Kconfig new file mode 100644 index 0000000000000..2b5c1f70b9649 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/Kconfig @@ -0,0 +1,1285 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +menu "Board Clock Configuration" + +choice + prompt "HSE clock source" + default NUCLEO_H753ZI_HSE_8MHZ + help + Select the HSE clock source for the Nucleo-H753ZI board. + 8 MHz: ST-LINK MCO (default, no hardware modification) + 25 MHz: External crystal X3 (requires hardware modification) + +config NUCLEO_H753ZI_HSE_8MHZ + bool "8 MHz from ST-LINK MCO" + help + Default Nucleo-H753ZI configuration. + Uses 8 MHz clock from ST-LINK MCO output (PH0-OSC_IN). + Solder Bridge Configuration: + SB45=ON, SB44=OFF, SB46=OFF, SB3=OFF, SB4=OFF + This is the factory default - no hardware changes needed. + System clocks with 8 MHz HSE: + - SYSCLK: 400 MHz + - HCLK: 200 MHz + - APB1/2/3/4: 100 MHz + - FDCAN: 25 MHz (via PLL2Q) + +config NUCLEO_H753ZI_HSE_25MHZ + bool "25 MHz external crystal X3" + help + Uses 25 MHz external crystal on X3 footprint. + Solder Bridge Configuration: + SB3=ON, SB4=ON, SB45=OFF, SB44=OFF, SB46=OFF + WARNING: Requires hardware modification: + - Install 25 MHz crystal at X3 footprint + - Reconfigure solder bridges as indicated above + System clocks with 25 MHz HSE: + - SYSCLK: 400 MHz + - HCLK: 200 MHz + - APB1/2/3/4: 100 MHz + - FDCAN: 25 MHz (direct from HSE) + +endchoice + +config STM32H7_BOARD_HSE_FREQUENCY + int + default 8000000 if NUCLEO_H753ZI_HSE_8MHZ + default 25000000 if NUCLEO_H753ZI_HSE_25MHZ + depends on STM32H7_HSE + +endmenu + +config NUCLEO_H753ZI_GPIO_DRIVER + bool "Enable Nucleo H753ZI board GPIO driver" + default n + select DEV_GPIO + help + This option enables the low-level GPIO driver for the + Nucleo H753ZI board. Other features like buttons or LEDs + will depend on this driver. + +choice + prompt "LED Control Mode" + default NUCLEO_H753ZI_LEDS_AUTO + help + Select how the onboard LEDs should be controlled. + +config NUCLEO_H753ZI_LEDS_AUTO + bool "Automatic LEDs (Kernel controlled)" + help + LEDs are automatically controlled by the kernel to indicate + system status (boot stages, interrupts, panics, etc.). + The LEDs will show: + - GREEN: System ready, signals + - ORANGE: Heap allocation, IRQs + - RED: Assertions, panics, idle + NOTE: You still need to manually enable: + Board Selection -> Board LED Status support + +config NUCLEO_H753ZI_LEDS_USER + bool "User-controlled LEDs" + select USERLED + select USERLED_LOWER + select BOARD_LATE_INITIALIZE + help + LEDs are controlled by user applications via /dev/userleds. + Applications can turn individual LEDs on/off as needed. + Kernel status indication is disabled. + NOTE: You must manually disable: + Board Selection -> Board LED Status support (to avoid + conflicts) + +config NUCLEO_H753ZI_LEDS_DISABLED + bool "LEDs disabled" + help + LED functionality is completely disabled to save resources. + NOTE: You should manually disable: + Board Selection -> Board LED Status support + +endchoice + +menu "Button Configuration" + +config NUCLEO_H753ZI_BUTTON_SUPPORT + bool "Enable button support" + default n + select ARCH_BUTTONS + help + Enable GPIO button support for the Nucleo-H753ZI board. + +config NUCLEO_H753ZI_BUTTON_COUNT + int "Number of buttons" + depends on NUCLEO_H753ZI_BUTTON_SUPPORT + default 1 + range 1 32 + help + Total number of buttons to configure (1-32). + The STM32H7 button driver supports up to 32 buttons using + a 32-bit bitmask for button states. + +config NUCLEO_H753ZI_BUTTON_BUILTIN + bool "Include built-in user button (PC13)" + depends on NUCLEO_H753ZI_BUTTON_SUPPORT + default y + help + Include the built-in blue user button connected to PC13. + This button will always be assigned as button index 0. + If enabled, you need (BUTTON_COUNT - 1) additional pins. + If disabled, you need exactly BUTTON_COUNT pins. + +config NUCLEO_H753ZI_BUTTON_PINS + string "Button GPIO pin list" + depends on NUCLEO_H753ZI_BUTTON_SUPPORT + default "" + help + Comma-separated list of GPIO pins for buttons. + Format: PORT+PIN (e.g., "PF15,PG14,PG9,PE0,PA0,PB12") + Number of pins required: + - With built-in: (BUTTON_COUNT - 1) pins + - Without built-in: BUTTON_COUNT pins + Example for 5 buttons with built-in enabled: + "PF15,PG14,PG9,PE0" + Common Nucleo-H753ZI pins: + Arduino Headers: PF15(D2), PG14(D1), PG9(D0), PE0(D34) + Morpho Headers: PA0-PA15, PB0-PB15, PC0-PC15, PD0-PD15, + PE0-PE15, PF0-PF15, PG0-PG15, PH0-PH1 + Note: All buttons assume pull-down resistor configuration. + +config NUCLEO_H753ZI_BUTTON_VALIDATION + bool "Validate pin configuration at compile time" + depends on NUCLEO_H753ZI_BUTTON_SUPPORT + default y + help + Perform compile-time validation of GPIO pin assignments. + +endmenu + +menu "SPI Configuration" + depends on STM32H7_SPI + +comment "SPI interfaces now use per-sensor CS registration system" +comment "No CS pins configured at SPI level - sensors register their own CS pins" + +if STM32H7_SPI1 + +menu "SPI1 Configuration" + +config NUCLEO_H753ZI_SPI1_ENABLE + bool "Enable SPI1" + default n + help + Enable SPI1 with configurable pins. + CS pins are now registered per-sensor. + +choice + prompt "SPI1 Pin Set" + depends on NUCLEO_H753ZI_SPI1_ENABLE + default NUCLEO_H753ZI_SPI1_PINSET_1 + help + Select which set of pins to use for SPI1. + Choose based on availability and board layout. + +config NUCLEO_H753ZI_SPI1_PINSET_1 + bool "Pin Set 1: PA5(SCK), PA6(MISO), PA7(MOSI)" + help + SPI1 Pin Set 1 (Arduino SPI connector compatible): + - SCK: PA5 (D13 - Arduino SCK) + - MISO: PA6 (D12 - Arduino MISO) + - MOSI: PA7 (D11 - Arduino MOSI) + This is the standard Arduino SPI pinout. + +config NUCLEO_H753ZI_SPI1_PINSET_2 + bool "Pin Set 2: PB3(SCK), PB4(MISO), PB5(MOSI)" + help + SPI1 Pin Set 2: + - SCK: PB3 + - MISO: PB4 + - MOSI: PB5 + +config NUCLEO_H753ZI_SPI1_PINSET_3 + bool "Pin Set 3: PG11(SCK), PG9(MISO), PD7(MOSI)" + help + SPI1 Pin Set 3: + - SCK: PG11 + - MISO: PG9 + - MOSI: PD7 + +endchoice + +endmenu + +endif + +if STM32H7_SPI2 + +menu "SPI2 Configuration" + +config NUCLEO_H753ZI_SPI2_ENABLE + bool "Enable SPI2" + default n + help + Enable SPI2 with configurable pins. + CS pins are now registered per-sensor. + +choice + prompt "SPI2 Pin Set" + depends on NUCLEO_H753ZI_SPI2_ENABLE + default NUCLEO_H753ZI_SPI2_PINSET_1 + help + Select which set of pins to use for SPI2. + +config NUCLEO_H753ZI_SPI2_PINSET_1 + bool "Pin Set 1: PB13(SCK), PB14(MISO), PB15(MOSI)" + help + SPI2 Pin Set 1: + - SCK: PB13 + - MISO: PB14 + - MOSI: PB15 + +config NUCLEO_H753ZI_SPI2_PINSET_2 + bool "Pin Set 2: PA12(SCK), PC2(MISO), PC1(MOSI)" + help + SPI2 Pin Set 2: + - SCK: PA12 + - MISO: PC2 + - MOSI: PC1 + +config NUCLEO_H753ZI_SPI2_PINSET_3 + bool "Pin Set 3: PD3(SCK), PC2(MISO), PC3(MOSI)" + help + SPI2 Pin Set 3: + - SCK: PD3 + - MISO: PC2 + - MOSI: PC3 + +endchoice + +endmenu + +endif + +if STM32H7_SPI3 + +menu "SPI3 Configuration" + +config NUCLEO_H753ZI_SPI3_ENABLE + bool "Enable SPI3" + default n + help + Enable SPI3 with configurable pins. + CS pins are now registered per-sensor. + +choice + prompt "SPI3 Pin Set" + depends on NUCLEO_H753ZI_SPI3_ENABLE + default NUCLEO_H753ZI_SPI3_PINSET_1 + help + Select which set of pins to use for SPI3. + +config NUCLEO_H753ZI_SPI3_PINSET_1 + bool "Pin Set 1: PC10(SCK), PC11(MISO), PC12(MOSI)" + help + SPI3 Pin Set 1: + - SCK: PC10 + - MISO: PC11 + - MOSI: PC12 + +config NUCLEO_H753ZI_SPI3_PINSET_2 + bool "Pin Set 2: PB3(SCK), PB4(MISO), PB5(MOSI)" + help + SPI3 Pin Set 2: + - SCK: PB3 + - MISO: PB4 + - MOSI: PB5 + +endchoice + +endmenu + +endif + +if STM32H7_SPI4 + +menu "SPI4 Configuration" + +config NUCLEO_H753ZI_SPI4_ENABLE + bool "Enable SPI4" + default n + help + Enable SPI4 with configurable pins. + CS pins are now registered per-sensor. + +choice + prompt "SPI4 Pin Set" + depends on NUCLEO_H753ZI_SPI4_ENABLE + default NUCLEO_H753ZI_SPI4_PINSET_1 + help + Select which set of pins to use for SPI4. + +config NUCLEO_H753ZI_SPI4_PINSET_1 + bool "Pin Set 1: PE12(SCK), PE13(MISO), PE14(MOSI)" + help + SPI4 Pin Set 1: + - SCK: PE12 + - MISO: PE13 + - MOSI: PE14 + +config NUCLEO_H753ZI_SPI4_PINSET_2 + bool "Pin Set 2: PE2(SCK), PE5(MISO), PE6(MOSI)" + help + SPI4 Pin Set 2: + - SCK: PE2 + - MISO: PE5 + - MOSI: PE6 + +endchoice + +endmenu + +endif + +if STM32H7_SPI5 + +menu "SPI5 Configuration" + +config NUCLEO_H753ZI_SPI5_ENABLE + bool "Enable SPI5" + default n + help + Enable SPI5 with configurable pins. + CS pins are now registered per-sensor. + +choice + prompt "SPI5 Pin Set" + depends on NUCLEO_H753ZI_SPI5_ENABLE + default NUCLEO_H753ZI_SPI5_PINSET_1 + help + Select which set of pins to use for SPI5. + +config NUCLEO_H753ZI_SPI5_PINSET_1 + bool "Pin Set 1: PF7(SCK), PF8(MISO), PF9(MOSI)" + help + SPI5 Pin Set 1: + - SCK: PF7 + - MISO: PF8 + - MOSI: PF9 + +config NUCLEO_H753ZI_SPI5_PINSET_2 + bool "Pin Set 2: PK0(SCK), PJ11(MISO), PJ10(MOSI)" + help + SPI5 Pin Set 2: + - SCK: PK0 + - MISO: PJ11 + - MOSI: PJ10 + +endchoice + +endmenu + +endif + +if STM32H7_SPI6 + +menu "SPI6 Configuration" + +config NUCLEO_H753ZI_SPI6_ENABLE + bool "Enable SPI6" + default n + help + Enable SPI6 with configurable pins. + CS pins are now registered per-sensor. + +choice + prompt "SPI6 Pin Set" + depends on NUCLEO_H753ZI_SPI6_ENABLE + default NUCLEO_H753ZI_SPI6_PINSET_1 + help + Select which set of pins to use for SPI6. + +config NUCLEO_H753ZI_SPI6_PINSET_1 + bool "Pin Set 1: PG13(SCK), PG12(MISO), PG14(MOSI)" + help + SPI6 Pin Set 1: + - SCK: PG13 + - MISO: PG12 + - MOSI: PG14 + +config NUCLEO_H753ZI_SPI6_PINSET_2 + bool "Pin Set 2: PA5(SCK), PA6(MISO), PA7(MOSI)" + help + SPI6 Pin Set 2: + - SCK: PA5 + - MISO: PA6 + - MOSI: PA7 + +endchoice + +endmenu + +endif + +endmenu + +menu "I2C Configuration" + depends on STM32H7_I2C + +config NUCLEO_H753ZI_I2C1_ENABLE + bool "Enable I2C1" + default n + depends on STM32H7_I2C1 + help + Enable I2C1 bus with configurable pinset selection. + +if NUCLEO_H753ZI_I2C1_ENABLE + +choice + prompt "I2C1 Pin Set" + default NUCLEO_H753ZI_I2C1_PINSET_1 + help + Select which pins to use for I2C1 SCL/SDA signals. + +config NUCLEO_H753ZI_I2C1_PINSET_1 + bool "Pin Set 1: PB6(SCL), PB7(SDA) - AF4" + help + I2C1 Pin Set 1 (Arduino D10/D9): + - SCL: PB6 (CN7-13, D10) - AF4 + - SDA: PB7 (CN7-21, D9) - AF4 + This is the default Arduino-compatible pinout. + WARNING: Conflicts with I2C4 Pinset 4 (same pins, AF6). + +config NUCLEO_H753ZI_I2C1_PINSET_2 + bool "Pin Set 2: PB8(SCL), PB9(SDA) - AF4" + help + I2C1 Pin Set 2 (Morpho): + - SCL: PB8 (CN7-2) - AF4 + - SDA: PB9 (CN7-4) - AF4 + WARNING: Conflicts with I2C4 Pinset 5 (same pins, AF6). + +endchoice + +config NUCLEO_H753ZI_I2C1_DEFAULT_FREQUENCY + int "I2C1 Default Bus Frequency (Hz)" + default 100000 + range 10000 1000000 + help + Default I2C1 bus frequency. + Individual devices can override this. + Standard speeds: + - 100000 (100 kHz): Standard mode + - 400000 (400 kHz): Fast mode + - 1000000 (1 MHz): Fast mode plus + +endif + +config NUCLEO_H753ZI_I2C2_ENABLE + bool "Enable I2C2" + default n + depends on STM32H7_I2C2 + help + Enable I2C2 bus with configurable pinset selection. + +if NUCLEO_H753ZI_I2C2_ENABLE + +choice + prompt "I2C2 Pin Set" + default NUCLEO_H753ZI_I2C2_PINSET_1 + help + Select which pins to use for I2C2 SCL/SDA signals. + +config NUCLEO_H753ZI_I2C2_PINSET_1 + bool "Pin Set 1: PB10(SCL), PB11(SDA) - AF4" + help + I2C2 Pin Set 1: + - SCL: PB10 - AF4 + - SDA: PB11 - AF4 + +config NUCLEO_H753ZI_I2C2_PINSET_2 + bool "Pin Set 2: PF1(SCL), PF0(SDA) - AF4" + help + I2C2 Pin Set 2: + - SCL: PF1 - AF4 + - SDA: PF0 - AF4 + +config NUCLEO_H753ZI_I2C2_PINSET_3 + bool "Pin Set 3: PH4(SCL), PH5(SDA) - AF4" + help + I2C2 Pin Set 3: + - SCL: PH4 - AF4 + - SDA: PH5 - AF4 + +endchoice + +config NUCLEO_H753ZI_I2C2_DEFAULT_FREQUENCY + int "I2C2 Default Bus Frequency (Hz)" + default 100000 + range 10000 1000000 + +endif + +config NUCLEO_H753ZI_I2C3_ENABLE + bool "Enable I2C3" + default n + depends on STM32H7_I2C3 + help + Enable I2C3 bus with configurable pinset selection. + +if NUCLEO_H753ZI_I2C3_ENABLE + +choice + prompt "I2C3 Pin Set" + default NUCLEO_H753ZI_I2C3_PINSET_1 + help + Select which pins to use for I2C3 SCL/SDA signals. + +config NUCLEO_H753ZI_I2C3_PINSET_1 + bool "Pin Set 1: PA8(SCL), PC9(SDA) - AF4" + help + I2C3 Pin Set 1: + - SCL: PA8 - AF4 + - SDA: PC9 - AF4 + +config NUCLEO_H753ZI_I2C3_PINSET_2 + bool "Pin Set 2: PH7(SCL), PH8(SDA) - AF4" + help + I2C3 Pin Set 2: + - SCL: PH7 - AF4 + - SDA: PH8 - AF4 + +endchoice + +config NUCLEO_H753ZI_I2C3_DEFAULT_FREQUENCY + int "I2C3 Default Bus Frequency (Hz)" + default 100000 + range 10000 1000000 + +endif + +config NUCLEO_H753ZI_I2C4_ENABLE + bool "Enable I2C4" + default n + depends on STM32H7_I2C4 + help + Enable I2C4 bus with configurable pinset selection. + +if NUCLEO_H753ZI_I2C4_ENABLE + +choice + prompt "I2C4 Pin Set" + default NUCLEO_H753ZI_I2C4_PINSET_1 + help + Select which pins to use for I2C4 SCL/SDA signals. + +config NUCLEO_H753ZI_I2C4_PINSET_1 + bool "Pin Set 1: PD12(SCL), PD13(SDA) - AF4" + help + I2C4 Pin Set 1: + - SCL: PD12 - AF4 + - SDA: PD13 - AF4 + +config NUCLEO_H753ZI_I2C4_PINSET_2 + bool "Pin Set 2: PF14(SCL), PF15(SDA) - AF4" + help + I2C4 Pin Set 2: + - SCL: PF14 - AF4 + - SDA: PF15 - AF4 + +config NUCLEO_H753ZI_I2C4_PINSET_3 + bool "Pin Set 3: PH11(SCL), PH12(SDA) - AF4" + help + I2C4 Pin Set 3: + - SCL: PH11 - AF4 + - SDA: PH12 - AF4 + +config NUCLEO_H753ZI_I2C4_PINSET_4 + bool "Pin Set 4: PB6(SCL), PB7(SDA) - AF6" + depends on !NUCLEO_H753ZI_I2C1_PINSET_1 + help + I2C4 Pin Set 4 (Alternate Function 6): + - SCL: PB6 - AF6 + - SDA: PB7 - AF6 + WARNING: These are the same physical pins as I2C1 Pinset 1. + Cannot use both I2C1 Pinset 1 (AF4) and I2C4 Pinset 4 (AF6). + OK to use with I2C1 Pinset 2 (different pins). + +config NUCLEO_H753ZI_I2C4_PINSET_5 + bool "Pin Set 5: PB8(SCL), PB9(SDA) - AF6" + depends on !NUCLEO_H753ZI_I2C1_PINSET_2 + help + I2C4 Pin Set 5 (Alternate Function 6): + - SCL: PB8 - AF6 + - SDA: PB9 - AF6 + WARNING: These are the same physical pins as I2C1 Pinset 2. + Cannot use both I2C1 Pinset 2 (AF4) and I2C4 Pinset 5 (AF6). + OK to use with I2C1 Pinset 1 (different pins). + +endchoice + +config NUCLEO_H753ZI_I2C4_DEFAULT_FREQUENCY + int "I2C4 Default Bus Frequency (Hz)" + default 100000 + range 10000 1000000 + +endif + +endmenu + +menu "SPI MODULES" + depends on STM32H7_SPI + +menu "MFRC522 RFID Reader Configuration" + depends on CL_MFRC522 + +config NUCLEO_H753ZI_MFRC522_ENABLE + bool "Enable MFRC522 RFID Reader" + default n + help + Enable MFRC522 13.56 MHz RFID reader with configurable SPI bus, + CS pin, and optional IRQ support. + +if NUCLEO_H753ZI_MFRC522_ENABLE + +choice + prompt "MFRC522 SPI Bus" + help + Select which SPI bus the MFRC522 is connected to. + +config NUCLEO_H753ZI_MFRC522_SPI1 + bool "Use SPI1" + depends on NUCLEO_H753ZI_SPI1_ENABLE + +config NUCLEO_H753ZI_MFRC522_SPI2 + bool "Use SPI2" + depends on NUCLEO_H753ZI_SPI2_ENABLE + +config NUCLEO_H753ZI_MFRC522_SPI3 + bool "Use SPI3" + depends on NUCLEO_H753ZI_SPI3_ENABLE + +config NUCLEO_H753ZI_MFRC522_SPI4 + bool "Use SPI4" + depends on NUCLEO_H753ZI_SPI4_ENABLE + +config NUCLEO_H753ZI_MFRC522_SPI5 + bool "Use SPI5" + depends on NUCLEO_H753ZI_SPI5_ENABLE + +config NUCLEO_H753ZI_MFRC522_SPI6 + bool "Use SPI6" + depends on NUCLEO_H753ZI_SPI6_ENABLE + +endchoice + +config NUCLEO_H753ZI_MFRC522_SPI_BUS + int + default 1 if NUCLEO_H753ZI_MFRC522_SPI1 + default 2 if NUCLEO_H753ZI_MFRC522_SPI2 + default 3 if NUCLEO_H753ZI_MFRC522_SPI3 + default 4 if NUCLEO_H753ZI_MFRC522_SPI4 + default 5 if NUCLEO_H753ZI_MFRC522_SPI5 + default 6 if NUCLEO_H753ZI_MFRC522_SPI6 + +config NUCLEO_H753ZI_MFRC522_DEVID + int "MFRC522 Device ID" + range 0 15 + default 0 + help + Device ID for MFRC522 within the selected SPI bus. + Range: 0-15 for each SPI bus. + This ID will be used to register the CS pin. + +config NUCLEO_H753ZI_MFRC522_CS_PIN + string "CS (Chip Select) GPIO Pin" + default "PA4" + help + GPIO pin for MFRC522 Chip Select. + Format: PORT+PIN (e.g., "PA4", "PB0", "PC5") + Common available pins: + - Arduino Headers: PF15(D2), PG14(D1), PG9(D0), PE0(D34) + - Morpho Headers: PA0-PA15, PB0-PB15, PC0-PC15, PD0-PD15, + PE0-PE15, PF0-PF15, PG0-PG15, PH0-PH1 + Avoid pins already used by selected SPI MISO/MOSI/SCK. + +choice + prompt "CS Pin Active Level" + default NUCLEO_H753ZI_MFRC522_CS_ACTIVE_LOW + help + Select whether the CS pin is active low or active high. + +config NUCLEO_H753ZI_MFRC522_CS_ACTIVE_LOW + bool "Active Low (standard)" + help + CS pin is active low (0V = selected, 3.3V = deselected). + This is the standard for MFRC522. + +config NUCLEO_H753ZI_MFRC522_CS_ACTIVE_HIGH + bool "Active High" + help + CS pin is active high (3.3V = selected, 0V = deselected). + Use only if your hardware requires it. + +endchoice + +config NUCLEO_H753ZI_MFRC522_IRQ_ENABLE + bool "Enable IRQ support" + default n + help + Enable interrupt-driven operation for MFRC522. + Allows the reader to signal when a card is detected. + +config NUCLEO_H753ZI_MFRC522_IRQ_PIN + string "IRQ GPIO Pin" + depends on NUCLEO_H753ZI_MFRC522_IRQ_ENABLE + default "PF2" + help + GPIO pin for MFRC522 interrupt signal. + Format: PORT+PIN (e.g., "PF2", "PE1", "PA3") + This pin should be connected to the MFRC522's IRQ output. + Choose a pin that supports external interrupts. + Common interrupt-capable pins: + - Arduino Headers: PF15(D2), PG14(D1), PG9(D0) + - Morpho Headers: Most PA/PB/PC/PD/PE/PF/PG pins + Avoid pins already used by SPI or CS. + +choice + prompt "IRQ Trigger Type" + depends on NUCLEO_H753ZI_MFRC522_IRQ_ENABLE + default NUCLEO_H753ZI_MFRC522_IRQ_FALLING_EDGE + help + Select the interrupt trigger type for MFRC522. + +config NUCLEO_H753ZI_MFRC522_IRQ_FALLING_EDGE + bool "Falling Edge" + help + Trigger interrupt on falling edge (3.3V to 0V transition). + This is the default for MFRC522. + +config NUCLEO_H753ZI_MFRC522_IRQ_RISING_EDGE + bool "Rising Edge" + help + Trigger interrupt on rising edge (0V to 3.3V transition). + +config NUCLEO_H753ZI_MFRC522_IRQ_BOTH_EDGES + bool "Both Edges" + help + Trigger interrupt on both rising and falling edges. + +endchoice + +endif + +endmenu + +menu "ST7796 LCD Display Configuration" + depends on LCD_ST7796 + +config NUCLEO_H753ZI_ST7796_ENABLE + bool "Enable ST7796 LCD Display" + default n + select SPI_CMDDATA + help + Enable ST7796 3.5" IPS LCD display (320x480) with configurable + SPI bus, CS pin, DC pin, RESET pin, and LED backlight pin. + +if NUCLEO_H753ZI_ST7796_ENABLE + +choice + prompt "ST7796 SPI Bus" + help + Select which SPI bus the ST7796 is connected to. + +config NUCLEO_H753ZI_ST7796_SPI1 + bool "Use SPI1" + depends on NUCLEO_H753ZI_SPI1_ENABLE + +config NUCLEO_H753ZI_ST7796_SPI2 + bool "Use SPI2" + depends on NUCLEO_H753ZI_SPI2_ENABLE + +config NUCLEO_H753ZI_ST7796_SPI3 + bool "Use SPI3" + depends on NUCLEO_H753ZI_SPI3_ENABLE + +config NUCLEO_H753ZI_ST7796_SPI4 + bool "Use SPI4" + depends on NUCLEO_H753ZI_SPI4_ENABLE + +config NUCLEO_H753ZI_ST7796_SPI5 + bool "Use SPI5" + depends on NUCLEO_H753ZI_SPI5_ENABLE + +config NUCLEO_H753ZI_ST7796_SPI6 + bool "Use SPI6" + depends on NUCLEO_H753ZI_SPI6_ENABLE + +endchoice + +config NUCLEO_H753ZI_ST7796_SPI_BUS + int + default 1 if NUCLEO_H753ZI_ST7796_SPI1 + default 2 if NUCLEO_H753ZI_ST7796_SPI2 + default 3 if NUCLEO_H753ZI_ST7796_SPI3 + default 4 if NUCLEO_H753ZI_ST7796_SPI4 + default 5 if NUCLEO_H753ZI_ST7796_SPI5 + default 6 if NUCLEO_H753ZI_ST7796_SPI6 + +config NUCLEO_H753ZI_ST7796_DEVID + int "ST7796 Device ID" + range 0 15 + default 0 + help + Device ID for ST7796 within the selected SPI bus. + Range: 0-15 for each SPI bus. + This ID will be used to register the CS pin. + +menu "ST7796 Pin Configuration" + +config NUCLEO_H753ZI_ST7796_CS_PIN + string "CS (Chip Select) GPIO Pin" + default "PA4" + help + GPIO pin for ST7796 Chip Select. + Format: PORT+PIN (e.g., "PA4", "PB0", "PC5") + Common available pins: + - Arduino Headers: PF15(D2), PG14(D1), PG9(D0), PE0(D34) + - Morpho Headers: PA0-PA15, PB0-PB15, PC0-PC15, PD0-PD15, + PE0-PE15, PF0-PF15, PG0-PG15, PH0-PH1 + Avoid pins already used by selected SPI MISO/MOSI/SCK. + +choice + prompt "CS Pin Active Level" + default NUCLEO_H753ZI_ST7796_CS_ACTIVE_LOW + help + Select whether the CS pin is active low or active high. + +config NUCLEO_H753ZI_ST7796_CS_ACTIVE_LOW + bool "Active Low (most common)" + help + CS pin is active low (0V = selected, 3.3V = deselected). + This is the standard for most SPI displays including ST7796. + +config NUCLEO_H753ZI_ST7796_CS_ACTIVE_HIGH + bool "Active High" + help + CS pin is active high (3.3V = selected, 0V = deselected). + Less common, use only if your hardware requires it. + +endchoice + +config NUCLEO_H753ZI_ST7796_DC_PIN + string "DC (Data/Command) GPIO Pin" + default "PA3" + help + GPIO pin for ST7796 Data/Command selection. + Format: PORT+PIN (e.g., "PA3", "PB1", "PC4") + This pin controls whether data sent to the display is + interpreted as commands or display data. + DC=0: Command + DC=1: Data + Choose a pin not used by SPI or CS. + +config NUCLEO_H753ZI_ST7796_RESET_PIN + string "RESET GPIO Pin" + default "PA2" + help + GPIO pin for ST7796 hardware reset. + Format: PORT+PIN (e.g., "PA2", "PB2", "PC3") + This pin is used to perform a hardware reset of the display. + Active low reset (pull low to reset, high for normal + operation). + Choose a pin not used by SPI, CS, or DC. + +config NUCLEO_H753ZI_ST7796_LED_PIN + string "LED (Backlight) GPIO Pin" + default "PA1" + help + GPIO pin for ST7796 backlight control. + Format: PORT+PIN (e.g., "PA1", "PB3", "PC2") + This pin controls the LCD backlight LED. + High = backlight on, Low = backlight off. + Note: Currently configured for direct 3.3V connection + without PWM. For PWM brightness control, additional + configuration will be needed. + Choose a pin not used by SPI, CS, DC, or RESET. + +endmenu + +menu "ST7796 Display Settings" + +choice + prompt "Color Depth" + default NUCLEO_H753ZI_ST7796_RGB565 + help + Select the color depth for the ST7796 display. + +config NUCLEO_H753ZI_ST7796_RGB444 + bool "12-bit RGB444" + help + 12-bit color depth (4096 colors). + Lower memory usage but reduced color quality. + +config NUCLEO_H753ZI_ST7796_RGB565 + bool "16-bit RGB565 (recommended)" + help + 16-bit color depth (65536 colors). + Good balance between color quality and memory usage. + This is the most common configuration. + +config NUCLEO_H753ZI_ST7796_RGB666 + bool "18-bit RGB666" + help + 18-bit color depth (262144 colors). + Higher color quality but increased memory usage and + slower SPI transfers. + +endchoice + +choice + prompt "Display Orientation" + default NUCLEO_H753ZI_ST7796_PORTRAIT + help + Select the display orientation. + +config NUCLEO_H753ZI_ST7796_PORTRAIT + bool "Portrait (320x480)" + help + Portrait orientation: 320 pixels wide, 480 pixels tall. + This is the natural orientation of the display. + +config NUCLEO_H753ZI_ST7796_LANDSCAPE + bool "Landscape (480x320)" + help + Landscape orientation: 480 pixels wide, 320 pixels tall. + 90 degree rotation from portrait. + +config NUCLEO_H753ZI_ST7796_RPORTRAIT + bool "Reverse Portrait (320x480)" + help + Reverse portrait orientation: 320 pixels wide, 480 pixels + tall. 180 degree rotation from portrait. + +config NUCLEO_H753ZI_ST7796_RLANDSCAPE + bool "Reverse Landscape (480x320)" + help + Reverse landscape orientation: 480 pixels wide, 320 pixels + tall. 270 degree rotation from portrait (or 90 degrees from + landscape). + +endchoice + +config NUCLEO_H753ZI_ST7796_BGR + bool "Use BGR color order instead of RGB" + default y + help + Enable this if your display shows colors incorrectly + (e.g., red appears as blue and vice versa). + Most ST7796 displays use RGB order, but some use BGR. + +config NUCLEO_H753ZI_ST7796_FREQUENCY + int "SPI Frequency (Hz)" + default 40000000 + range 1000000 80000000 + help + SPI bus frequency for ST7796 communication. + Recommended values: + - 40000000 (40 MHz): Safe default, works with most displays + - 60000000 (60 MHz): Faster, may work depending on wiring + - 80000000 (80 MHz): Maximum, requires good signal integrity + Lower frequencies (10-20 MHz) can be used if you experience + display issues or have long/poor quality connections. + +endmenu + +menu "ST7796 Framebuffer Configuration" + +config NUCLEO_H753ZI_ST7796_FB_SUPPORT + bool "Enable framebuffer support" + default y + depends on VIDEO_FB + help + Enable framebuffer support for ST7796. + This allows the display to be used with LVGL and other + graphics libraries that use the framebuffer interface. + +if NUCLEO_H753ZI_ST7796_FB_SUPPORT + +config NUCLEO_H753ZI_ST7796_FB_SIZE + int "Framebuffer size (in KB)" + default 300 + range 150 600 + help + Size of the framebuffer in kilobytes. + Full resolution requirements: + - RGB444 (12-bit): 300 KB (320x480x1.5 bytes) + - RGB565 (16-bit): 300 KB (320x480x2 bytes) + - RGB666 (18-bit): 450 KB (320x480x3 bytes) + For memory-constrained systems, you can reduce this + and implement partial screen updates. + +endif + +endmenu + +menu "ST7796 Orientation" + +choice + prompt "Display Rotation" + default NUCLEO_H753ZI_ST7796_ROTATION_0 + help + Select the display rotation angle. Use this if your display + is mounted upside down or needs rotation. + This rotation is applied AFTER the base orientation selected + in "Display Settings" above. + +config NUCLEO_H753ZI_ST7796_ROTATION_0 + bool "0 degrees (Normal)" + help + No rotation. Display orientation as configured in Display + Settings (Portrait, Landscape, etc). + Use this if your display is mounted correctly. + +config NUCLEO_H753ZI_ST7796_ROTATION_180 + bool "180 degrees (Flip)" + help + Rotate display 180 degrees. Use this if your display is + mounted upside down. + This flips both horizontal and vertical axes, effectively + rotating the entire display content 180 degrees. + Works with all orientation modes (Portrait, Landscape, etc). + +endchoice + +config NUCLEO_H753ZI_ST7796_ROTATION + int + default 0 if NUCLEO_H753ZI_ST7796_ROTATION_0 + default 180 if NUCLEO_H753ZI_ST7796_ROTATION_180 + help + Internal: Rotation angle in degrees. + +endmenu + +endif + +endmenu + +endmenu + +menu "I2C MODULES" + depends on STM32H7_I2C + +menu "SSD1306 OLED Display Configuration" + depends on LCD_SSD1306 + +config NUCLEO_H753ZI_SSD1306_ENABLE + bool "Enable SSD1306 OLED Display (I2C)" + default n + help + Enable SSD1306 OLED display via I2C interface. + The SSD1306 is a monochrome OLED display controller + commonly used in 128x64 and 128x32 pixel displays. + +if NUCLEO_H753ZI_SSD1306_ENABLE + +choice + prompt "SSD1306 I2C Bus" + default NUCLEO_H753ZI_SSD1306_I2C1 + help + Select which I2C bus the SSD1306 is connected to. + +config NUCLEO_H753ZI_SSD1306_I2C1 + bool "I2C1" + depends on STM32H7_I2C1 + select NUCLEO_H753ZI_I2C1_ENABLE + help + Use I2C1 bus for SSD1306 display. + +config NUCLEO_H753ZI_SSD1306_I2C2 + bool "I2C2" + depends on STM32H7_I2C2 + select NUCLEO_H753ZI_I2C2_ENABLE + help + Use I2C2 bus for SSD1306 display. + +config NUCLEO_H753ZI_SSD1306_I2C3 + bool "I2C3" + depends on STM32H7_I2C3 + select NUCLEO_H753ZI_I2C3_ENABLE + help + Use I2C3 bus for SSD1306 display. + +config NUCLEO_H753ZI_SSD1306_I2C4 + bool "I2C4" + depends on STM32H7_I2C4 + select NUCLEO_H753ZI_I2C4_ENABLE + help + Use I2C4 bus for SSD1306 display. + +endchoice + +config NUCLEO_H753ZI_SSD1306_I2C_BUS + int + default 1 if NUCLEO_H753ZI_SSD1306_I2C1 + default 2 if NUCLEO_H753ZI_SSD1306_I2C2 + default 3 if NUCLEO_H753ZI_SSD1306_I2C3 + default 4 if NUCLEO_H753ZI_SSD1306_I2C4 + +choice + prompt "SSD1306 I2C Address" + default NUCLEO_H753ZI_SSD1306_ADDR_3C + help + Select the I2C address of your SSD1306 module. + Check your hardware: + - Most modules use 0x3C (default) + - Some modules use 0x3D + - Address is determined by the SA0 pin state + +config NUCLEO_H753ZI_SSD1306_ADDR_3C + bool "0x3C (SA0 = GND) - Default" + help + I2C address 0x3C (60 decimal). + This is the most common address for SSD1306 modules. + Used when SA0 pin is connected to GND. + +config NUCLEO_H753ZI_SSD1306_ADDR_3D + bool "0x3D (SA0 = VDD)" + help + I2C address 0x3D (61 decimal). + Used when SA0 pin is connected to VDD. + +config NUCLEO_H753ZI_SSD1306_ADDR_CUSTOM + bool "Custom Address" + help + Specify a custom I2C address. + +endchoice + +config NUCLEO_H753ZI_SSD1306_ADDR_CUSTOM_VALUE + hex "Custom I2C Address" + depends on NUCLEO_H753ZI_SSD1306_ADDR_CUSTOM + default 0x3C + range 0x08 0x77 + help + Enter custom I2C address in hexadecimal format. + Valid range: 0x08 to 0x77 + +config NUCLEO_H753ZI_SSD1306_I2C_ADDR + hex + default 0x3C if NUCLEO_H753ZI_SSD1306_ADDR_3C + default 0x3D if NUCLEO_H753ZI_SSD1306_ADDR_3D + default NUCLEO_H753ZI_SSD1306_ADDR_CUSTOM_VALUE if NUCLEO_H753ZI_SSD1306_ADDR_CUSTOM + +config NUCLEO_H753ZI_SSD1306_I2C_FREQUENCY + int "I2C Bus Frequency (Hz)" + default 400000 + range 10000 1000000 + help + I2C bus frequency for SSD1306 communication. + Recommended speeds: + - 100000 (100 kHz): Standard mode (safer, slower) + - 400000 (400 kHz): Fast mode (recommended) + - 1000000 (1 MHz): Fast mode plus (if supported by module) + Higher frequencies provide faster screen updates. + +config NUCLEO_H753ZI_SSD1306_POWER_PERCENT + int "Display Power/Brightness (%)" + default 100 + range 0 100 + help + Display power/brightness level as percentage. + - 0%: Display off + - 50%: Half brightness + - 100%: Maximum brightness (recommended) + Note: This translates to the SSD1306 contrast setting. + Higher values = brighter display but more power consumption. + +config NUCLEO_H753ZI_SSD1306_POWER_LEVEL + int + default 0 if NUCLEO_H753ZI_SSD1306_POWER_PERCENT = 0 + default 1 if NUCLEO_H753ZI_SSD1306_POWER_PERCENT <= 100 + help + Internal: Converts percentage to NuttX power level. + - 0 = off + - 1 = on (brightness controlled by contrast) + +choice + prompt "Display Resolution" + default NUCLEO_H753ZI_SSD1306_128X64 + help + Select your SSD1306 display resolution. + +config NUCLEO_H753ZI_SSD1306_128X64 + bool "128x64 pixels" + help + Standard 0.96" OLED display (128x64 pixels). + This is the most common size. + +config NUCLEO_H753ZI_SSD1306_128X32 + bool "128x32 pixels" + help + Smaller 0.91" OLED display (128x32 pixels). + +endchoice + +config NUCLEO_H753ZI_SSD1306_FB_SIZE + int + default 1024 if NUCLEO_H753ZI_SSD1306_128X64 + default 512 if NUCLEO_H753ZI_SSD1306_128X32 + help + Internal: Framebuffer size in bytes. + 128x64 = 1024 bytes (128*64/8) + 128x32 = 512 bytes (128*32/8) + +config NUCLEO_H753ZI_SSD1306_DEVPATH + string "Device Path" + default "/dev/lcd0" + help + Device node path for SSD1306 display. + For multiple displays use different paths: + - /dev/lcd0 (first display) + - /dev/lcd1 (second display) + - /dev/oled0, /dev/oled1 (alternative naming) + The path should match the device number below. + +config NUCLEO_H753ZI_SSD1306_DEVNO + int "Device Number" + default 0 + range 0 7 + help + LCD device number for registration. + This number is passed to the NuttX LCD driver and should + typically match the number in the device path: + - Device 0 -> /dev/lcd0 + - Device 1 -> /dev/lcd1 + - etc. + For multiple SSD1306 displays, use different numbers for each. + +endif + +endmenu + +endmenu + +config STM32_ROMFS + bool "Automount built-in ROMFS image" + default n + depends on FS_ROMFS + help + Select STM32_ROMFS_IMAGEFILE, STM32_ROMFS_DEV_MINOR, + STM32_ROMFS_MOUNTPOINT + +config STM32_ROMFS_DEV_MINOR + int "Minor number for the block device backing the data" + depends on STM32_ROMFS + default 64 + +config STM32_ROMFS_MOUNTPOINT + string "Mount point of the custom ROMFS image" + depends on STM32_ROMFS + default "/rom" + +config STM32_ROMFS_IMAGEFILE + string "ROMFS image file to include in the build" + depends on STM32_ROMFS + default "../../../rom.img" diff --git a/boards/arm/stm32h7/nucleo-h753zi/configs/button_driver/defconfig b/boards/arm/stm32h7/nucleo-h753zi/configs/button_driver/defconfig new file mode 100644 index 0000000000000..b53e6adf4f8bc --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/configs/button_driver/defconfig @@ -0,0 +1,70 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_NSH_DISABLE_IFCONFIG is not set +# CONFIG_NSH_DISABLE_PS is not set +# CONFIG_STANDARD_SERIAL is not set +# CONFIG_STM32H7_USE_LEGACY_PINMAP is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nucleo-h753zi" +CONFIG_ARCH_BOARD_NUCLEO_H753ZI=y +CONFIG_ARCH_CHIP="stm32h7" +CONFIG_ARCH_CHIP_STM32H753ZI=y +CONFIG_ARCH_CHIP_STM32H7=y +CONFIG_ARCH_CHIP_STM32H7_CORTEXM7=y +CONFIG_ARCH_IRQBUTTONS=y +CONFIG_ARCH_LEDS_CPU_ACTIVITY=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARMV7M_DCACHE=y +CONFIG_ARMV7M_DCACHE_WRITETHROUGH=y +CONFIG_ARMV7M_DTCM=y +CONFIG_ARMV7M_ICACHE=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=43103 +CONFIG_BUILTIN=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_EXAMPLES_BUTTONS=y +CONFIG_EXAMPLES_BUTTONS_NAME0="PC13" +CONFIG_EXAMPLES_BUTTONS_NAME1="PB1" +CONFIG_EXAMPLES_BUTTONS_NAME2="PD0" +CONFIG_EXAMPLES_BUTTONS_NAME3="PG4" +CONFIG_EXAMPLES_BUTTONS_NAME4="PD5" +CONFIG_EXAMPLES_BUTTONS_NAME5="PE6" +CONFIG_EXAMPLES_BUTTONS_NAME6="PE3" +CONFIG_EXAMPLES_BUTTONS_NAME7="PD12" +CONFIG_EXAMPLES_BUTTONS_NAMES=y +CONFIG_EXPERIMENTAL=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INPUT=y +CONFIG_INPUT_BUTTONS=y +CONFIG_INPUT_BUTTONS_LOWER=y +CONFIG_INTELHEX_BINARY=y +CONFIG_LINE_MAX=64 +CONFIG_MM_REGIONS=4 +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_NUCLEO_H753ZI_BUTTON_COUNT=8 +CONFIG_NUCLEO_H753ZI_BUTTON_PINS="PB1,PD0,PG4,PD5,PE6,PE3,PD12" +CONFIG_NUCLEO_H753ZI_BUTTON_SUPPORT=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=245760 +CONFIG_RAM_START=0x20010000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=6 +CONFIG_START_MONTH=12 +CONFIG_START_YEAR=2011 +CONFIG_STM32H7_USART3=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_USART3_SERIAL_CONSOLE=y +CONFIG_USERLED=y +CONFIG_USERLED_LOWER=y diff --git a/boards/arm/stm32h7/nucleo-h753zi/configs/nsh/defconfig b/boards/arm/stm32h7/nucleo-h753zi/configs/nsh/defconfig new file mode 100644 index 0000000000000..86a2f4ba622f4 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/configs/nsh/defconfig @@ -0,0 +1,54 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_LEDS is not set +# CONFIG_NSH_DISABLE_IFCONFIG is not set +# CONFIG_NSH_DISABLE_PS is not set +# CONFIG_STANDARD_SERIAL is not set +# CONFIG_STM32H7_USE_LEGACY_PINMAP is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nucleo-h753zi" +CONFIG_ARCH_BOARD_NUCLEO_H753ZI=y +CONFIG_ARCH_CHIP="stm32h7" +CONFIG_ARCH_CHIP_STM32H753ZI=y +CONFIG_ARCH_CHIP_STM32H7=y +CONFIG_ARCH_CHIP_STM32H7_CORTEXM7=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARMV7M_DCACHE=y +CONFIG_ARMV7M_DCACHE_WRITETHROUGH=y +CONFIG_ARMV7M_DTCM=y +CONFIG_ARMV7M_ICACHE=y +CONFIG_BOARD_LOOPSPERMSEC=43103 +CONFIG_BUILTIN=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_EXAMPLES_GPIO=y +CONFIG_EXAMPLES_LEDS=y +CONFIG_EXPERIMENTAL=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_LINE_MAX=64 +CONFIG_MM_REGIONS=4 +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_NUCLEO_H753ZI_GPIO_DRIVER=y +CONFIG_NUCLEO_H753ZI_LEDS_USER=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=245760 +CONFIG_RAM_START=0x20010000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=6 +CONFIG_START_MONTH=12 +CONFIG_START_YEAR=2011 +CONFIG_STM32H7_USART3=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_USART3_SERIAL_CONSOLE=y diff --git a/boards/arm/stm32h7/nucleo-h753zi/configs/socketcan/defconfig b/boards/arm/stm32h7/nucleo-h753zi/configs/socketcan/defconfig new file mode 100644 index 0000000000000..9966b9c40e3bb --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/configs/socketcan/defconfig @@ -0,0 +1,74 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_STANDARD_SERIAL is not set +# CONFIG_STM32H7_USE_LEGACY_PINMAP is not set +CONFIG_ALLOW_BSD_COMPONENTS=y +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nucleo-h753zi" +CONFIG_ARCH_BOARD_NUCLEO_H753ZI=y +CONFIG_ARCH_CHIP="stm32h7" +CONFIG_ARCH_CHIP_STM32H753ZI=y +CONFIG_ARCH_CHIP_STM32H7=y +CONFIG_ARCH_CHIP_STM32H7_CORTEXM7=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARMV7M_DCACHE=y +CONFIG_ARMV7M_DCACHE_WRITETHROUGH=y +CONFIG_ARMV7M_DTCM=y +CONFIG_ARMV7M_ICACHE=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=43103 +CONFIG_BUILTIN=y +CONFIG_CANUTILS_CANDUMP=y +CONFIG_CANUTILS_CANDUMP_STACKSIZE=4096 +CONFIG_CANUTILS_CANSEND=y +CONFIG_CANUTILS_LIBCANUTILS=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_EXPERIMENTAL=y +CONFIG_FDCAN1_ARBI_BITRATE=500000 +CONFIG_FDCAN1_DATA_BITRATE=500000 +CONFIG_FS_PROCFS=y +CONFIG_FS_PROCFS_REGISTER=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_IOB_NBUFFERS=24 +CONFIG_IOB_THROTTLE=0 +CONFIG_LINE_MAX=64 +CONFIG_MM_REGIONS=4 +CONFIG_NET=y +CONFIG_NETDEV_CAN_BITRATE_IOCTL=y +CONFIG_NETDEV_CAN_STATE_IOCTL=y +CONFIG_NETDEV_IFINDEX=y +CONFIG_NETDOWN_NOTIFIER=y +CONFIG_NET_CAN=y +CONFIG_NET_CAN_ERRORS=y +CONFIG_NET_CAN_NOTIFIER=y +CONFIG_NET_CAN_SOCK_OPTS=y +CONFIG_NET_CAN_WRITE_BUFFERS=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_DISABLE_VCONFIG=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=245760 +CONFIG_RAM_START=0x20010000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_SPI=y +CONFIG_START_DAY=6 +CONFIG_START_MONTH=12 +CONFIG_START_YEAR=2011 +CONFIG_STM32H7_FDCAN1=y +CONFIG_STM32H7_FDCAN_HPWORK=y +CONFIG_STM32H7_USART3=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_USART3_SERIAL_CONSOLE=y diff --git a/boards/arm/stm32h7/nucleo-h753zi/include/board.h b/boards/arm/stm32h7/nucleo-h753zi/include/board.h new file mode 100644 index 0000000000000..d5d38aae05a26 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/include/board.h @@ -0,0 +1,1309 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/include/board.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +/* GPIO PINOUT MAPPING FOR NUCLEO-H753ZI (MB1364) + * + * Pin usage table for STM32H753ZI on Nucleo board's on-board peripherals. + * Pins not listed here are, by default, free for general use. + * + * Based on the following documents: + * - Schematics: 19250.pdf + * + * |---------------------------------------------------------------------| + * |Function/Peripheral | Logical Name | STM32 Pin | A.F | Notes | + * |---------------------------------------------------------------------| + * | User Button | B1_USER | PC13 | - | | + * | LED1 (Green) | LD1 | PB0 | - | | + * | LED2 (Orange) | LD2 | PE1 | - | | + * | LED3 (Red) | LD3 | PB14 | - | | + * | Ethernet | RMII_MDIO | PA2 | AF11 | | + * | | RMII_MDC | PC1 | AF11 | | + * | | RMII_TX_EN | PG11 | AF11 | | + * | | RMII_TXD0 | PG13 | AF11 | | + * | | RMII_TXD1 | PG12 | AF11 | | + * | | RMII_RXD0 | PC4 | AF11 | | + * | | RMII_RXD1 | PC5 | AF11 | | + * | | RMII_CRS_DV | PA7 | AF11 | | + * | | RMII_REF_CLK | PA1 | AF11 | | + * | USB VCP | VCP_TX | PD8 | AF7 | USART3_TX | + * | | VCP_RX | PD9 | AF7 | USART3_RX | + * | USB OTG_FS | USB_FS_VBUS | PA9 | AF10 | | + * | | USB_FS_ID | PA10 | AF10 | | + * | | USB_FS_N | PA11 | AF10 | | + * | | USB_FS_P | PA12 | AF10 | | + * | Debug (ST-LINK) | SWCLK | PA14 | AF0 | | + * | | SWDIO | PA13 | AF0 | | + * | Zio Connector(I2C) | A4 | PB9 | AF4 | I2C1_SDA | + * | | A5 | PB8 | AF4 | I2C1_SCL | + * | External Clock HSE | HSE_IN | PH0 | - | 8 MHz MCO | + * | | HSE_OUT | PH1 | - | Reserved X3 | + * |----------------------------------------------------------------------| + * + */ + +#ifndef __BOARDS_ARM_STM32H7_NUCLEO_H753ZI_INCLUDE_BOARD_H +#define __BOARDS_ARM_STM32H7_NUCLEO_H753ZI_INCLUDE_BOARD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#ifndef __ASSEMBLY__ +# include +#endif + +/* Do not include STM32 H7 header files here */ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * SECTION 1: CLOCK CONFIGURATION + ****************************************************************************/ + +/* Oscillator Frequency Definitions */ + +#define STM32_HSI_FREQUENCY 64000000ul +#define STM32_CSI_FREQUENCY 4000000ul +#define STM32_LSI_FREQUENCY 32000ul +#define STM32_LSE_FREQUENCY 32768ul + +#ifdef CONFIG_NUCLEO_H753ZI_HSE_25MHZ +# define STM32_HSE_FREQUENCY 25000000ul +#else +# define STM32_HSE_FREQUENCY 8000000ul +#endif + +/* PLL Configuration + * + * Main PLL Configuration. + * + * PLL source is HSE + * + * When STM32_HSE_FREQUENCY / PLLM <= 2MHz VCOL must be selected. + * VCOH otherwise. + * + * PLL_VCOx = (STM32_HSE_FREQUENCY / PLLM) * PLLN + * Subject to: + * + * 1 <= PLLM <= 63 + * 4 <= PLLN <= 512 + * 150 MHz <= PLL_VCOL <= 420MHz + * 192 MHz <= PLL_VCOH <= 836MHz + * + * SYSCLK = PLL_VCO / PLLP + * CPUCLK = SYSCLK / D1CPRE + * Subject to + * + * PLLP1 = {2, 4, 6, 8, ..., 128} + * PLLP2,3 = {2, 3, 4, ..., 128} + * CPUCLK <= 480 MHz + */ + +#define STM32_BOARD_USEHSE +#define STM32_PLLCFG_PLLSRC RCC_PLLCKSELR_PLLSRC_HSE + +#ifdef CONFIG_NUCLEO_H753ZI_HSE_25MHZ + +/* PLL1 - 25 MHz HSE input, enable DIVP, DIVQ, DIVR + * + * CORRECTED: VCO limited to 836 MHz, SYSCLK limited to 400 MHz (VOS1) + * + * PLL1_input = 25 MHz / 5 = 5 MHz (within 4-8 MHz range) + * PLL1_VCO = 5 MHz * 160 = 800 MHz (within 192-836 MHz) + * + * PLL1P = PLL1_VCO/2 = 800 MHz / 2 = 400 MHz (SYSCLK) + * PLL1Q = PLL1_VCO/4 = 800 MHz / 4 = 200 MHz (SPI123, SDMMC) + * PLL1R = PLL1_VCO/4 = 800 MHz / 4 = 200 MHz + * + * Note: Same 400 MHz SYSCLK as 8 MHz config (VOS1 safe, NuttX default) + */ + +#define STM32_PLLCFG_PLL1CFG (RCC_PLLCFGR_PLL1VCOSEL_WIDE| \ + RCC_PLLCFGR_PLL1RGE_4_8_MHZ| \ + RCC_PLLCFGR_DIVP1EN| \ + RCC_PLLCFGR_DIVQ1EN| \ + RCC_PLLCFGR_DIVR1EN) +#define STM32_PLLCFG_PLL1M RCC_PLLCKSELR_DIVM1(5) +#define STM32_PLLCFG_PLL1N RCC_PLL1DIVR_N1(160) +#define STM32_PLLCFG_PLL1P RCC_PLL1DIVR_P1(2) +#define STM32_PLLCFG_PLL1Q RCC_PLL1DIVR_Q1(4) +#define STM32_PLLCFG_PLL1R RCC_PLL1DIVR_R1(4) + +#define STM32_VCO1_FREQUENCY ((STM32_HSE_FREQUENCY / 5) * 160) +#define STM32_PLL1P_FREQUENCY (STM32_VCO1_FREQUENCY / 2) +#define STM32_PLL1Q_FREQUENCY (STM32_VCO1_FREQUENCY / 4) +#define STM32_PLL1R_FREQUENCY (STM32_VCO1_FREQUENCY / 4) + +/* PLL2 - 25 MHz HSE input, enable DIVP, DIVQ, DIVR + * + * CORRECTED: Input range (was 4-8 MHz, needs 8-16 MHz) and FDCAN clock + * + * PLL2_input = 25 MHz / 2 = 12.5 MHz (within 8-16 MHz range) + * PLL2_VCO = 12.5 MHz * 48 = 600 MHz (within 192-836 MHz) + * + * PLL2P = PLL2_VCO/8 = 600 MHz / 8 = 75 MHz (ADC, SPI45) + * PLL2Q = PLL2_VCO/24 = 600 MHz / 24 = 25 MHz (FDCAN - not usedHSE direct) + * PLL2R = PLL2_VCO/3 = 600 MHz / 3 = 200 MHz + * + * Note: FDCAN uses HSE directly (25 MHz) for this configuration, + * but PLL2Q is configured to 25 MHz for consistency + */ + +#define STM32_PLLCFG_PLL2CFG (RCC_PLLCFGR_PLL2VCOSEL_WIDE| \ + RCC_PLLCFGR_PLL2RGE_8_16_MHZ| \ + RCC_PLLCFGR_DIVP2EN| \ + RCC_PLLCFGR_DIVQ2EN| \ + RCC_PLLCFGR_DIVR2EN) +#define STM32_PLLCFG_PLL2M RCC_PLLCKSELR_DIVM2(2) +#define STM32_PLLCFG_PLL2N RCC_PLL2DIVR_N2(48) +#define STM32_PLLCFG_PLL2P RCC_PLL2DIVR_P2(8) +#define STM32_PLLCFG_PLL2Q RCC_PLL2DIVR_Q2(24) +#define STM32_PLLCFG_PLL2R RCC_PLL2DIVR_R2(3) + +#define STM32_VCO2_FREQUENCY ((STM32_HSE_FREQUENCY / 2) * 48) +#define STM32_PLL2P_FREQUENCY (STM32_VCO2_FREQUENCY / 8) +#define STM32_PLL2Q_FREQUENCY (STM32_VCO2_FREQUENCY / 24) +#define STM32_PLL2R_FREQUENCY (STM32_VCO2_FREQUENCY / 3) + +/* PLL3 - 25 MHz HSE input, enable DIVP, DIVQ, DIVR + * + * CORRECTED: Input frequency limited to 8-16 MHz range + * + * PLL3_input = 25 MHz / 2 = 12.5 MHz (within 8-16 MHz range) + * PLL3_VCO = 12.5 MHz * 64 = 800 MHz (within 192-836 MHz) + * + * PLL3P = PLL3_VCO/2 = 800 MHz / 2 = 400 MHz + * PLL3Q = PLL3_VCO/32 = 800 MHz / 32 = 25 MHz + * PLL3R = PLL3_VCO/20 = 800 MHz / 20 = 40 MHz + */ + +#define STM32_PLLCFG_PLL3CFG (RCC_PLLCFGR_PLL3VCOSEL_WIDE| \ + RCC_PLLCFGR_PLL3RGE_8_16_MHZ| \ + RCC_PLLCFGR_DIVP3EN| \ + RCC_PLLCFGR_DIVQ3EN| \ + RCC_PLLCFGR_DIVR3EN) +#define STM32_PLLCFG_PLL3M RCC_PLLCKSELR_DIVM3(2) +#define STM32_PLLCFG_PLL3N RCC_PLL3DIVR_N3(64) +#define STM32_PLLCFG_PLL3P RCC_PLL3DIVR_P3(2) +#define STM32_PLLCFG_PLL3Q RCC_PLL3DIVR_Q3(32) +#define STM32_PLLCFG_PLL3R RCC_PLL3DIVR_R3(20) + +#define STM32_VCO3_FREQUENCY ((STM32_HSE_FREQUENCY / 2) * 64) +#define STM32_PLL3P_FREQUENCY (STM32_VCO3_FREQUENCY / 2) +#define STM32_PLL3Q_FREQUENCY (STM32_VCO3_FREQUENCY / 32) +#define STM32_PLL3R_FREQUENCY (STM32_VCO3_FREQUENCY / 20) + +#else /* CONFIG_NUCLEO_H753ZI_HSE_8MHZ (default) */ + +/* PLL1 - 8 MHz HSE input, enable DIVP, DIVQ, DIVR + * + * Calculation for 8 MHz HSE: + * Step 1: PLL1 input = HSE / DIVM1 = 8 MHz / 1 = 8 MHz + * Range: 8 MHz is within 4-16 MHz (RCC_PLLCFGR_PLL1RGE_4_8_MHZ) + * + * Step 2: VCO = PLL1_input * DIVN1 = 8 MHz * 100 = 800 MHz + * Range: 800 MHz is within 192-836 MHz (VCOH) + * + * PLL1P = VCO / DIVP1 = 800 MHz / 2 = 400 MHz (SYSCLK) + * PLL1Q = VCO / DIVQ1 = 800 MHz / 4 = 200 MHz + * PLL1R = VCO / DIVR1 = 800 MHz / 4 = 200 MHz + */ + +#define STM32_PLLCFG_PLL1CFG (RCC_PLLCFGR_PLL1VCOSEL_WIDE| \ + RCC_PLLCFGR_PLL1RGE_4_8_MHZ| \ + RCC_PLLCFGR_DIVP1EN| \ + RCC_PLLCFGR_DIVQ1EN| \ + RCC_PLLCFGR_DIVR1EN) +#define STM32_PLLCFG_PLL1M RCC_PLLCKSELR_DIVM1(1) +#define STM32_PLLCFG_PLL1N RCC_PLL1DIVR_N1(100) +#define STM32_PLLCFG_PLL1P RCC_PLL1DIVR_P1(2) +#define STM32_PLLCFG_PLL1Q RCC_PLL1DIVR_Q1(4) +#define STM32_PLLCFG_PLL1R RCC_PLL1DIVR_R1(4) + +#define STM32_VCO1_FREQUENCY ((STM32_HSE_FREQUENCY / 1) * 100) +#define STM32_PLL1P_FREQUENCY (STM32_VCO1_FREQUENCY / 2) +#define STM32_PLL1Q_FREQUENCY (STM32_VCO1_FREQUENCY / 4) +#define STM32_PLL1R_FREQUENCY (STM32_VCO1_FREQUENCY / 4) + +/* PLL2 - 8 MHz HSE input, enable DIVP, DIVQ, DIVR + * + * CRITICAL: PLL2Q must output 25 MHz for FDCAN compatibility + * + * Calculation for 8 MHz HSE: + * Step 1: PLL2 input = HSE / DIVM2 = 8 MHz / 1 = 8 MHz + * Range: 8 MHz is within 4-16 MHz (RCC_PLLCFGR_PLL2RGE_4_8_MHZ) + * + * Step 2: VCO = PLL2_input * DIVN2 = 8 MHz * 75 = 600 MHz + * Range: 600 MHz is within 192-836 MHz (VCOH) + * + * PLL2P = VCO / DIVP2 = 600 MHz / 8 = 75 MHz (ADC, SPI45) + * PLL2Q = VCO / DIVQ2 = 600 MHz / 24 = 25 MHz (FDCAN kernel clock) + * PLL2R = VCO / DIVR2 = 600 MHz / 3 = 200 MHz + */ + +#define STM32_PLLCFG_PLL2CFG (RCC_PLLCFGR_PLL2VCOSEL_WIDE| \ + RCC_PLLCFGR_PLL2RGE_4_8_MHZ| \ + RCC_PLLCFGR_DIVP2EN| \ + RCC_PLLCFGR_DIVQ2EN| \ + RCC_PLLCFGR_DIVR2EN) + +#define STM32_PLLCFG_PLL2M RCC_PLLCKSELR_DIVM2(1) +#define STM32_PLLCFG_PLL2N RCC_PLL2DIVR_N2(75) +#define STM32_PLLCFG_PLL2P RCC_PLL2DIVR_P2(8) +#define STM32_PLLCFG_PLL2Q RCC_PLL2DIVR_Q2(24) +#define STM32_PLLCFG_PLL2R RCC_PLL2DIVR_R2(3) + +#define STM32_VCO2_FREQUENCY ((STM32_HSE_FREQUENCY / 1) * 75) +#define STM32_PLL2P_FREQUENCY (STM32_VCO2_FREQUENCY / 8) +#define STM32_PLL2Q_FREQUENCY (STM32_VCO2_FREQUENCY / 24) +#define STM32_PLL2R_FREQUENCY (STM32_VCO2_FREQUENCY / 3) + +/* PLL3 - 8 MHz HSE input, enable DIVP, DIVQ, DIVR + * + * NOTE: PLL3 is not used for 8 MHz HSE configuration + * FDCAN clock is provided by PLL2Q (25 MHz) instead + * However, PLL3 must be defined for NuttX RCC code compatibility + * + * Step 1: PLL3 input = HSE / DIVM3 = 8 MHz / 2 = 4 MHz + * Range: 4 MHz is within 2-16 MHz (RCC_PLLCFGR_PLL3RGE_2_4_MHZ) + * + * Step 2: VCO = PLL3_input * DIVN3 = 4 MHz * 100 = 400 MHz + * Range: 400 MHz is within 192-836 MHz (VCOH) + * + * PLL3P = VCO / DIVP3 = 400 MHz / 2 = 200 MHz + * PLL3Q = VCO / DIVQ3 = 400 MHz / 16 = 25 MHz + * PLL3R = VCO / DIVR3 = 400 MHz / 10 = 40 MHz + */ + +#define STM32_PLLCFG_PLL3CFG (RCC_PLLCFGR_PLL3VCOSEL_WIDE| \ + RCC_PLLCFGR_PLL3RGE_2_4_MHZ| \ + RCC_PLLCFGR_DIVP3EN| \ + RCC_PLLCFGR_DIVQ3EN| \ + RCC_PLLCFGR_DIVR3EN) + +#define STM32_PLLCFG_PLL3M RCC_PLLCKSELR_DIVM3(2) +#define STM32_PLLCFG_PLL3N RCC_PLL3DIVR_N3(100) +#define STM32_PLLCFG_PLL3P RCC_PLL3DIVR_P3(2) +#define STM32_PLLCFG_PLL3Q RCC_PLL3DIVR_Q3(16) +#define STM32_PLLCFG_PLL3R RCC_PLL3DIVR_R3(10) + +#define STM32_VCO3_FREQUENCY ((STM32_HSE_FREQUENCY / 2) * 100) +#define STM32_PLL3P_FREQUENCY (STM32_VCO3_FREQUENCY / 2) +#define STM32_PLL3Q_FREQUENCY (STM32_VCO3_FREQUENCY / 16) +#define STM32_PLL3R_FREQUENCY (STM32_VCO3_FREQUENCY / 10) + +#endif /* CONFIG_NUCLEO_H753ZI_HSE_25MHZ */ + +/* System Clock Configuration + * + * SYSCLK = PLL1P + * CPUCLK = SYSCLK / 1 + */ + +#define STM32_RCC_D1CFGR_D1CPRE (RCC_D1CFGR_D1CPRE_SYSCLK) +#define STM32_SYSCLK_FREQUENCY (STM32_PLL1P_FREQUENCY) +#define STM32_CPUCLK_FREQUENCY (STM32_SYSCLK_FREQUENCY / 1) + +/* AHB and APB Clock Configuration + * + * AHB clock (HCLK) is SYSCLK/2 + * HCLK1 = HCLK2 = HCLK3 = HCLK4 + */ + +#define STM32_RCC_D1CFGR_HPRE RCC_D1CFGR_HPRE_SYSCLKd2 +#define STM32_ACLK_FREQUENCY (STM32_SYSCLK_FREQUENCY / 2) +#define STM32_HCLK_FREQUENCY (STM32_SYSCLK_FREQUENCY / 2) + +/* APB1 clock (PCLK1) is HCLK/2 */ + +#define STM32_RCC_D2CFGR_D2PPRE1 RCC_D2CFGR_D2PPRE1_HCLKd2 +#define STM32_PCLK1_FREQUENCY (STM32_HCLK_FREQUENCY/2) + +/* APB2 clock (PCLK2) is HCLK/2 */ + +#define STM32_RCC_D2CFGR_D2PPRE2 RCC_D2CFGR_D2PPRE2_HCLKd2 +#define STM32_PCLK2_FREQUENCY (STM32_HCLK_FREQUENCY/2) + +/* APB3 clock (PCLK3) is HCLK/2 */ + +#define STM32_RCC_D1CFGR_D1PPRE RCC_D1CFGR_D1PPRE_HCLKd2 +#define STM32_PCLK3_FREQUENCY (STM32_HCLK_FREQUENCY/2) + +/* APB4 clock (PCLK4) is HCLK/2 */ + +#define STM32_RCC_D3CFGR_D3PPRE RCC_D3CFGR_D3PPRE_HCLKd2 +#define STM32_PCLK4_FREQUENCY (STM32_HCLK_FREQUENCY/2) + +/* Timer Clock Frequencies + * + * Timers driven from APB1 will be twice PCLK1 + */ + +#define STM32_APB1_TIM2_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM3_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM4_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM5_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM6_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM7_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM12_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM13_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM14_CLKIN (2*STM32_PCLK1_FREQUENCY) + +/* Timers driven from APB2 will be twice PCLK2 */ + +#define STM32_APB2_TIM1_CLKIN (2*STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM8_CLKIN (2*STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM15_CLKIN (2*STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM16_CLKIN (2*STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM17_CLKIN (2*STM32_PCLK2_FREQUENCY) + +/* Kernel Clock Configuration + * + * Note: Refer to Table 54 in STM32H7 Reference Manual (RM0433) + */ + +/* According to the STM32H753ZI is recommended to use PCLK for I2C bus. + * I2C123 clock source - PCLK1 (100 MHz) + * #define STM32_RCC_D2CCIP2R_I2C123SRC RCC_D2CCIP2R_I2C123SEL_PCLK1 + * + * I2C4 clock source - PCLK4 (100 MHz) + * #define STM32_RCC_D3CCIPR_I2C4SRC RCC_D3CCIPR_I2C4SEL_PCLK4 + * + * However, it seems NuttX has a bug in the I2C driver that only allow I2C + * using HSI as clock source and it has to be configured at 16 MHz. + * + * Hence, this board will use the following workaround until the NuttX + * I2C driver is fixed. + */ + +#define STM32_HSI_FREQUENCY 16000000ul /* 64MHz / 4 = 16MHz */ + +/* I2C123 clock source - HSI (16 MHz) - Required by NuttX I2C driver */ + +#define STM32_RCC_D2CCIP2R_I2C123SRC RCC_D2CCIP2R_I2C123SEL_HSI + +/* I2C4 clock source - HSI (16 MHz) - Required by NuttX I2C driver */ + +#define STM32_RCC_D3CCIPR_I2C4SRC RCC_D3CCIPR_I2C4SEL_HSI + +/* SPI123 clock source - PLL1Q */ + +#define STM32_RCC_D2CCIP1R_SPI123SRC RCC_D2CCIP1R_SPI123SEL_PLL1 + +/* SPI45 clock source - PLL2P */ + +#define STM32_RCC_D2CCIP1R_SPI45SRC RCC_D2CCIP1R_SPI45SEL_PLL2 + +/* SPI6 clock source - PCLK4 */ + +#define STM32_RCC_D3CCIPR_SPI6SRC RCC_D3CCIPR_SPI6SEL_PCLK4 + +/* USB 1 and 2 clock source - HSI48 */ + +#define STM32_RCC_D2CCIP2R_USBSRC RCC_D2CCIP2R_USBSEL_HSI48 + +/* ADC 1 2 3 clock source - PLL2P */ + +#define STM32_RCC_D3CCIPR_ADCSRC RCC_D3CCIPR_ADCSEL_PLL2 + +/* FDCAN 1 2 clock source selection based on HSE config */ + +#ifdef CONFIG_NUCLEO_H753ZI_HSE_25MHZ +/* FDCAN 1 2 clock source - HSE (25 MHz direct) */ +# define STM32_RCC_D2CCIP1R_FDCANSEL RCC_D2CCIP1R_FDCANSEL_HSE +# define STM32_FDCANCLK STM32_HSE_FREQUENCY +#else +/* FDCAN 1 2 clock source - PLL2Q (25 MHz for CAN compliance) */ +# define STM32_RCC_D2CCIP1R_FDCANSEL RCC_D2CCIP1R_FDCANSEL_PLL2 +# define STM32_FDCANCLK STM32_PLL2Q_FREQUENCY +#endif + +/* SDMMC 1 2 clock source - PLL1Q */ + +#define STM32_RCC_D1CCIPR_SDMMCSEL RCC_D1CCIPR_SDMMC_PLL1 + +/* FMC clock source - HCLK */ + +#define BOARD_FMC_CLK RCC_D1CCIPR_FMCSEL_HCLK + +/* Flash Configuration ******************************************************/ + +/* FLASH wait states + * + * ------------ ---------- ----------- + * Vcore MAX ACLK WAIT STATES + * ------------ ---------- ----------- + * 1.15-1.26 V 70 MHz 0 + * (VOS1 level) 140 MHz 1 + * 210 MHz 2 + * 275 MHz 3 + * 480 MHz 4 + * 1.05-1.15 V 55 MHz 0 + * (VOS2 level) 110 MHz 1 + * 165 MHz 2 + * 220 MHz 3 + * 0.95-1.05 V 45 MHz 0 + * (VOS3 level) 90 MHz 1 + * 135 MHz 2 + * 180 MHz 3 + * 225 MHz 4 + * ------------ ---------- ----------- + */ + +#define BOARD_FLASH_WAITSTATES 4 + +/**************************************************************************** + * SECTION 2: COMMUNICATION BUSES + ****************************************************************************/ + +/**************************************************************************** + * UART/USART Configuration + ****************************************************************************/ + +/* USART3 (Nucleo Virtual Console) */ + +#define GPIO_USART3_RX (GPIO_USART3_RX_3 | GPIO_SPEED_100MHz) /* PD9 */ +#define GPIO_USART3_TX (GPIO_USART3_TX_3 | GPIO_SPEED_100MHz) /* PD8 */ + +/* USART6 (Arduino Serial Shield) */ + +#define GPIO_USART6_RX (GPIO_USART6_RX_2 | GPIO_SPEED_100MHz) /* PG9 */ +#define GPIO_USART6_TX (GPIO_USART6_TX_2 | GPIO_SPEED_100MHz) /* PG14 */ + +/* UART/USART DMA Mappings */ + +#define DMAMAP_USART3_RX DMAMAP_DMA12_USART3RX_0 +#define DMAMAP_USART3_TX DMAMAP_DMA12_USART3TX_1 +#define DMAMAP_USART6_RX DMAMAP_DMA12_USART6RX_1 +#define DMAMAP_USART6_TX DMAMAP_DMA12_USART6TX_0 + +/* TODO: Add USART1, USART2, UART4, UART5, UART7, UART8 configurations */ + +/**************************************************************************** + * SPI Configuration + ****************************************************************************/ + +/* SPI GPIO Definitions - Based on Kconfig selections */ + +#define GPIO_SPI_CS_SPEED GPIO_SPEED_50MHz /* CS pin speed */ + +/* SPI1 Pin Configurations */ + +#ifdef CONFIG_NUCLEO_H753ZI_SPI1_ENABLE +# ifdef CONFIG_NUCLEO_H753ZI_SPI1_PINSET_1 +# define GPIO_SPI1_SCK GPIO_SPI1_SCK_1 /* PA5 */ +# define GPIO_SPI1_MISO GPIO_SPI1_MISO_1 /* PA6 */ +# define GPIO_SPI1_MOSI GPIO_SPI1_MOSI_1 /* PA7 */ +# elif defined(CONFIG_NUCLEO_H753ZI_SPI1_PINSET_2) +# define GPIO_SPI1_SCK GPIO_SPI1_SCK_2 /* PB3 */ +# define GPIO_SPI1_MISO GPIO_SPI1_MISO_2 /* PB4 */ +# define GPIO_SPI1_MOSI GPIO_SPI1_MOSI_2 /* PB5 */ +# elif defined(CONFIG_NUCLEO_H753ZI_SPI1_PINSET_3) +# define GPIO_SPI1_SCK GPIO_SPI1_SCK_3 /* PG11 */ +# define GPIO_SPI1_MISO GPIO_SPI1_MISO_3 /* PG9 */ +# define GPIO_SPI1_MOSI GPIO_SPI1_MOSI_3 /* PD7 */ +# endif +#endif /* CONFIG_NUCLEO_H753ZI_SPI1_ENABLE */ + +/* SPI2 Pin Configurations */ + +#ifdef CONFIG_NUCLEO_H753ZI_SPI2_ENABLE +# ifdef CONFIG_NUCLEO_H753ZI_SPI2_PINSET_1 +# define GPIO_SPI2_SCK GPIO_SPI2_SCK_4 /* PB13 */ +# define GPIO_SPI2_MISO GPIO_SPI2_MISO_1 /* PB14 */ +# define GPIO_SPI2_MOSI GPIO_SPI2_MOSI_1 /* PB15 */ +# elif defined(CONFIG_NUCLEO_H753ZI_SPI2_PINSET_2) +# define GPIO_SPI2_SCK GPIO_SPI2_SCK_1 /* PA12 */ +# define GPIO_SPI2_MISO GPIO_SPI2_MISO_2 /* PC2 */ +# define GPIO_SPI2_MOSI GPIO_SPI2_MOSI_2 /* PC1 */ +# elif defined(CONFIG_NUCLEO_H753ZI_SPI2_PINSET_3) +# define GPIO_SPI2_SCK GPIO_SPI2_SCK_5 /* PD3 */ +# define GPIO_SPI2_MISO GPIO_SPI2_MISO_2 /* PC2 */ +# define GPIO_SPI2_MOSI GPIO_SPI2_MOSI_3 /* PC3 */ +# endif +#endif /* CONFIG_NUCLEO_H753ZI_SPI2_ENABLE */ + +/* SPI3 Pin Configurations */ + +#ifdef CONFIG_NUCLEO_H753ZI_SPI3_ENABLE +# ifdef CONFIG_NUCLEO_H753ZI_SPI3_PINSET_1 +# define GPIO_SPI3_SCK GPIO_SPI3_SCK_1 /* PB3 */ +# define GPIO_SPI3_MISO GPIO_SPI3_MISO_1 /* PB4 */ +# define GPIO_SPI3_MOSI GPIO_SPI3_MOSI_1 /* PB2 */ +# elif defined(CONFIG_NUCLEO_H753ZI_SPI3_PINSET_2) +# define GPIO_SPI3_SCK GPIO_SPI3_SCK_2 /* PC10 */ +# define GPIO_SPI3_MISO GPIO_SPI3_MISO_2 /* PC11 */ +# define GPIO_SPI3_MOSI GPIO_SPI3_MOSI_2 /* PC12 */ +# elif defined(CONFIG_NUCLEO_H753ZI_SPI3_PINSET_3) +# define GPIO_SPI3_SCK GPIO_SPI3_SCK_3 /* PB3 */ +# define GPIO_SPI3_MISO GPIO_SPI3_MISO_3 /* PB4 */ +# define GPIO_SPI3_MOSI GPIO_SPI3_MOSI_3 /* PB5 */ +# endif +#endif /* CONFIG_NUCLEO_H753ZI_SPI3_ENABLE */ + +/* SPI4 Pin Configurations */ + +#ifdef CONFIG_NUCLEO_H753ZI_SPI4_ENABLE +# ifdef CONFIG_NUCLEO_H753ZI_SPI4_PINSET_1 +# define GPIO_SPI4_SCK GPIO_SPI4_SCK_1 /* PE12 */ +# define GPIO_SPI4_MISO GPIO_SPI4_MISO_1 /* PE13 */ +# define GPIO_SPI4_MOSI GPIO_SPI4_MOSI_1 /* PE14 */ +# elif defined(CONFIG_NUCLEO_H753ZI_SPI4_PINSET_2) +# define GPIO_SPI4_SCK GPIO_SPI4_SCK_2 /* PE2 */ +# define GPIO_SPI4_MISO GPIO_SPI4_MISO_2 /* PE5 */ +# define GPIO_SPI4_MOSI GPIO_SPI4_MOSI_2 /* PE6 */ +# endif +#endif /* CONFIG_NUCLEO_H753ZI_SPI4_ENABLE */ + +/* SPI5 Pin Configurations */ + +#ifdef CONFIG_NUCLEO_H753ZI_SPI5_ENABLE +# ifdef CONFIG_NUCLEO_H753ZI_SPI5_PINSET_1 +# define GPIO_SPI5_SCK GPIO_SPI5_SCK_1 /* PF7 */ +# define GPIO_SPI5_MISO GPIO_SPI5_MISO_1 /* PF8 */ +# define GPIO_SPI5_MOSI GPIO_SPI5_MOSI_1 /* PF11 */ +# elif defined(CONFIG_NUCLEO_H753ZI_SPI5_PINSET_2) +# define GPIO_SPI5_SCK GPIO_SPI5_SCK_2 /* PF7 */ +# define GPIO_SPI5_MISO GPIO_SPI5_MISO_2 /* PF8 */ +# define GPIO_SPI5_MOSI GPIO_SPI5_MOSI_2 /* PF9 */ +# elif defined(CONFIG_NUCLEO_H753ZI_SPI5_PINSET_3) +# define GPIO_SPI5_SCK GPIO_SPI5_SCK_3 /* PH6 */ +# define GPIO_SPI5_MISO GPIO_SPI5_MISO_3 /* PH7 */ +# define GPIO_SPI5_MOSI GPIO_SPI5_MOSI_3 /* PF11 */ +# elif defined(CONFIG_NUCLEO_H753ZI_SPI5_PINSET_4) +# define GPIO_SPI5_SCK GPIO_SPI5_SCK_4 /* PK0 */ +# define GPIO_SPI5_MISO GPIO_SPI5_MISO_4 /* PJ11 */ +# define GPIO_SPI5_MOSI GPIO_SPI5_MOSI_4 /* PJ10 */ +# endif +#endif /* CONFIG_NUCLEO_H753ZI_SPI5_ENABLE */ + +/* SPI6 Pin Configurations */ + +#ifdef CONFIG_NUCLEO_H753ZI_SPI6_ENABLE +# ifdef CONFIG_NUCLEO_H753ZI_SPI6_PINSET_1 +# define GPIO_SPI6_SCK GPIO_SPI6_SCK_1 /* PG13 */ +# define GPIO_SPI6_MISO GPIO_SPI6_MISO_1 /* PG12 */ +# define GPIO_SPI6_MOSI GPIO_SPI6_MOSI_1 /* PG14 */ +# elif defined(CONFIG_NUCLEO_H753ZI_SPI6_PINSET_2) +# define GPIO_SPI6_SCK GPIO_SPI6_SCK_2 /* PA5 */ +# define GPIO_SPI6_MISO GPIO_SPI6_MISO_2 /* PA6 */ +# define GPIO_SPI6_MOSI GPIO_SPI6_MOSI_2 /* PA7 */ +# elif defined(CONFIG_NUCLEO_H753ZI_SPI6_PINSET_3) +# define GPIO_SPI6_SCK GPIO_SPI6_SCK_3 /* PB3 */ +# define GPIO_SPI6_MISO GPIO_SPI6_MISO_3 /* PB4 */ +# define GPIO_SPI6_MOSI GPIO_SPI6_MOSI_3 /* PB5 */ +# endif +#endif /* CONFIG_NUCLEO_H753ZI_SPI6_ENABLE */ + +/* SPI DMA Mappings */ + +#define DMAMAP_SPI3_RX DMAMAP_DMA12_SPI3RX_0 /* DMA1 */ +#define DMAMAP_SPI3_TX DMAMAP_DMA12_SPI3TX_0 /* DMA1 */ + +/**************************************************************************** + * I2C Pin Configurations + ****************************************************************************/ + +/* I2C1 Pin Configurations */ + +#ifdef CONFIG_NUCLEO_H753ZI_I2C1_ENABLE + +# ifdef CONFIG_NUCLEO_H753ZI_I2C1_PINSET_1 + /* AF4: I2C1 on PB6/PB7 (Arduino D10/D9) */ +# define GPIO_I2C1_SCL GPIO_I2C1_SCL_1 /* PB6 - AF4 */ +# define GPIO_I2C1_SDA GPIO_I2C1_SDA_1 /* PB7 - AF4 */ + +# elif defined(CONFIG_NUCLEO_H753ZI_I2C1_PINSET_2) + /* AF4: I2C1 on PB8/PB9 (Morpho) */ +# define GPIO_I2C1_SCL GPIO_I2C1_SCL_2 /* PB8 - AF4 */ +# define GPIO_I2C1_SDA GPIO_I2C1_SDA_2 /* PB9 - AF4 */ +# endif + +# define I2C1_FREQUENCY CONFIG_NUCLEO_H753ZI_I2C1_DEFAULT_FREQUENCY + +#endif /* CONFIG_NUCLEO_H753ZI_I2C1_ENABLE */ + +/* I2C2 Pin Configurations */ + +#ifdef CONFIG_NUCLEO_H753ZI_I2C2_ENABLE + +# ifdef CONFIG_NUCLEO_H753ZI_I2C2_PINSET_1 + /* AF4: I2C2 on PB10/PB11 */ +# define GPIO_I2C2_SCL GPIO_I2C2_SCL_1 /* PB10 - AF4 */ +# define GPIO_I2C2_SDA GPIO_I2C2_SDA_1 /* PB11 - AF4 */ + +# elif defined(CONFIG_NUCLEO_H753ZI_I2C2_PINSET_2) + /* AF4: I2C2 on PF1/PF0 */ +# define GPIO_I2C2_SCL GPIO_I2C2_SCL_2 /* PF1 - AF4 */ +# define GPIO_I2C2_SDA GPIO_I2C2_SDA_2 /* PF0 - AF4 */ + +# elif defined(CONFIG_NUCLEO_H753ZI_I2C2_PINSET_3) + /* AF4: I2C2 on PH4/PH5 */ +# define GPIO_I2C2_SCL GPIO_I2C2_SCL_3 /* PH4 - AF4 */ +# define GPIO_I2C2_SDA GPIO_I2C2_SDA_3 /* PH5 - AF4 */ +# endif + +# define I2C2_FREQUENCY CONFIG_NUCLEO_H753ZI_I2C2_DEFAULT_FREQUENCY + +#endif /* CONFIG_NUCLEO_H753ZI_I2C2_ENABLE */ + +/* I2C3 Pin Configurations */ + +#ifdef CONFIG_NUCLEO_H753ZI_I2C3_ENABLE + +# ifdef CONFIG_NUCLEO_H753ZI_I2C3_PINSET_1 + /* AF4: I2C3 on PA8/PC9 */ +# define GPIO_I2C3_SCL GPIO_I2C3_SCL_1 /* PA8 - AF4 */ +# define GPIO_I2C3_SDA GPIO_I2C3_SDA_1 /* PC9 - AF4 */ + +# elif defined(CONFIG_NUCLEO_H753ZI_I2C3_PINSET_2) + /* AF4: I2C3 on PH7/PH8 */ +# define GPIO_I2C3_SCL GPIO_I2C3_SCL_2 /* PH7 - AF4 */ +# define GPIO_I2C3_SDA GPIO_I2C3_SDA_2 /* PH8 - AF4 */ +# endif + +# define I2C3_FREQUENCY CONFIG_NUCLEO_H753ZI_I2C3_DEFAULT_FREQUENCY + +#endif /* CONFIG_NUCLEO_H753ZI_I2C3_ENABLE */ + +/* I2C4 Pin Configurations */ + +#ifdef CONFIG_NUCLEO_H753ZI_I2C4_ENABLE + +# ifdef CONFIG_NUCLEO_H753ZI_I2C4_PINSET_1 + /* AF4: I2C4 on PD12/PD13 */ +# define GPIO_I2C4_SCL GPIO_I2C4_SCL_1 /* PD12 - AF4 */ +# define GPIO_I2C4_SDA GPIO_I2C4_SDA_1 /* PD13 - AF4 */ + +# elif defined(CONFIG_NUCLEO_H753ZI_I2C4_PINSET_2) + /* AF4: I2C4 on PF14/PF15 */ +# define GPIO_I2C4_SCL GPIO_I2C4_SCL_2 /* PF14 - AF4 */ +# define GPIO_I2C4_SDA GPIO_I2C4_SDA_2 /* PF15 - AF4 */ + +# elif defined(CONFIG_NUCLEO_H753ZI_I2C4_PINSET_3) + /* AF4: I2C4 on PH11/PH12 */ +# define GPIO_I2C4_SCL GPIO_I2C4_SCL_3 /* PH11 - AF4 */ +# define GPIO_I2C4_SDA GPIO_I2C4_SDA_3 /* PH12 - AF4 */ + +# elif defined(CONFIG_NUCLEO_H753ZI_I2C4_PINSET_4) + /* AF6: I2C4 on PB6/PB7 (shared with I2C1!) */ +# define GPIO_I2C4_SCL GPIO_I2C4_SCL_4 /* PB6 - AF6 */ +# define GPIO_I2C4_SDA GPIO_I2C4_SDA_4 /* PB7 - AF6 */ + +# elif defined(CONFIG_NUCLEO_H753ZI_I2C4_PINSET_5) + /* AF6: I2C4 on PB8/PB9 (shared with I2C1!) */ +# define GPIO_I2C4_SCL GPIO_I2C4_SCL_5 /* PB8 - AF6 */ +# define GPIO_I2C4_SDA GPIO_I2C4_SDA_5 /* PB9 - AF6 */ +# endif + +# define I2C4_FREQUENCY CONFIG_NUCLEO_H753ZI_I2C4_DEFAULT_FREQUENCY + +#endif /* CONFIG_NUCLEO_H753ZI_I2C4_ENABLE */ + +/**************************************************************************** + * I3C Configuration (Placeholder) + ****************************************************************************/ + +/* TODO: Add I3C support when needed + * I3C1: SCL=PB6, SDA=PB7 (can share with I2C1) + * I3C2: SCL=PB10, SDA=PB11 + */ + +/**************************************************************************** + * I2S Configuration (Placeholder) + ****************************************************************************/ + +/* TODO: Add I2S support when needed + * I2S1: mapped to SPI1 pins with audio-specific AF + * I2S2: mapped to SPI2 pins with audio-specific AF + * I2S3: mapped to SPI3 pins with audio-specific AF + */ + +/**************************************************************************** + * CAN/FDCAN Configuration + ****************************************************************************/ + +/* FDCAN1 GPIO Configuration */ + +#define GPIO_CAN1_RX GPIO_CAN1_RX_2 /* PB8 */ +#define GPIO_CAN1_TX GPIO_CAN1_TX_2 /* PB9 */ + +/* TODO: Add FDCAN2 configuration when needed */ + +/**************************************************************************** + * Ethernet Configuration + ****************************************************************************/ + +/* PIN CONFLICTS + * + * -------------------------------------------------------------------------- + * | PB13 | RMII | JP6: ON | I2S_A_CK | + * | | TXD1 | | | + * -------------------------------------------------------------------------- + */ + +/* UM2407 REV 4, page 28/49 + * + * By default nucleo-h753 has Solder Bridges 'ON' (SBXY: ON). + * MCU pins are already connected to Ethernet connector. + * Hence, no connection for these pins from ST Zio or Morpho connectors + * + * ------------------------------------------------------------------------- + * | | | | | | + * | pin_name | function | Config | conflict | config when using| + * | | | ST ZIO CON | ST ZIO CON | ST ZIO or morpho | + * ------------------------------------------------------------------------- + * | PA1 | RMII ref. | SB57: ON | NO | SB57: OFF | + * | | clock | | | | + * ------------------------------------------------------------------------- + * | PA2 | RMII | SB72: ON | NO | SB72: OFF | + * | | MDIO | | | | + * ------------------------------------------------------------------------- + * | PC1 | RMII | SB64: ON | NO | SB64: OFF | + * | | MDC | | | | + * ------------------------------------------------------------------------- + * | PA7 | RMII RX | SB31: ON | NO | SB31: OFF | + * | | data valid | | | | + * ------------------------------------------------------------------------- + * | PC4 | RMII | SB36: ON | NO | SB36: OFF | + * | | RXD0 | | | | + * ------------------------------------------------------------------------- + * | PC5 | RMII | SB29: ON | NO | SB29: OFF | + * | | RXD1 | | | | + * ------------------------------------------------------------------------- + * | PG11 | RMII | SB27: ON | NO | SB27: OFF | + * | | TX enable | | | | + * ------------------------------------------------------------------------- + * | PG13 | RMII | SB30: ON | NO | SB30: OFF | + * | | TXD0 | | | | + * ------------------------------------------------------------------------- + * | PB13 | RMII | JP6: ON | I2S_A_CK | JP6: OFF | + * | | TXD1 | | | | + * ------------------------------------------------------------------------- + */ + +#define GPIO_ETH_RMII_REF_CLK \ + (GPIO_ETH_RMII_REF_CLK_0|GPIO_SPEED_100MHz) /* PA1*/ +#define GPIO_ETH_RMII_CRS_DV \ + (GPIO_ETH_RMII_CRS_DV_0 |GPIO_SPEED_100MHz) /* PA7*/ +#define GPIO_ETH_RMII_TX_EN \ + (GPIO_ETH_RMII_TX_EN_2 |GPIO_SPEED_100MHz) /* PG11*/ +#define GPIO_ETH_RMII_TXD0 \ + (GPIO_ETH_RMII_TXD0_2 |GPIO_SPEED_100MHz) /* PG13*/ +#define GPIO_ETH_RMII_TXD1 \ + (GPIO_ETH_RMII_TXD1_1 |GPIO_SPEED_100MHz) /* PB13*/ +#define GPIO_ETH_RMII_RXD0 \ + (GPIO_ETH_RMII_RXD0_0 |GPIO_SPEED_100MHz) /* PC4*/ +#define GPIO_ETH_RMII_RXD1 \ + (GPIO_ETH_RMII_RXD1_0 |GPIO_SPEED_100MHz) /* PC5*/ +#define GPIO_ETH_MDIO \ + (GPIO_ETH_MDIO_0 |GPIO_SPEED_100MHz) /* PA2*/ +#define GPIO_ETH_MDC \ + (GPIO_ETH_MDC_0 |GPIO_SPEED_100MHz) /* PC1*/ + +/* TODO: Add Ethernet PHY control pins (reset, interrupt, etc) */ + +/**************************************************************************** + * USB Configuration + ****************************************************************************/ + +/* USB OTG FS GPIO Definitions */ + +#define GPIO_OTGFS_DM (GPIO_OTGFS_DM_0 | GPIO_SPEED_100MHz) +#define GPIO_OTGFS_DP (GPIO_OTGFS_DP_0 | GPIO_SPEED_100MHz) +#define GPIO_OTGFS_ID (GPIO_OTGFS_ID_0 | GPIO_SPEED_100MHz) + +/* TODO: Add USB OTG HS configuration when needed */ + +/**************************************************************************** + * SDMMC Configuration + ****************************************************************************/ + +/* SDMMC Clock Configuration - Frequency Stability Across HSE Sources + * + * These SDMMC clock dividers remain valid for ALL HSE source configurations + * because PLL1Q is maintained at a constant 200 MHz regardless of HSE freq. + * + * Clock Frequency Verification Table: + * +----------------+--------+---------+-------------+------------------+ + * | HSE Source | VCO | PLL1Q | SDMMC Init | SDMMC Transfer | + * +----------------+--------+---------+-------------+------------------+ + * | ST-LINK 8MHz | 800MHz | 200MHz | 416 kHz | 50 MHz | + * | Crystal 25MHz | 800MHz | 200MHz | 416 kHz | 50 MHz | + * +----------------+--------+---------+-------------+------------------+ + * + * Calculation for 8 MHz HSE: + * SDMMC_Init = PLL1Q / (2*240) = 200MHz / 480 = 416 kHz (SD compliant) + * SDMMC_Xfer = PLL1Q / (2*2) = 200MHz / 4 = 50 MHz (25 MB/s) + * + * Calculation for 25 MHz HSE: + * SDMMC_Init = PLL1Q / (2*240) = 200MHz / 480 = 416 kHz (SD compliant) + * SDMMC_Xfer = PLL1Q / (2*2) = 200MHz / 4 = 50 MHz (25 MB/s) + */ + +/* Init 400kHz, PLL1Q/(2*240) */ + +#define STM32_SDMMC_INIT_CLKDIV (240 << STM32_SDMMC_CLKCR_CLKDIV_SHIFT) + +/* Transfer at max speed, PLL1Q/(2*2) */ + +#define STM32_SDMMC_MMCXFR_CLKDIV (2 << STM32_SDMMC_CLKCR_CLKDIV_SHIFT) +#define STM32_SDMMC_SDXFR_CLKDIV (2 << STM32_SDMMC_CLKCR_CLKDIV_SHIFT) +#define STM32_SDMMC_CLKCR_EDGE STM32_SDMMC_CLKCR_NEGEDGE + +/* SDMMC clock source - PLL1Q */ + +#define STM32_RCC_D1CCIPR_SDMMCSEL RCC_D1CCIPR_SDMMC_PLL1 + +/* TODO: Add SDMMC GPIO pin configurations when needed */ + +/**************************************************************************** + * LVDS Configuration (Placeholder) + ****************************************************************************/ + +/* TODO: Add LVDS support when needed + * STM32H753 does not have built-in LVDS + * Requires external LVDS serializer/deserializer + */ + +/**************************************************************************** + * 1-Wire Configuration (Placeholder) + ****************************************************************************/ + +/* TODO: Add 1-Wire (OneWire) support when needed + * Typically implemented via UART in half-duplex mode + * or using bit-banging on GPIO + */ + +/**************************************************************************** + * QSPI Configuration (Placeholder) + ****************************************************************************/ + +/* TODO: Add QSPI support when needed + * QSPI1: Available for external flash memory + */ + +/**************************************************************************** + * FMC Configuration (Placeholder) + ****************************************************************************/ + +/* TODO: Add FMC support when needed + * FMC: For external SRAM, NOR, NAND, PSRAM + */ + +/**************************************************************************** + * SAI Configuration (Placeholder) + ****************************************************************************/ + +/* TODO: Add SAI (Serial Audio Interface) support when needed + * SAI1, SAI2: For high-quality audio applications + */ + +/**************************************************************************** + * SECTION 3: GPIO (General Purpose I/O) + ****************************************************************************/ + +/**************************************************************************** + * Digital Output - LEDs + ****************************************************************************/ + +/* The Nucleo-H753ZI board has several LEDs. + * Only three are user-controllable: + * + * LD1 -> Green + * LD2 -> Orange + * LD3 -> Red + * + * Behavior depends on CONFIG_ARCH_LEDS: + * + * SYMBOL OWNER USAGE + * ---------------- -------- ------------------------------- + * CONFIG_ARCH_LEDS=n User /dev/leds + * boards/.../stm32_userleds.c + * apps/examples/leds + * + * CONFIG_ARCH_LEDS=y NuttX boards/.../stm32_autoleds.c + * + * For more information, check the Kconfig file or use menuconfig help. + */ + +/* LED index values for use with board_userled() */ + +#define BOARD_LED1 0 +#define BOARD_LED2 1 +#define BOARD_LED3 2 +#define BOARD_NLEDS 3 + +#define BOARD_LED_GREEN BOARD_LED1 +#define BOARD_LED_ORANGE BOARD_LED2 +#define BOARD_LED_RED BOARD_LED3 + +/* LED bits for use with board_userled_all() */ + +#define BOARD_LED1_BIT (1 << BOARD_LED1) +#define BOARD_LED2_BIT (1 << BOARD_LED2) +#define BOARD_LED3_BIT (1 << BOARD_LED3) + +/* If CONFIG_ARCH_LEDS is defined, usage by board port is defined in + * include/board.h and src/stm32_leds.c. + * The LEDs are used to encode OS-related events as follows: + * + * + * SYMBOL Meaning LED state + * Red Green Orange + * ---------------------- ---------------------- ----- ------ ------ + */ + +#define LED_STARTED 0 /* NuttX has been started OFF OFF OFF */ +#define LED_HEAPALLOCATE 1 /* Heap allocated OFF OFF ON */ +#define LED_IRQSENABLED 2 /* Interrupts enabled OFF ON OFF */ +#define LED_STACKCREATED 3 /* Idle stack created OFF ON ON */ +#define LED_INIRQ 4 /* In an interrupt N/C N/C GLOW */ +#define LED_SIGNAL 5 /* In a signal handler N/C GLOW N/C */ +#define LED_ASSERTION 6 /* An assertion failed GLOW N/C GLOW */ +#define LED_PANIC 7 /* System has crashed Blink OFF N/C */ +#define LED_IDLE 8 /* MCU is in sleep mode ON OFF OFF */ + +/* TODO: Add support for additional GPIO outputs (relays, external LEDs, + * etc) + */ + +/**************************************************************************** + * Digital Input - Buttons + ****************************************************************************/ + +/* Dynamic Button Configuration with EXTI Conflict Prevention + * + * Nucleo-H753ZI has only one User-Button. However, might be good to keep + * the system ready to support until 32 buttons. This is what will be done + * here. + * + * CRITICAL: STM32 EXTI lines are shared across ports! + * Only ONE pin NUMBER can be used as interrupt source at a time. + * Example of CONFLICT: + * PG3 + PE3 (both use EXTI3 -> only last one works) + * PG3 + PE4 (EXTI3 and EXTI4 -> both work) + * + * Example for a configuration for 10 buttons: + * PC13, PB1, PB2, PD0, PD4, PD5, PE6, PE7, PF8, PF9 + * EXTI: 13, 1, 2, 0, 4, 5, 6, 7, 8, 9 + * + * NO EXTERNAL INTERRUPTION CONFLICTS! + */ + +/* Define NUM_BUTTONS FIRST */ + +#ifdef CONFIG_NUCLEO_H753ZI_BUTTON_SUPPORT +# define NUM_BUTTONS CONFIG_NUCLEO_H753ZI_BUTTON_COUNT +#else +# define NUM_BUTTONS 0 +#endif + +/* Button definitions - only if enabled */ + +#ifdef CONFIG_NUCLEO_H753ZI_BUTTON_SUPPORT + +/* Built-in button */ + +# ifdef CONFIG_NUCLEO_H753ZI_BUTTON_BUILTIN +# define BUTTON_BUILT_IN 0 +# define BUTTON_BUILT_IN_BIT (1 << 0) +# endif + +/* External buttons */ + +# if NUM_BUTTONS > 1 +# define BUTTON_1 1 +# define BUTTON_1_BIT (1 << 1) +# endif +# if NUM_BUTTONS > 2 +# define BUTTON_2 2 +# define BUTTON_2_BIT (1 << 2) +# endif +# if NUM_BUTTONS > 3 +# define BUTTON_3 3 +# define BUTTON_3_BIT (1 << 3) +# endif +# if NUM_BUTTONS > 4 +# define BUTTON_4 4 +# define BUTTON_4_BIT (1 << 4) +# endif +# if NUM_BUTTONS > 5 +# define BUTTON_5 5 +# define BUTTON_5_BIT (1 << 5) +# endif +# if NUM_BUTTONS > 6 +# define BUTTON_6 6 +# define BUTTON_6_BIT (1 << 6) +# endif +# if NUM_BUTTONS > 7 +# define BUTTON_7 7 +# define BUTTON_7_BIT (1 << 7) +# endif +# if NUM_BUTTONS > 8 +# define BUTTON_8 8 +# define BUTTON_8_BIT (1 << 8) +# endif +# if NUM_BUTTONS > 9 +# define BUTTON_9 9 +# define BUTTON_9_BIT (1 << 9) +# endif +# if NUM_BUTTONS > 10 +# define BUTTON_10 10 +# define BUTTON_10_BIT (1 << 10) +# endif +# if NUM_BUTTONS > 11 +# define BUTTON_11 11 +# define BUTTON_11_BIT (1 << 11) +# endif +# if NUM_BUTTONS > 12 +# define BUTTON_12 12 +# define BUTTON_12_BIT (1 << 12) +# endif +# if NUM_BUTTONS > 13 +# define BUTTON_13 13 +# define BUTTON_13_BIT (1 << 13) +# endif +# if NUM_BUTTONS > 14 +# define BUTTON_14 14 +# define BUTTON_14_BIT (1 << 14) +# endif +# if NUM_BUTTONS > 15 +# define BUTTON_15 15 +# define BUTTON_15_BIT (1 << 15) +# endif +# if NUM_BUTTONS > 16 +# define BUTTON_16 16 +# define BUTTON_16_BIT (1 << 16) +# endif +# if NUM_BUTTONS > 17 +# define BUTTON_17 17 +# define BUTTON_17_BIT (1 << 17) +# endif +# if NUM_BUTTONS > 18 +# define BUTTON_18 18 +# define BUTTON_18_BIT (1 << 18) +# endif +# if NUM_BUTTONS > 19 +# define BUTTON_19 19 +# define BUTTON_19_BIT (1 << 19) +# endif +# if NUM_BUTTONS > 20 +# define BUTTON_20 20 +# define BUTTON_20_BIT (1 << 20) +# endif +# if NUM_BUTTONS > 21 +# define BUTTON_21 21 +# define BUTTON_21_BIT (1 << 21) +# endif +# if NUM_BUTTONS > 22 +# define BUTTON_22 22 +# define BUTTON_22_BIT (1 << 22) +# endif +# if NUM_BUTTONS > 23 +# define BUTTON_23 23 +# define BUTTON_23_BIT (1 << 23) +# endif +# if NUM_BUTTONS > 24 +# define BUTTON_24 24 +# define BUTTON_24_BIT (1 << 24) +# endif +# if NUM_BUTTONS > 25 +# define BUTTON_25 25 +# define BUTTON_25_BIT (1 << 25) +# endif +# if NUM_BUTTONS > 26 +# define BUTTON_26 26 +# define BUTTON_26_BIT (1 << 26) +# endif +# if NUM_BUTTONS > 27 +# define BUTTON_27 27 +# define BUTTON_27_BIT (1 << 27) +# endif +# if NUM_BUTTONS > 28 +# define BUTTON_28 28 +# define BUTTON_28_BIT (1 << 28) +# endif +# if NUM_BUTTONS > 29 +# define BUTTON_29 29 +# define BUTTON_29_BIT (1 << 29) +# endif +# if NUM_BUTTONS > 30 +# define BUTTON_30 30 +# define BUTTON_30_BIT (1 << 30) +# endif +# if NUM_BUTTONS > 31 +# define BUTTON_31 31 +# define BUTTON_31_BIT (1 << 31) +# endif + +/* IRQ button range */ + +# define MIN_IRQBUTTON 0 +# define MAX_IRQBUTTON (NUM_BUTTONS - 1) +# define NUM_IRQBUTTONS NUM_BUTTONS + +#else /* !CONFIG_NUCLEO_H753ZI_BUTTON_SUPPORT */ + +# define NUM_BUTTONS 0 +# define MIN_IRQBUTTON 0 +# define MAX_IRQBUTTON 0 +# define NUM_IRQBUTTONS 0 + +#endif /* CONFIG_NUCLEO_H753ZI_BUTTON_SUPPORT */ + +/* TODO: Add support for additional digital inputs (sensors, switches, etc) */ + +/**************************************************************************** + * Analog Input - ADC + ****************************************************************************/ + +/* ADC GPIO Definitions */ + +#define GPIO_ADC123_INP10 GPIO_ADC123_INP10_0 /* PC0 */ +#define GPIO_ADC123_INP12 GPIO_ADC123_INP12_0 /* PC2 */ +#define GPIO_ADC123_INP11 GPIO_ADC123_INP11_0 /* PC1 */ +#define GPIO_ADC12_INP13 GPIO_ADC12_INP13_0 /* PC3 */ +#define GPIO_ADC12_INP15 GPIO_ADC12_INP15_0 /* PA3 */ +#define GPIO_ADC12_INP18 GPIO_ADC12_INP18_0 /* PA4 */ +#define GPIO_ADC12_INP19 GPIO_ADC12_INP19_0 /* PA5 */ +#define GPIO_ADC12_INP14 GPIO_ADC12_INP14_0 /* PA2 */ +#define GPIO_ADC123_INP7 GPIO_ADC12_INP7_0 /* PA7 */ +#define GPIO_ADC12_INP5 GPIO_ADC12_INP5_0 /* PB1 */ +#define GPIO_ADC12_INP3 GPIO_ADC12_INP3_0 /* PA6 */ +#define GPIO_ADC12_INP4 GPIO_ADC12_INP4_0 /* PC4 */ +#define GPIO_ADC12_INP8 GPIO_ADC12_INP8_0 /* PC5 */ +#define GPIO_ADC2_INP2 GPIO_ADC2_INP2_0 /* PF13 */ + +/* TODO: Add ADC3 channel definitions when needed */ + +/**************************************************************************** + * Analog Output - DAC (Placeholder) + ****************************************************************************/ + +/* TODO: Add DAC support when needed + * DAC1_OUT1: PA4 + * DAC1_OUT2: PA5 + */ + +/**************************************************************************** + * PWM/Timer Output + ****************************************************************************/ + +/* Timer GPIO Definitions */ + +/* TIM1 */ + +#define GPIO_TIM1_CH1OUT (GPIO_TIM1_CH1OUT_2 | GPIO_SPEED_50MHz) /* PE9 */ +#define GPIO_TIM1_CH1NOUT (GPIO_TIM1_CH1NOUT_3 | GPIO_SPEED_50MHz) /* PE8 */ +#define GPIO_TIM1_CH2OUT (GPIO_TIM1_CH2OUT_2 | GPIO_SPEED_50MHz) /* PE11 */ +#define GPIO_TIM1_CH2NOUT (GPIO_TIM1_CH2NOUT_3 | GPIO_SPEED_50MHz) /* PE10 */ +#define GPIO_TIM1_CH3OUT (GPIO_TIM1_CH3OUT_2 | GPIO_SPEED_50MHz) /* PE13 */ +#define GPIO_TIM1_CH3NOUT (GPIO_TIM1_CH3NOUT_3 | GPIO_SPEED_50MHz) /* PE12 */ +#define GPIO_TIM1_CH4OUT (GPIO_TIM1_CH4OUT_2 | GPIO_SPEED_50MHz) /* PE14 */ + +/* TODO: Add TIM2-8, TIM12-17 PWM configurations when needed */ + +/**************************************************************************** + * External Interrupts (Additional) + ****************************************************************************/ + +/* TODO: Add support for additional external interrupt sources + * beyond buttons (sensors, alarms, etc) + */ + +/**************************************************************************** + * Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_STM32H7_SPI + +/** + * Name: stm32_spi_register_cs_device + * + * Description: + * Register a CS device for a specific SPI bus and device ID. + * + * Input Parameters: + * spi_bus - SPI bus number (1-6) + * devid - Device ID (0-15) + * cs_pin - CS pin string (e.g., "PF1") + * active_low - true if CS is active low, false if active high + * + * Returned Value: + * OK on success, negative errno on error + */ + +int stm32_spi_register_cs_device(int spi_bus, uint32_t devid, + const char *cs_pin, bool active_low); + +/** + * Name: stm32_spi_unregister_cs_device + * + * Description: + * Unregister a CS device. + * + * Input Parameters: + * spi_bus - SPI bus number (1-6) + * devid - Device ID + * + * Returned Value: + * OK on success, negative errno on error + */ + +int stm32_spi_unregister_cs_device(int spi_bus, uint32_t devid); + +#endif /* CONFIG_STM32H7_SPI */ + +int stm32_spi_initialize(void); + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM_STM32H7_NUCLEO_H753ZI_INCLUDE_BOARD_H */ diff --git a/boards/arm/stm32h7/nucleo-h753zi/include/readme.txt b/boards/arm/stm32h7/nucleo-h753zi/include/readme.txt new file mode 100644 index 0000000000000..29741d2a5235f --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/include/readme.txt @@ -0,0 +1,420 @@ +README +====== + +ST Nucleo-H753ZI Board Support for Apache NuttX +================================================ + + MCU: STM32H753ZIT6 (Arm Cortex-M7, 480 MHz max, 2 MB Flash, 1 MB RAM) + Board: NUCLEO-H753ZI (MB1364) + Vendor: STMicroelectronics + NuttX: 12.11+ + +References +---------- + + UM2407 - Nucleo-H753ZI User Manual (Rev 4) + DS12110 - STM32H753ZI Datasheet (Rev 9) + RM0433 - STM32H7x3 Reference Manual + +Board Overview +-------------- + + The Nucleo-H753ZI is a development board featuring the STM32H753ZIT6 + microcontroller with the following on-board resources: + + - 3 user LEDs: LD1 (Green/PB0), LD2 (Orange/PE1), LD3 (Red/PB14) + - 1 user push-button: B1 (PC13) + - ST-LINK/V3 debugger/programmer (provides 8 MHz MCO to MCU HSE) + - Ethernet connector (RMII interface) + - USB OTG FS connector + - Arduino Uno V3 expansion headers (Zio) + - ST Morpho expansion headers + +Menuconfig-Driven Architecture +------------------------------- + + This board support package is designed around a menuconfig-driven + architecture. Nearly all hardware options are selectable at build + time through Kconfig without modifying any source files. This + includes: + + Clock Source Selection + Via menuconfig: Board Clock Configuration -> HSE clock source + - 8 MHz (default): Uses ST-LINK MCO, no hardware changes needed + - 25 MHz: Uses external crystal at X3 (requires HW modification) + Both configurations produce identical system performance (see + Clock Configuration section below). + + SPI Bus and Pin Set Selection + Via menuconfig: SPI Configuration -> SPIx Configuration + - Enable/disable each SPI bus independently (SPI1-SPI6) + - Select alternative pin sets per bus (2-4 options per bus) + - CS pins are NOT configured at the SPI bus level; each + peripheral registers its own CS pin dynamically at runtime + + I2C Bus, Pin Set and Frequency Selection + Via menuconfig: I2C Configuration -> I2Cx Configuration + - Enable/disable each I2C bus independently (I2C1-I2C4) + - Select alternative pin sets per bus (2-5 options per bus) + - Configure default bus frequency per bus (100/400/1000 kHz) + - Kconfig prevents conflicting pin assignments at compile time + (e.g., I2C1 pinset 1 and I2C4 pinset 4 share PB6/PB7) + + LED Control Mode + Via menuconfig: LED Control Mode + - Automatic: Kernel controls LEDs to indicate OS state + - User: Application controls LEDs via /dev/userleds + - Disabled: LED subsystem completely disabled + + Button Configuration + Via menuconfig: Button Configuration + - Enable/disable button support + - Configure number of buttons (1-32) + - Include/exclude built-in button (PC13) + - Specify additional button GPIO pins via string + (e.g., "PF15,PG14,PG9,PE0") + - Compile-time EXTI conflict validation + + Peripheral Module Configuration + Via menuconfig: SPI MODULES / I2C MODULES + - ST7796 LCD (SPI): bus, CS pin, DC pin, RESET pin, LED pin, + color depth, orientation, rotation, framebuffer size, + SPI frequency + - MFRC522 RFID (SPI): bus, CS pin, CS polarity, IRQ pin, + IRQ trigger type + - SSD1306 OLED (I2C): bus, I2C address, frequency, + brightness, resolution (128x64 or 128x32), device path + +Clock Configuration +------------------- + + Available clock sources on Nucleo-H753ZI: + + HSI: 64 MHz RC factory-trimmed + CSI: 4 MHz RC oscillator + LSI: 32 kHz RC + HSE: 8 MHz from ST-LINK MCO (default) or 25 MHz crystal (X3) + LSE: 32.768 kHz crystal (X2) + HSI48: 48 MHz RC (dedicated for USB) + + Both HSE configurations produce identical system clocks: + + SYSCLK = 400 MHz (VOS1 maximum; VOS0 not used by NuttX default) + CPUCLK = 400 MHz + HCLK = 200 MHz (AHB, SYSCLK/2) + PCLK1 = 100 MHz (APB1, HCLK/2) + PCLK2 = 100 MHz (APB2, HCLK/2) + PCLK3 = 100 MHz (APB3, HCLK/2) + PCLK4 = 100 MHz (APB4, HCLK/2) + Timers = 200 MHz (2 x PCLK when APB prescaler != 1) + + PLL Summary (8 MHz HSE, default): + + PLL1: 8/1 * 100 = 800 MHz VCO + P = 400 MHz -> SYSCLK + Q = 200 MHz -> SPI1/2/3, SDMMC + R = 200 MHz + + PLL2: 8/1 * 75 = 600 MHz VCO + P = 75 MHz -> ADC1/2/3, SPI4/5 + Q = 25 MHz -> FDCAN1/2 + R = 200 MHz + + PLL3: 8/2 * 100 = 400 MHz VCO + P = 200 MHz + Q = 25 MHz + R = 40 MHz + + PLL Summary (25 MHz HSE, optional): + + PLL1: 25/5 * 160 = 800 MHz VCO (same outputs as 8 MHz config) + PLL2: 25/2 * 48 = 600 MHz VCO (same outputs; FDCAN via HSE direct) + PLL3: 25/2 * 64 = 800 MHz VCO + + Peripheral kernel clocks: + + I2C1/2/3/4 HSI 16 MHz (workaround: NuttX I2C driver requires HSI) + SPI1/2/3 PLL1Q 200 MHz + SPI4/5 PLL2P 75 MHz + SPI6 PCLK4 100 MHz + ADC1/2/3 PLL2P 75 MHz (within 80 MHz limit per DS12110) + FDCAN1/2 PLL2Q 25 MHz (8 MHz config) / HSE direct (25 MHz config) + SDMMC1/2 PLL1Q 200 MHz + USB1/2 HSI48 48 MHz + + FLASH wait states: 4 (conservative; safe for VOS1 up to 480 MHz HCLK). + Minimum required for 200 MHz HCLK at VOS1 is 2 wait states. + + Hardware configuration for 8 MHz HSE (factory default, no changes): + SB45=ON, SB44=OFF, SB46=OFF, SB3=OFF, SB4=OFF + + Hardware configuration for 25 MHz HSE (requires modification): + Install 25 MHz crystal at X3. + SB3=ON, SB4=ON, SB45=OFF, SB44=OFF, SB46=OFF + +GPIO Pin Mapping (On-board Peripherals) +---------------------------------------- + + Function Pin AF Notes + ---------------- ----- ---- ---------------------------- + LD1 (Green LED) PB0 - Output, active high + LD2 (Orange LED) PE1 - Output, active high + LD3 (Red LED) PB14 - Output, active high + B1 (User Button) PC13 EXTI Input, pull-down + USART3 TX (VCP) PD8 AF7 ST-LINK virtual COM port + USART3 RX (VCP) PD9 AF7 ST-LINK virtual COM port + USART6 TX PG14 AF7 + USART6 RX PG9 AF7 + I2C1 SCL (opt1) PB6 AF4 Arduino D10 + I2C1 SDA (opt1) PB7 AF4 Arduino D9 + I2C1 SCL (opt2) PB8 AF4 Morpho + I2C1 SDA (opt2) PB9 AF4 Morpho + FDCAN1 RX PB8 AF9 + FDCAN1 TX PB9 AF9 + USB OTG FS DM PA11 AF10 + USB OTG FS DP PA12 AF10 + USB VBUS PA9 - + ETH RMII REF_CLK PA1 AF11 + ETH RMII CRS_DV PA7 AF11 + ETH RMII TX_EN PG11 AF11 + ETH RMII TXD0 PG13 AF11 + ETH RMII TXD1 PB13 AF11 + ETH RMII RXD0 PC4 AF11 + ETH RMII RXD1 PC5 AF11 + ETH MDIO PA2 AF11 + ETH MDC PC1 AF11 + HSE IN PH0 - ST-LINK MCO (8 MHz default) + HSE OUT PH1 - Reserved (X3 crystal) + SWCLK PA14 AF0 + SWDIO PA13 AF0 + + Note: Ethernet requires solder bridge changes when using Zio/Morpho + headers. See UM2407 Rev 4, page 28 for solder bridge table. + +SPI Interfaces +-------------- + + Six SPI buses available (SPI1-SPI6). Each bus supports multiple + pin sets selectable via menuconfig. CS pins are registered + dynamically per peripheral. + + SPI bus -> kernel clock -> max SCK: + SPI1/2/3: PLL1Q (200 MHz) -> 100 MHz max SCK + SPI4/5: PLL2P (75 MHz) -> 37.5 MHz max SCK + SPI6: PCLK4 (100 MHz) -> 50 MHz max SCK + + SPI1 pin sets: + Set 1 (Arduino): PA5(SCK), PA6(MISO), PA7(MOSI) + Set 2: PB3(SCK), PB4(MISO), PB5(MOSI) + Set 3: PG11(SCK), PG9(MISO), PD7(MOSI) + + SPI2 pin sets: + Set 1: PB13(SCK), PB14(MISO), PB15(MOSI) + Set 2: PA12(SCK), PC2(MISO), PC1(MOSI) + Set 3: PD3(SCK), PC2(MISO), PC3(MOSI) + + SPI3 pin sets: + Set 1: PC10(SCK), PC11(MISO), PC12(MOSI) + Set 2: PB3(SCK), PB4(MISO), PB5(MOSI) + + SPI4 pin sets: + Set 1: PE12(SCK), PE13(MISO), PE14(MOSI) + Set 2: PE2(SCK), PE5(MISO), PE6(MOSI) + + SPI5 pin sets: + Set 1: PF7(SCK), PF8(MISO), PF9(MOSI) + Set 2: PK0(SCK), PJ11(MISO), PJ10(MOSI) + + SPI6 pin sets: + Set 1: PG13(SCK), PG12(MISO), PG14(MOSI) + Set 2: PA5(SCK), PA6(MISO), PA7(MOSI) + +I2C Interfaces +-------------- + + Four I2C buses available (I2C1-I2C4). All use HSI (16 MHz) as + kernel clock (NuttX I2C driver requirement). Bus frequency + configurable per bus via menuconfig (100/400/1000 kHz). + + I2C1 pin sets: + Set 1: PB6(SCL), PB7(SDA) - AF4 (Arduino D10/D9) + Set 2: PB8(SCL), PB9(SDA) - AF4 (Morpho) + + I2C2 pin sets: + Set 1: PB10(SCL), PB11(SDA) - AF4 + Set 2: PF1(SCL), PF0(SDA) - AF4 + Set 3: PH4(SCL), PH5(SDA) - AF4 + + I2C3 pin sets: + Set 1: PA8(SCL), PC9(SDA) - AF4 + Set 2: PH7(SCL), PH8(SDA) - AF4 + + I2C4 pin sets: + Set 1: PD12(SCL), PD13(SDA) - AF4 + Set 2: PF14(SCL), PF15(SDA) - AF4 + Set 3: PH11(SCL), PH12(SDA) - AF4 + Set 4: PB6(SCL), PB7(SDA) - AF6 (conflicts with I2C1 Set 1) + Set 5: PB8(SCL), PB9(SDA) - AF6 (conflicts with I2C1 Set 2) + + Kconfig enforces conflicting pin exclusions at build time. + +FDCAN (CAN FD) +-------------- + + FDCAN1: RX=PB8, TX=PB9 + Kernel clock: 25 MHz (PLL2Q for 8 MHz HSE; HSE direct for 25 MHz HSE) + Supported bitrates: 125 kbps, 250 kbps, 500 kbps, 1 Mbps (and FD rates) + +USB +--- + + USB OTG FS: PA11(DM), PA12(DP), PA9(VBUS), PG6(PWRON), PG7(OVERCURRENT) + Kernel clock: HSI48 (48 MHz, dedicated USB oscillator) + Supports: USB Device, USB Host, USB Monitor + +SDMMC +----- + + Kernel clock: PLL1Q (200 MHz) + Init frequency: 200 MHz / (2*240) = ~416 kHz + Transfer frequency: 200 MHz / (2*2) = 50 MHz (25 MB/s) + +ADC +--- + + ADC1/2/3 kernel clock: PLL2P (75 MHz, within 80 MHz HW limit) + Available channels exposed: INP3, INP4, INP5, INP7, INP8, INP10, + INP11, INP12, INP13, INP14, INP15, INP18, INP19 + +Supported Peripheral Modules +------------------------------ + + The following modules are supported with full Kconfig configuration: + + ST7796 (SPI LCD, 480x320 IPS) + Configurable: SPI bus, CS/DC/RESET/LED pins, CS polarity, + color depth (RGB444/RGB565/RGB666), orientation (portrait/landscape + and reverse variants), 180-degree rotation, SPI frequency, + framebuffer size. Framebuffer interface (/dev/fb0) compatible + with LVGL and other graphics libraries. + + SSD1306 (I2C OLED, 128x64 or 128x32) + Configurable: I2C bus, I2C address (0x3C/0x3D/custom), bus + frequency, brightness (0-100%), resolution, device path, + device number. + + MFRC522 (SPI RFID, 13.56 MHz) + Configurable: SPI bus, device ID, CS pin, CS polarity, + optional IRQ pin, IRQ trigger (falling/rising/both edges). + Device node: /dev/rfid0 + + NRF24L01 (SPI 2.4 GHz transceiver) + CS=PA4, CE=PF12, IRQ=PD15 + + MMC/SD Card (SPI) + CS=PD15, Card-detect=PF12 (EXTI) + + LSM6DSL (I2C 6-axis IMU) + INT1=PB4, INT2=PB5 + + LSM303AGR (I2C magnetometer/accelerometer) + LSM9DS1 (I2C 9-axis IMU) + LPS22HB (I2C pressure sensor, INT1=PB10) + PCA9635 (I2C LED controller, addr=0x40, bus=I2C1) + +Additional Features +------------------- + + PROGMEM MTD: Internal flash exposed as MTD character device + RTC: Hardware RTC driver (/dev/rtc0) + PWM: TIM1 configured (CH1-CH4 + complementary outputs on PE8-PE14) + ROMFS: Optional auto-mount of built-in ROMFS image + GPIO driver: /dev/gpioN support (BOARD_NGPIOIN=1, NGPIOOUT=3, NGPIOINT=1) + USB MSC: Mass storage class support + +LED Behavior (Automatic Mode) +------------------------------- + + LED_STARTED Red=OFF, Green=OFF, Orange=OFF + LED_HEAPALLOCATE Red=OFF, Green=OFF, Orange=ON + LED_IRQSENABLED Red=OFF, Green=ON, Orange=OFF + LED_STACKCREATED Red=OFF, Green=ON, Orange=ON + LED_INIRQ Red=N/C, Green=N/C, Orange=GLOW + LED_SIGNAL Red=N/C, Green=GLOW,Orange=N/C + LED_ASSERTION Red=GLOW,Green=N/C, Orange=GLOW + LED_PANIC Red=BLINK,Green=OFF,Orange=N/C + LED_IDLE Red=ON, Green=OFF, Orange=OFF + +Configurations +-------------- + + nsh + Basic NuttShell (NSH) via USART3/VCP at 115200 baud. + User-controlled LEDs (/dev/userleds) via examples/leds. + Generic GPIO driver (/dev/gpioN) via examples/gpio. + D-cache and I-cache enabled. DTCM enabled. + CONFIG_ARCH_LEDS disabled (user LED mode). + + button_driver + NuttShell via USART3/VCP at 115200 baud. + Demonstrates the menuconfig-driven button system with 11 buttons: + Button 0: built-in PC13 + Buttons 1-10: PB1, PD0, PG4, PD5, PE6, PE3, PD12, PF9, PD15, PE11 + Each button assigned to a unique EXTI line (no conflicts). + Automatic LEDs enabled (CONFIG_ARCH_LEDS_CPU_ACTIVITY). + User LEDs also available (/dev/userleds). + Button device at /dev/buttons via examples/buttons. + IRQ-driven button events (CONFIG_ARCH_IRQBUTTONS). + + socketcan + NuttShell via USART3/VCP at 115200 baud. + FDCAN1 configured as SocketCAN network interface. + Arbitration bitrate: 500 kbps. + Data bitrate: 500 kbps (CAN FD capable). + Includes canutils: candump, cansend. + Network stack enabled (CONFIG_NET_CAN). + CAN error frames, socket options, write buffers enabled. + HPWORK thread for FDCAN interrupt handling. + procfs mounted for runtime inspection. + +Source Organization +------------------- + + src/ + stm32_boot.c - Boot and early initialization + stm32_bringup.c - Driver registration (bringup) + stm32_appinitialize.c - Application-level initialization + stm32_boot_image.c - MCUboot image support + nucleo-h753zi.h - Board-internal definitions and prototypes + + drivers/driver_bus/ + stm32_spi.c - SPI bus initialization (SPI1-SPI6) + stm32_i2c.c - I2C bus initialization (I2C1-I2C4) + + drivers/driver_generic/ + stm32_adc.c - ADC setup + stm32_buttons.c - Button driver (up to 32 buttons) + stm32_gpio.c - Generic GPIO driver + stm32_pwm.c - PWM output setup + stm32_userleds.c - User LED driver + + drivers/driver_middleware/ + stm32_autoleds.c - Automatic LED OS state indication + stm32_composite.c - USB composite device + stm32_progmem.c - Internal flash MTD + stm32_reset.c - Board reset support + stm32_romfs_initialize.c- ROMFS auto-mount + stm32_uid.c - Unique device ID + stm32_usb.c - USB OTG FS initialization + stm32_usbmsc.c - USB mass storage class + + drivers/driver_modules/ + stm32_lsm303agr.c - LSM303AGR IMU driver + stm32_lsm6dsl.c - LSM6DSL IMU driver + stm32_lsm9ds1.c - LSM9DS1 IMU driver + stm32_mfrc522.c - MFRC522 RFID driver + stm32_mmcsd.c - MMC/SD card (SPI) driver + stm32_nrf24l01.c - NRF24L01 wireless driver + stm32_pca9635.c - PCA9635 LED controller driver + stm32_ssd1306.c - SSD1306 OLED driver + stm32_st7796.c - ST7796 LCD + framebuffer driver diff --git a/boards/arm/stm32h7/nucleo-h753zi/kernel/Makefile b/boards/arm/stm32h7/nucleo-h753zi/kernel/Makefile new file mode 100644 index 0000000000000..63432ee4e4f98 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/kernel/Makefile @@ -0,0 +1,94 @@ +############################################################################ +# boards/arm/stm32h7/nucleo-h753zi/kernel/Makefile +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(TOPDIR)/Make.defs + +# The entry point name (if none is provided in the .config file) + +CONFIG_INIT_ENTRYPOINT ?= user_start +ENTRYPT = $(patsubst "%",%,$(CONFIG_INIT_ENTRYPOINT)) + +# Get the paths to the libraries and the links script path in format that +# is appropriate for the host OS + +USER_LIBPATHS = $(addprefix -L,$(call CONVERT_PATH,$(addprefix $(TOPDIR)$(DELIM),$(dir $(USERLIBS))))) +USER_LDSCRIPT = -T $(call CONVERT_PATH,$(BOARD_DIR)$(DELIM)scripts$(DELIM)memory.ld) +USER_LDSCRIPT += -T $(call CONVERT_PATH,$(BOARD_DIR)$(DELIM)scripts$(DELIM)user-space.ld) +USER_HEXFILE += $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx_user.hex) +USER_SRECFILE += $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx_user.srec) +USER_BINFILE += $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx_user.bin) + +USER_LDFLAGS = --undefined=$(ENTRYPT) --entry=$(ENTRYPT) $(USER_LDSCRIPT) +USER_LDLIBS = $(patsubst lib%,-l%,$(basename $(notdir $(USERLIBS)))) +USER_LIBGCC = "${shell "$(CC)" $(ARCHCPUFLAGS) -print-libgcc-file-name}" + +# Source files + +CSRCS = stm32_userspace.c +COBJS = $(CSRCS:.c=$(OBJEXT)) +OBJS = $(COBJS) + +# Targets: + +all: $(TOPDIR)$(DELIM)nuttx_user.elf $(TOPDIR)$(DELIM)User.map +.PHONY: nuttx_user.elf depend clean distclean + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +# Create the nuttx_user.elf file containing all of the user-mode code + +nuttx_user.elf: $(OBJS) + $(Q) $(LD) -o $@ $(USER_LDFLAGS) $(USER_LIBPATHS) $(OBJS) --start-group $(USER_LDLIBS) --end-group $(USER_LIBGCC) + +$(TOPDIR)$(DELIM)nuttx_user.elf: nuttx_user.elf + @echo "LD: nuttx_user.elf" + $(Q) cp -a nuttx_user.elf $(TOPDIR)$(DELIM)nuttx_user.elf +ifeq ($(CONFIG_INTELHEX_BINARY),y) + @echo "CP: nuttx_user.hex" + $(Q) $(OBJCOPY) $(OBJCOPYARGS) -O ihex nuttx_user.elf $(USER_HEXFILE) +endif +ifeq ($(CONFIG_MOTOROLA_SREC),y) + @echo "CP: nuttx_user.srec" + $(Q) $(OBJCOPY) $(OBJCOPYARGS) -O srec nuttx_user.elf $(USER_SRECFILE) +endif +ifeq ($(CONFIG_RAW_BINARY),y) + @echo "CP: nuttx_user.bin" + $(Q) $(OBJCOPY) $(OBJCOPYARGS) -O binary nuttx_user.elf $(USER_BINFILE) +endif + +$(TOPDIR)$(DELIM)User.map: nuttx_user.elf + @echo "MK: User.map" + $(Q) $(NM) nuttx_user.elf >$(TOPDIR)$(DELIM)User.map + $(Q) $(CROSSDEV)size nuttx_user.elf + +.depend: + +depend: .depend + +clean: + $(call DELFILE, nuttx_user.elf) + $(call DELFILE, "$(TOPDIR)$(DELIM)nuttx_user.*") + $(call DELFILE, "$(TOPDIR)$(DELIM)User.map") + $(call CLEAN) + +distclean: clean diff --git a/boards/arm/stm32h7/nucleo-h753zi/kernel/stm32_userspace.c b/boards/arm/stm32h7/nucleo-h753zi/kernel/stm32_userspace.c new file mode 100644 index 0000000000000..1c8f709de071f --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/kernel/stm32_userspace.c @@ -0,0 +1,102 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/kernel/stm32_userspace.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include +#include +#include + +#if defined(CONFIG_BUILD_PROTECTED) && !defined(__KERNEL__) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifndef CONFIG_NUTTX_USERSPACE +# error "CONFIG_NUTTX_USERSPACE not defined" +#endif + +#if CONFIG_NUTTX_USERSPACE != 0x08020000 +# error "CONFIG_NUTTX_USERSPACE must be 0x08020000 to match memory.ld" +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* These 'addresses' of these values are setup by the linker script. */ + +extern uint8_t _stext[]; /* Start of .text */ +extern uint8_t _etext[]; /* End_1 of .text + .rodata */ +extern const uint8_t _eronly[]; /* End+1 of read only section (.text + .rodata) */ +extern uint8_t _sdata[]; /* Start of .data */ +extern uint8_t _edata[]; /* End+1 of .data */ +extern uint8_t _sbss[]; /* Start of .bss */ +extern uint8_t _ebss[]; /* End+1 of .bss */ + +const struct userspace_s userspace locate_data(".userspace") = +{ + /* General memory map */ + + .us_entrypoint = CONFIG_INIT_ENTRYPOINT, + .us_textstart = (uintptr_t)_stext, + .us_textend = (uintptr_t)_etext, + .us_datasource = (uintptr_t)_eronly, + .us_datastart = (uintptr_t)_sdata, + .us_dataend = (uintptr_t)_edata, + .us_bssstart = (uintptr_t)_sbss, + .us_bssend = (uintptr_t)_ebss, + + /* Memory manager heap structure */ + + .us_heap = &g_mmheap, + + /* Task/thread startup routines */ + + .task_startup = nxtask_startup, + + /* Signal handler trampoline */ + + .signal_handler = up_signal_handler, + + /* User-space work queue support (declared in include/nuttx/wqueue.h) */ + +#ifdef CONFIG_LIBC_USRWORK + .work_usrstart = work_usrstart, +#endif +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#endif /* CONFIG_BUILD_PROTECTED && !__KERNEL__ */ diff --git a/boards/arm/stm32h7/nucleo-h753zi/scripts/Make.defs b/boards/arm/stm32h7/nucleo-h753zi/scripts/Make.defs new file mode 100644 index 0000000000000..238179f4e2268 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/scripts/Make.defs @@ -0,0 +1,50 @@ +############################################################################ +# boards/arm/stm32h7/nucleo-h753zi/scripts/Make.defs +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(TOPDIR)/.config +include $(TOPDIR)/tools/Config.mk +include $(TOPDIR)/arch/arm/src/armv7-m/Toolchain.defs + +ifeq ($(CONFIG_STM32_APP_FORMAT_MCUBOOT),y) + ifeq ($(CONFIG_MCUBOOT_BOOTLOADER),y) + LDSCRIPT = flash-mcuboot-loader.ld + else + LDSCRIPT = flash-mcuboot-app.ld + endif +else + LDSCRIPT = flash.ld +endif + +ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)$(LDSCRIPT) + +ARCHPICFLAGS = -fpic -msingle-pic-base -mpic-register=r10 + +CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) +CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS) +CXXFLAGS := $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) +CXXPICFLAGS = $(ARCHPICFLAGS) $(CXXFLAGS) +CPPFLAGS := $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) +AFLAGS := $(CFLAGS) -D__ASSEMBLY__ + +NXFLATLDFLAGS1 = -r -d -warn-common +NXFLATLDFLAGS2 = $(NXFLATLDFLAGS1) -T$(TOPDIR)/binfmt/libnxflat/gnu-nxflat-pcrel.ld -no-check-sections +LDNXFLATFLAGS = -e main -s 2048 diff --git a/boards/arm/stm32h7/nucleo-h753zi/scripts/flash-mcuboot-app.ld b/boards/arm/stm32h7/nucleo-h753zi/scripts/flash-mcuboot-app.ld new file mode 100644 index 0000000000000..a60c25b625eb0 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/scripts/flash-mcuboot-app.ld @@ -0,0 +1,203 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/scripts/flash-mcuboot-app.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* The STM32H753ZI has 2048Kb of main FLASH memory. The flash memory is + * partitioned into a User Flash memory and a System Flash memory. Each + * of these memories has two banks: + * + * 1) User Flash memory: + * + * Bank 1: Start address 0x0800:0000 to 0x080F:FFFF with 8 sectors, 128Kb each + * Bank 2: Start address 0x0810:0000 to 0x081F:FFFF with 8 sectors, 128Kb each + * + * 2) System Flash memory: + * + * Bank 1: Start address 0x1FF0:0000 to 0x1FF1:FFFF with 1 x 128Kb sector + * Bank 1: Start address 0x1FF4:0000 to 0x1FF5:FFFF with 1 x 128Kb sector + * + * 3) User option bytes for user configuration, only in Bank 1. + * + * In the STM32H753ZI, two different boot spaces can be selected through + * the BOOT pin and the boot base address programmed in the BOOT_ADD0 and + * BOOT_ADD1 option bytes: + * + * 1) BOOT=0: Boot address defined by user option byte BOOT_ADD0[15:0]. + * ST programmed value: Flash memory at 0x0800:0000 + * 2) BOOT=1: Boot address defined by user option byte BOOT_ADD1[15:0]. + * ST programmed value: System bootloader at 0x1FF0:0000 + * + * TODO: Check next paragraph with nucleo schematics + * + * NuttX does not modify these option bytes. On the unmodified NUCLEO-H753ZI + * board, the BOOT0 pin is at ground so by default, the STM32 will boot + * to address 0x0800:0000 in FLASH. + * + * The STM32H753ZI also has 1024Kb of data SRAM. + * SRAM is split up into several blocks and into three power domains: + * + * 1) TCM SRAMs are dedicated to the Cortex-M7 and are accessible with + * 0 wait states by the Cortex-M7 and by MDMA through AHBS slave bus + * + * 1.1) 128Kb of DTCM-RAM beginning at address 0x2000:0000 + * + * The DTCM-RAM is organized as 2 x 64Kb DTCM-RAMs on 2 x 32 bit + * DTCM ports. The DTCM-RAM could be used for critical real-time + * data, such as interrupt service routines or stack / heap memory. + * Both DTCM-RAMs can be used in parallel (for load/store operations) + * thanks to the Cortex-M7 dual issue capability. + * + * 1.2) 64Kb of ITCM-RAM beginning at address 0x0000:0000 + * + * This RAM is connected to ITCM 64-bit interface designed for + * execution of critical real-times routines by the CPU. + * + * 2) AXI SRAM (D1 domain) accessible by all system masters except BDMA + * through D1 domain AXI bus matrix + * + * 2.1) 512Kb of SRAM beginning at address 0x2400:0000 + * + * 3) AHB SRAM (D2 domain) accessible by all system masters except BDMA + * through D2 domain AHB bus matrix + * + * 3.1) 128Kb of SRAM1 beginning at address 0x3000:0000 + * 3.2) 128Kb of SRAM2 beginning at address 0x3002:0000 + * 3.3) 32Kb of SRAM3 beginning at address 0x3004:0000 + * + * SRAM1 - SRAM3 are one contiguous block: 288Kb at address 0x3000:0000 + * + * 4) AHB SRAM (D3 domain) accessible by most of system masters + * through D3 domain AHB bus matrix + * + * 4.1) 64Kb of SRAM4 beginning at address 0x3800:0000 + * 4.1) 4Kb of backup RAM beginning at address 0x3880:0000 + * + * When booting from FLASH, FLASH memory is aliased to address 0x0000:0000 + * where the code expects to begin execution by jumping to the entry point in + * the 0x0800:0000 address range. + */ + +MEMORY +{ + itcm (rwx) : ORIGIN = 0x00000000, LENGTH = 64K + flash (rx) : ORIGIN = 0x08040200, LENGTH = 768K - 256K + dtcm1 (rwx) : ORIGIN = 0x20000000, LENGTH = 64K + dtcm2 (rwx) : ORIGIN = 0x20010000, LENGTH = 64K + sram (rwx) : ORIGIN = 0x24000000, LENGTH = 512K + sram1 (rwx) : ORIGIN = 0x30000000, LENGTH = 128K + sram2 (rwx) : ORIGIN = 0x30020000, LENGTH = 128K + sram3 (rwx) : ORIGIN = 0x30040000, LENGTH = 32K + sram4 (rwx) : ORIGIN = 0x38000000, LENGTH = 64K + bbram (rwx) : ORIGIN = 0x38800000, LENGTH = 4K +} + +OUTPUT_ARCH(arm) +EXTERN(_vectors) +ENTRY(_stext) +SECTIONS +{ + .text : + { + _stext = ABSOLUTE(.); + *(.vectors) + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.rodata .rodata.*) + *(.gnu.linkonce.t.*) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + _etext = ABSOLUTE(.); + } > flash + + .init_section : + { + _sinit = ABSOLUTE(.); + KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP(*(.init_array EXCLUDE_FILE(*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o) .ctors)) + _einit = ABSOLUTE(.); + } > flash + + .ARM.extab : + { + *(.ARM.extab*) + } > flash + + __exidx_start = ABSOLUTE(.); + .ARM.exidx : + { + *(.ARM.exidx*) + } > flash + __exidx_end = ABSOLUTE(.); + + _eronly = ABSOLUTE(.); + + .data : + { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + . = ALIGN(4); + _edata = ABSOLUTE(.); + } > sram AT > flash + + .bss : + { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = ABSOLUTE(.); + } > sram + + /* Emit the the D3 power domain section for locating BDMA data + * + * Static data with locate_data(".sram4") will be located + * at start of SRAM4; the rest of SRAM4 will be added to the heap. + */ + + .sram4_reserve (NOLOAD) : + { + *(.sram4) + . = ALIGN(4); + _sram4_heap_start = ABSOLUTE(.); + } > sram4 + + /* Stabs debugging sections. */ + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/scripts/flash-mcuboot-loader.ld b/boards/arm/stm32h7/nucleo-h753zi/scripts/flash-mcuboot-loader.ld new file mode 100644 index 0000000000000..7041e776a0908 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/scripts/flash-mcuboot-loader.ld @@ -0,0 +1,203 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/scripts/flash-mcuboot-laoder.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* The STM32H753ZI has 2048Kb of main FLASH memory. The flash memory is + * partitioned into a User Flash memory and a System Flash memory. Each + * of these memories has two banks: + * + * 1) User Flash memory: + * + * Bank 1: Start address 0x0800:0000 to 0x080F:FFFF with 8 sectors, 128Kb each + * Bank 2: Start address 0x0810:0000 to 0x081F:FFFF with 8 sectors, 128Kb each + * + * 2) System Flash memory: + * + * Bank 1: Start address 0x1FF0:0000 to 0x1FF1:FFFF with 1 x 128Kb sector + * Bank 1: Start address 0x1FF4:0000 to 0x1FF5:FFFF with 1 x 128Kb sector + * + * 3) User option bytes for user configuration, only in Bank 1. + * + * In the STM32H753ZI, two different boot spaces can be selected through + * the BOOT pin and the boot base address programmed in the BOOT_ADD0 and + * BOOT_ADD1 option bytes: + * + * 1) BOOT=0: Boot address defined by user option byte BOOT_ADD0[15:0]. + * ST programmed value: Flash memory at 0x0800:0000 + * 2) BOOT=1: Boot address defined by user option byte BOOT_ADD1[15:0]. + * ST programmed value: System bootloader at 0x1FF0:0000 + * + * TODO: Check next paragraph with nucleo schematics + * + * NuttX does not modify these option bytes. On the unmodified NUCLEO-H753ZI + * board, the BOOT0 pin is at ground so by default, the STM32 will boot + * to address 0x0800:0000 in FLASH. + * + * The STM32H753ZI also has 1024Kb of data SRAM. + * SRAM is split up into several blocks and into three power domains: + * + * 1) TCM SRAMs are dedicated to the Cortex-M7 and are accessible with + * 0 wait states by the Cortex-M7 and by MDMA through AHBS slave bus + * + * 1.1) 128Kb of DTCM-RAM beginning at address 0x2000:0000 + * + * The DTCM-RAM is organized as 2 x 64Kb DTCM-RAMs on 2 x 32 bit + * DTCM ports. The DTCM-RAM could be used for critical real-time + * data, such as interrupt service routines or stack / heap memory. + * Both DTCM-RAMs can be used in parallel (for load/store operations) + * thanks to the Cortex-M7 dual issue capability. + * + * 1.2) 64Kb of ITCM-RAM beginning at address 0x0000:0000 + * + * This RAM is connected to ITCM 64-bit interface designed for + * execution of critical real-times routines by the CPU. + * + * 2) AXI SRAM (D1 domain) accessible by all system masters except BDMA + * through D1 domain AXI bus matrix + * + * 2.1) 512Kb of SRAM beginning at address 0x2400:0000 + * + * 3) AHB SRAM (D2 domain) accessible by all system masters except BDMA + * through D2 domain AHB bus matrix + * + * 3.1) 128Kb of SRAM1 beginning at address 0x3000:0000 + * 3.2) 128Kb of SRAM2 beginning at address 0x3002:0000 + * 3.3) 32Kb of SRAM3 beginning at address 0x3004:0000 + * + * SRAM1 - SRAM3 are one contiguous block: 288Kb at address 0x3000:0000 + * + * 4) AHB SRAM (D3 domain) accessible by most of system masters + * through D3 domain AHB bus matrix + * + * 4.1) 64Kb of SRAM4 beginning at address 0x3800:0000 + * 4.1) 4Kb of backup RAM beginning at address 0x3880:0000 + * + * When booting from FLASH, FLASH memory is aliased to address 0x0000:0000 + * where the code expects to begin execution by jumping to the entry point in + * the 0x0800:0000 address range. + */ + +MEMORY +{ + itcm (rwx) : ORIGIN = 0x00000000, LENGTH = 64K + flash (rx) : ORIGIN = 0x08000000, LENGTH = 256K + dtcm1 (rwx) : ORIGIN = 0x20000000, LENGTH = 64K + dtcm2 (rwx) : ORIGIN = 0x20010000, LENGTH = 64K + sram (rwx) : ORIGIN = 0x24000000, LENGTH = 512K + sram1 (rwx) : ORIGIN = 0x30000000, LENGTH = 128K + sram2 (rwx) : ORIGIN = 0x30020000, LENGTH = 128K + sram3 (rwx) : ORIGIN = 0x30040000, LENGTH = 32K + sram4 (rwx) : ORIGIN = 0x38000000, LENGTH = 64K + bbram (rwx) : ORIGIN = 0x38800000, LENGTH = 4K +} + +OUTPUT_ARCH(arm) +EXTERN(_vectors) +ENTRY(_stext) +SECTIONS +{ + .text : + { + _stext = ABSOLUTE(.); + *(.vectors) + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.rodata .rodata.*) + *(.gnu.linkonce.t.*) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + _etext = ABSOLUTE(.); + } > flash + + .init_section : + { + _sinit = ABSOLUTE(.); + KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP(*(.init_array EXCLUDE_FILE(*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o) .ctors)) + _einit = ABSOLUTE(.); + } > flash + + .ARM.extab : + { + *(.ARM.extab*) + } > flash + + __exidx_start = ABSOLUTE(.); + .ARM.exidx : + { + *(.ARM.exidx*) + } > flash + __exidx_end = ABSOLUTE(.); + + _eronly = ABSOLUTE(.); + + .data : + { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + . = ALIGN(4); + _edata = ABSOLUTE(.); + } > sram AT > flash + + .bss : + { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = ABSOLUTE(.); + } > sram + + /* Emit the the D3 power domain section for locating BDMA data + * + * Static data with locate_data(".sram4") will be located + * at start of SRAM4; the rest of SRAM4 will be added to the heap. + */ + + .sram4_reserve (NOLOAD) : + { + *(.sram4) + . = ALIGN(4); + _sram4_heap_start = ABSOLUTE(.); + } > sram4 + + /* Stabs debugging sections. */ + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/scripts/flash.ld b/boards/arm/stm32h7/nucleo-h753zi/scripts/flash.ld new file mode 100644 index 0000000000000..99d7e261175d6 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/scripts/flash.ld @@ -0,0 +1,203 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/scripts/flash.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* The STM32H753ZI has 2048Kb of main FLASH memory. The flash memory is + * partitioned into a User Flash memory and a System Flash memory. Each + * of these memories has two banks: + * + * 1) User Flash memory: + * + * Bank 1: Start address 0x0800:0000 to 0x080F:FFFF with 8 sectors, 128Kb each + * Bank 2: Start address 0x0810:0000 to 0x081F:FFFF with 8 sectors, 128Kb each + * + * 2) System Flash memory: + * + * Bank 1: Start address 0x1FF0:0000 to 0x1FF1:FFFF with 1 x 128Kb sector + * Bank 1: Start address 0x1FF4:0000 to 0x1FF5:FFFF with 1 x 128Kb sector + * + * 3) User option bytes for user configuration, only in Bank 1. + * + * In the STM32H753ZI, two different boot spaces can be selected through + * the BOOT pin and the boot base address programmed in the BOOT_ADD0 and + * BOOT_ADD1 option bytes: + * + * 1) BOOT=0: Boot address defined by user option byte BOOT_ADD0[15:0]. + * ST programmed value: Flash memory at 0x0800:0000 + * 2) BOOT=1: Boot address defined by user option byte BOOT_ADD1[15:0]. + * ST programmed value: System bootloader at 0x1FF0:0000 + * + * TODO: Check next paragraph with nucleo schematics + * + * NuttX does not modify these option bytes. On the unmodified NUCLEO-H753ZI + * board, the BOOT0 pin is at ground so by default, the STM32 will boot + * to address 0x0800:0000 in FLASH. + * + * The STM32H753ZI also has 1024Kb of data SRAM. + * SRAM is split up into several blocks and into three power domains: + * + * 1) TCM SRAMs are dedicated to the Cortex-M7 and are accessible with + * 0 wait states by the Cortex-M7 and by MDMA through AHBS slave bus + * + * 1.1) 128Kb of DTCM-RAM beginning at address 0x2000:0000 + * + * The DTCM-RAM is organized as 2 x 64Kb DTCM-RAMs on 2 x 32 bit + * DTCM ports. The DTCM-RAM could be used for critical real-time + * data, such as interrupt service routines or stack / heap memory. + * Both DTCM-RAMs can be used in parallel (for load/store operations) + * thanks to the Cortex-M7 dual issue capability. + * + * 1.2) 64Kb of ITCM-RAM beginning at address 0x0000:0000 + * + * This RAM is connected to ITCM 64-bit interface designed for + * execution of critical real-times routines by the CPU. + * + * 2) AXI SRAM (D1 domain) accessible by all system masters except BDMA + * through D1 domain AXI bus matrix + * + * 2.1) 512Kb of SRAM beginning at address 0x2400:0000 + * + * 3) AHB SRAM (D2 domain) accessible by all system masters except BDMA + * through D2 domain AHB bus matrix + * + * 3.1) 128Kb of SRAM1 beginning at address 0x3000:0000 + * 3.2) 128Kb of SRAM2 beginning at address 0x3002:0000 + * 3.3) 32Kb of SRAM3 beginning at address 0x3004:0000 + * + * SRAM1 - SRAM3 are one contiguous block: 288Kb at address 0x3000:0000 + * + * 4) AHB SRAM (D3 domain) accessible by most of system masters + * through D3 domain AHB bus matrix + * + * 4.1) 64Kb of SRAM4 beginning at address 0x3800:0000 + * 4.1) 4Kb of backup RAM beginning at address 0x3880:0000 + * + * When booting from FLASH, FLASH memory is aliased to address 0x0000:0000 + * where the code expects to begin execution by jumping to the entry point in + * the 0x0800:0000 address range. + */ + +MEMORY +{ + itcm (rwx) : ORIGIN = 0x00000000, LENGTH = 64K + flash (rx) : ORIGIN = 0x08000000, LENGTH = 2048K + dtcm1 (rwx) : ORIGIN = 0x20000000, LENGTH = 64K + dtcm2 (rwx) : ORIGIN = 0x20010000, LENGTH = 64K + sram (rwx) : ORIGIN = 0x24000000, LENGTH = 512K + sram1 (rwx) : ORIGIN = 0x30000000, LENGTH = 128K + sram2 (rwx) : ORIGIN = 0x30020000, LENGTH = 128K + sram3 (rwx) : ORIGIN = 0x30040000, LENGTH = 32K + sram4 (rwx) : ORIGIN = 0x38000000, LENGTH = 64K + bbram (rwx) : ORIGIN = 0x38800000, LENGTH = 4K +} + +OUTPUT_ARCH(arm) +EXTERN(_vectors) +ENTRY(_stext) +SECTIONS +{ + .text : + { + _stext = ABSOLUTE(.); + *(.vectors) + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.rodata .rodata.*) + *(.gnu.linkonce.t.*) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + _etext = ABSOLUTE(.); + } > flash + + .init_section : + { + _sinit = ABSOLUTE(.); + KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP(*(.init_array EXCLUDE_FILE(*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o) .ctors)) + _einit = ABSOLUTE(.); + } > flash + + .ARM.extab : + { + *(.ARM.extab*) + } > flash + + __exidx_start = ABSOLUTE(.); + .ARM.exidx : + { + *(.ARM.exidx*) + } > flash + __exidx_end = ABSOLUTE(.); + + _eronly = ABSOLUTE(.); + + .data : + { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + . = ALIGN(4); + _edata = ABSOLUTE(.); + } > sram AT > flash + + .bss : + { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = ABSOLUTE(.); + } > sram + + /* Emit the the D3 power domain section for locating BDMA data + * + * Static data with locate_data(".sram4") will be located + * at start of SRAM4; the rest of SRAM4 will be added to the heap. + */ + + .sram4_reserve (NOLOAD) : + { + *(.sram4) + . = ALIGN(4); + _sram4_heap_start = ABSOLUTE(.); + } > sram4 + + /* Stabs debugging sections. */ + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/scripts/kernel.space.ld b/boards/arm/stm32h7/nucleo-h753zi/scripts/kernel.space.ld new file mode 100644 index 0000000000000..83403ce296b89 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/scripts/kernel.space.ld @@ -0,0 +1,112 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/scripts/kernel.space.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* NOTE: This depends on the memory.ld script having been included prior to + * this script. + */ + +OUTPUT_ARCH(arm) +ENTRY(_stext) +SECTIONS +{ + .text : { + _stext = ABSOLUTE(.); + *(.vectors) + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.rodata .rodata.*) + *(.gnu.linkonce.t.*) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + _etext = ABSOLUTE(.); + } > kflash + + .init_section : { + _sinit = ABSOLUTE(.); + KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP(*(.init_array EXCLUDE_FILE(*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o) .ctors)) + _einit = ABSOLUTE(.); + } > kflash + + .ARM.extab : { + *(.ARM.extab*) + } > kflash + + __exidx_start = ABSOLUTE(.); + .ARM.exidx : { + *(.ARM.exidx*) + } > kflash + + __exidx_end = ABSOLUTE(.); + + _eronly = ABSOLUTE(.); + + .data : { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + . = ALIGN(4); + _edata = ABSOLUTE(.); + } > ksram AT > kflash + + .bss : { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = ABSOLUTE(.); + } > ksram + + /* Emit the the D3 power domain section for locating BDMA data + * + * Static data with locate_data(".sram4") will be located + * at start of SRAM4; the rest of SRAM4 will be added to the heap. + */ + + .sram4_reserve (NOLOAD) : + { + *(.sram4) + . = ALIGN(4); + _sram4_heap_start = ABSOLUTE(.); + } > sram4 + + /* Stabs debugging sections */ + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/scripts/memory.ld b/boards/arm/stm32h7/nucleo-h753zi/scripts/memory.ld new file mode 100644 index 0000000000000..ef69f2320b817 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/scripts/memory.ld @@ -0,0 +1,54 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/scripts/memory.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* TODO: Add description for memory organisation */ + +MEMORY +{ + /* ITCM boot address */ + + itcm (rwx) : ORIGIN = 0x00000000, LENGTH = 64K + + /* 2048Kb FLASH */ + + kflash (rx) : ORIGIN = 0x08000000, LENGTH = 128K + uflash (rx) : ORIGIN = 0x08020000, LENGTH = 128K + xflash (rx) : ORIGIN = 0x08040000, LENGTH = 1792K + + /* 288Kb SRAM123 */ + + ksram (rwx) : ORIGIN = 0x30000000, LENGTH = 16K + usram (rwx) : ORIGIN = 0x30004000, LENGTH = 16K + xsram (rwx) : ORIGIN = 0x30008000, LENGTH = 288K - 32K + + /* 512Kb of contiguous AXI SRAM */ + + sram (rwx) : ORIGIN = 0x24000000, LENGTH = 512K + + /* DTCM SRAM */ + + dtcm1 (rwx) : ORIGIN = 0x20000000, LENGTH = 64K + dtcm2 (rwx) : ORIGIN = 0x20010000, LENGTH = 64K + + sram4 (rwx) : ORIGIN = 0x38000000, LENGTH = 64K + bbram (rwx) : ORIGIN = 0x38800000, LENGTH = 4K +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/scripts/user-space.ld b/boards/arm/stm32h7/nucleo-h753zi/scripts/user-space.ld new file mode 100644 index 0000000000000..a8bc29f412c8e --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/scripts/user-space.ld @@ -0,0 +1,101 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/scripts/user-space.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* NOTE: This depends on the memory.ld script having been included prior to + * this script. + */ + +OUTPUT_ARCH(arm) +SECTIONS +{ + .userspace : { + *(.userspace) + } > uflash + + .text : { + _stext = ABSOLUTE(.); + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.rodata .rodata.*) + *(.gnu.linkonce.t.*) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + _etext = ABSOLUTE(.); + } > uflash + + .init_section : { + _sinit = ABSOLUTE(.); + KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP(*(.init_array EXCLUDE_FILE(*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o) .ctors)) + _einit = ABSOLUTE(.); + } > uflash + + .ARM.extab : { + *(.ARM.extab*) + } > uflash + + __exidx_start = ABSOLUTE(.); + .ARM.exidx : { + *(.ARM.exidx*) + } > uflash + + __exidx_end = ABSOLUTE(.); + + _eronly = ABSOLUTE(.); + + .data : { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + . = ALIGN(4); + _edata = ABSOLUTE(.); + } > usram AT > uflash + + .bss : { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = ABSOLUTE(.); + } > usram + + /* Stabs debugging sections */ + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/CMakeLists.txt b/boards/arm/stm32h7/nucleo-h753zi/src/CMakeLists.txt new file mode 100644 index 0000000000000..18c29cc4e2a74 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/CMakeLists.txt @@ -0,0 +1,127 @@ +# ############################################################################## +# boards/arm/stm32h7/nucleo-h753zi/src/CMakeLists.txt +# ############################################################################## + +set(SRCS stm32_boot.c stm32_bringup.c stm32_appinitialize.c) + +if(CONFIG_ADC) + list(APPEND SRCS stm32_adc.c) +endif() + +if(CONFIG_ARCH_LEDS) + list(APPEND SRCS stm32_autoleds.c) +else() + list(APPEND SRCS stm32_userleds.c) +endif() + +if(CONFIG_ARCH_BUTTONS) + list(APPEND SRCS stm32_buttons.c) +endif() + +if(CONFIG_STM32_ROMFS) + list(APPEND SRCS stm32_romfs_initialize.c) +endif() + +if(CONFIG_STM32H7_I2C) + list(APPEND SRCS stm32_i2c.c) +endif() + +if(CONFIG_STM32H7_SPI) + list(APPEND SRCS stm32_spi.c) +endif() + +if(CONFIG_NUCLEO_H753ZI_MFRC522_ENABLE) + list(APPEND SRCS stm32_mfrc522.c) +endif() + +if(CONFIG_STM32H7_OTGFS) + list(APPEND SRCS stm32_usb.c) +endif() + +if(CONFIG_BOARDCTL_UNIQUEID) + list(APPEND SRCS stm32_uid.c) +endif() + +if(CONFIG_SENSORS_LSM6DSL) + list(APPEND SRCS stm32_lsm6dsl.c) +endif() + +if(CONFIG_SENSORS_LSM9DS1) + list(APPEND SRCS stm32_lsm9ds1.c) +endif() + +if(CONFIG_SENSORS_LSM303AGR) + list(APPEND SRCS stm32_lsm303agr.c) +endif() + +if(CONFIG_PCA9635PW) + list(APPEND SRCS stm32_pca9635.c) +endif() + +if(CONFIG_LCD_SSD1306) + list(APPEND SRCS stm32_ssd1306.c) +endif() + +if(CONFIG_LCD_ST7796) + list(APPEND SRCS stm32_st7796.c) +endif() + +if(CONFIG_STM32H7_PROGMEM) + list(APPEND SRCS stm32_progmem.c) +endif() + +if(CONFIG_WL_NRF24L01) + list(APPEND SRCS stm32_nrf24l01.c) +endif() + +if(CONFIG_NUCLEO_H753ZI_GPIO_DRIVER) + list(APPEND SRCS stm32_gpio.c) +endif() + +if(CONFIG_PWM) + list(APPEND SRCS stm32_pwm.c) +endif() + +if(CONFIG_BOARDCTL_RESET) + list(APPEND SRCS stm32_reset.c) +endif() + +if(CONFIG_BOARDCTL_BOOT_IMAGE) + list(APPEND SRCS stm32_boot_image.c) +endif() + +if(CONFIG_USBMSC) + list(APPEND SRCS stm32_usbmsc.c) +endif() + +if(CONFIG_USBDEV_COMPOSITE) + list(APPEND SRCS stm32_composite.c) +endif() + +if(CONFIG_MMCSD) + list(APPEND SRCS stm32_mmcsd.c) +endif() + +target_sources(board PRIVATE ${SRCS}) + +# Linker scripts +if(CONFIG_STM32_APP_FORMAT_MCUBOOT) + if(CONFIG_MCUBOOT_BOOTLOADER) + set_property( + GLOBAL PROPERTY LD_SCRIPT + "${NUTTX_BOARD_DIR}/scripts/flash-mcuboot-loader.ld") + else() + set_property( + GLOBAL PROPERTY LD_SCRIPT + "${NUTTX_BOARD_DIR}/scripts/flash-mcuboot-app.ld") + endif() +else() + set_property(GLOBAL PROPERTY LD_SCRIPT "${NUTTX_BOARD_DIR}/scripts/flash.ld") +endif() + +if(NOT CONFIG_BUILD_FLAT) + add_subdirectory(${NUTTX_BOARD_DIR}/kernel) + set_property( + GLOBAL PROPERTY LD_SCRIPT_USER ${NUTTX_BOARD_DIR}/scripts/memory.ld + ${NUTTX_BOARD_DIR}/scripts/user-space.ld) +endif() diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/Makefile b/boards/arm/stm32h7/nucleo-h753zi/src/Makefile new file mode 100644 index 0000000000000..8d0ebb6e95e14 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/Makefile @@ -0,0 +1,107 @@ +############################################################################ +# boards/arm/stm32h7/nucleo-h753zi/src/Makefile +############################################################################ + +include $(TOPDIR)/Make.defs + +CSRCS = stm32_boot.c stm32_bringup.c stm32_appinitialize.c + +ifeq ($(CONFIG_ADC),y) + CSRCS += stm32_adc.c +endif + +ifeq ($(CONFIG_ARCH_LEDS),y) + CSRCS += stm32_autoleds.c +else + CSRCS += stm32_userleds.c +endif + +ifeq ($(CONFIG_ARCH_BUTTONS),y) + CSRCS += stm32_buttons.c +endif + +ifeq ($(CONFIG_STM32_ROMFS),y) + CSRCS += stm32_romfs_initialize.c +endif + +ifeq ($(CONFIG_STM32H7_I2C),y) + CSRCS += stm32_i2c.c +endif + +ifeq ($(CONFIG_STM32H7_SPI),y) + CSRCS += stm32_spi.c +endif + +ifeq ($(CONFIG_NUCLEO_H753ZI_MFRC522_ENABLE),y) + CSRCS += stm32_mfrc522.c +endif + +ifeq ($(CONFIG_STM32H7_OTGFS),y) + CSRCS += stm32_usb.c +endif + +ifeq ($(CONFIG_BOARDCTL_UNIQUEID),y) + CSRCS += stm32_uid.c +endif + +ifeq ($(CONFIG_SENSORS_LSM6DSL),y) + CSRCS += stm32_lsm6dsl.c +endif + +ifeq ($(CONFIG_SENSORS_LSM9DS1),y) + CSRCS += stm32_lsm9ds1.c +endif + +ifeq ($(CONFIG_SENSORS_LSM303AGR),y) + CSRCS += stm32_lsm303agr.c +endif + +ifeq ($(CONFIG_PCA9635PW),y) + CSRCS += stm32_pca9635.c +endif + +ifeq ($(CONFIG_LCD_SSD1306),y) + CSRCS += stm32_ssd1306.c +endif + +ifeq ($(CONFIG_LCD_ST7796),y) + CSRCS += stm32_st7796.c +endif + +ifeq ($(CONFIG_STM32H7_PROGMEM),y) + CSRCS += stm32_progmem.c +endif + +ifeq ($(CONFIG_WL_NRF24L01),y) + CSRCS += stm32_nrf24l01.c +endif + +ifeq ($(CONFIG_NUCLEO_H753ZI_GPIO_DRIVER),y) + CSRCS += stm32_gpio.c +endif + +ifeq ($(CONFIG_PWM),y) + CSRCS += stm32_pwm.c +endif + +ifeq ($(CONFIG_BOARDCTL_RESET),y) + CSRCS += stm32_reset.c +endif + +ifeq ($(CONFIG_BOARDCTL_BOOT_IMAGE),y) + CSRCS += stm32_boot_image.c +endif + +ifeq ($(CONFIG_USBMSC),y) + CSRCS += stm32_usbmsc.c +endif + +ifeq ($(CONFIG_USBDEV_COMPOSITE),y) + CSRCS += stm32_composite.c +endif + +ifeq ($(CONFIG_MMCSD),y) + CSRCS += stm32_mmcsd.c +endif + +include $(TOPDIR)/boards/Board.mk diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/nucleo-h753zi.h b/boards/arm/stm32h7/nucleo-h753zi/src/nucleo-h753zi.h new file mode 100644 index 0000000000000..e18e5caab7cbc --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/nucleo-h753zi.h @@ -0,0 +1,1236 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/nucleo-h753zi.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM_STM32H7_NUCLEO_H753ZI_SRC_NUCLEO_H753ZI_H +#define __BOARDS_ARM_STM32H7_NUCLEO_H753ZI_SRC_NUCLEO_H753ZI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * SECTION 1: FEATURE CONFIGURATION + ****************************************************************************/ + +/* Core System Features */ + +#define HAVE_PROC 1 +#define HAVE_USBDEV 1 +#define HAVE_USBHOST 1 +#define HAVE_USBMONITOR 1 +#define HAVE_MTDCONFIG 1 +#define HAVE_PROGMEM_CHARDEV 1 +#define HAVE_RTC_DRIVER 1 + +/* USB Feature Dependencies */ + +#ifndef CONFIG_STM32H7_OTGFS +# undef HAVE_USBDEV +# undef HAVE_USBHOST +#endif + +#ifndef CONFIG_USBDEV +# undef HAVE_USBDEV +#endif + +#ifndef CONFIG_USBHOST +# undef HAVE_USBHOST +#endif + +#ifndef CONFIG_USBMONITOR +# undef HAVE_USBMONITOR +#endif + +#if !defined(HAVE_USBDEV) +# undef CONFIG_USBDEV_TRACE +#endif + +#if !defined(HAVE_USBHOST) +# undef CONFIG_USBHOST_TRACE +#endif + +#if !defined(CONFIG_USBDEV_TRACE) && !defined(CONFIG_USBHOST_TRACE) +# undef HAVE_USBMONITOR +#endif + +/* MTD Feature Dependencies */ + +#if !defined(CONFIG_STM32H7_PROGMEM) || !defined(CONFIG_MTD_PROGMEM) +# undef HAVE_PROGMEM_CHARDEV +#endif + +/* RTC Feature Dependencies */ + +#if !defined(CONFIG_RTC) || !defined(CONFIG_RTC_DRIVER) +# undef HAVE_RTC_DRIVER +#endif + +/* Flash-based Parameters */ + +#if defined(CONFIG_MMCSD) +# define FLASH_BASED_PARAMS +#endif + +/**************************************************************************** + * SECTION 2: DEVICE DRIVER PATHS + ****************************************************************************/ + +/* LED Driver */ + +#define LED_DRIVER_PATH "/dev/userleds" + +/* Button Driver */ + +#define BUTTONS_DRIVER_PATH "/dev/buttons" + +/* RTC Driver */ + +#define RTC_DRIVER_PATH "/dev/rtc0" + +/* CAN Driver */ + +#define CAN0_DRIVER_PATH "/dev/can0" + +/* Sensor Drivers */ + +#define MFRC522_DEVPATH "/dev/rfid0" + +/* Display Drivers */ + +#define ST7796_FB_PATH "/dev/fb0" + +/* Filesystem Paths */ + +#ifdef CONFIG_FS_PROCFS +# ifdef CONFIG_NSH_PROC_MOUNTPOINT +# define STM32_PROCFS_MOUNTPOINT CONFIG_NSH_PROC_MOUNTPOINT +# else +# define STM32_PROCFS_MOUNTPOINT "/proc" +# endif +#endif + +/* MTD Devices */ + +#define PROGMEM_MTD_MINOR 0 + +/**************************************************************************** + * SECTION 3: GPIO HARDWARE DEFINITIONS + ****************************************************************************/ + +/**************************************************************************** + * Board GPIO - LEDs + ****************************************************************************/ + +/* LED GPIO Definitions */ + +#define GPIO_LD1 (GPIO_OUTPUT | GPIO_PUSHPULL | GPIO_SPEED_50MHz | \ + GPIO_OUTPUT_CLEAR | GPIO_PORTB | GPIO_PIN0) +#define GPIO_LD2 (GPIO_OUTPUT | GPIO_PUSHPULL | GPIO_SPEED_50MHz | \ + GPIO_OUTPUT_CLEAR | GPIO_PORTE | GPIO_PIN1) +#define GPIO_LD3 (GPIO_OUTPUT | GPIO_PUSHPULL | GPIO_SPEED_50MHz | \ + GPIO_OUTPUT_CLEAR | GPIO_PORTB | GPIO_PIN14) + +/* LED Logical Name Aliases */ + +#define GPIO_LED_GREEN GPIO_LD1 +#define GPIO_LED_ORANGE GPIO_LD2 +#define GPIO_LED_RED GPIO_LD3 + +/**************************************************************************** + * Board GPIO - Buttons + ****************************************************************************/ + +#if defined(CONFIG_NUCLEO_H753ZI_BUTTON_SUPPORT) || \ + defined(CONFIG_NUCLEO_H753ZI_GPIO_DRIVER) +# define GPIO_BTN_BUILT_IN (GPIO_INPUT | GPIO_PULLDOWN | GPIO_EXTI | \ + GPIO_PORTC | GPIO_PIN13) +#endif + +/**************************************************************************** + * USB GPIO + ****************************************************************************/ + +#define GPIO_OTGFS_VBUS (GPIO_INPUT | GPIO_FLOAT | GPIO_SPEED_100MHz | \ + GPIO_OPENDRAIN | GPIO_PORTA | GPIO_PIN9) +#define GPIO_OTGFS_PWRON (GPIO_OUTPUT | GPIO_FLOAT | GPIO_SPEED_100MHz | \ + GPIO_PUSHPULL | GPIO_PORTG | GPIO_PIN6) + +#ifdef CONFIG_USBHOST +# define GPIO_OTGFS_OVER (GPIO_INPUT | GPIO_EXTI | GPIO_FLOAT | \ + GPIO_SPEED_100MHz | GPIO_PUSHPULL | \ + GPIO_PORTG | GPIO_PIN7) +#else +# define GPIO_OTGFS_OVER (GPIO_INPUT | GPIO_FLOAT | GPIO_SPEED_100MHz | \ + GPIO_PUSHPULL | GPIO_PORTG | GPIO_PIN7) +#endif + +/**************************************************************************** + * Generic GPIO Examples + ****************************************************************************/ + +/* GPIO Subsystem Definitions */ + +#define BOARD_NGPIOIN 1 +#define BOARD_NGPIOOUT 3 +#define BOARD_NGPIOINT 1 + +/* Placeholder - example for in, out and interrupt */ + +#define GPIO_IN1 (GPIO_INPUT | GPIO_FLOAT | GPIO_PORTE | \ + GPIO_PIN2) +#define GPIO_OUT1 (GPIO_OUTPUT | GPIO_PUSHPULL | \ + GPIO_SPEED_50MHz | GPIO_OUTPUT_SET | \ + GPIO_PORTE | GPIO_PIN4) +#define GPIO_INT1 (GPIO_INPUT | GPIO_FLOAT | GPIO_PORTE | \ + GPIO_PIN5) + +/**************************************************************************** + * SECTION 4: PERIPHERAL DEVICE CONFIGURATIONS + ****************************************************************************/ + +/**************************************************************************** + * Core Communication Buses - I2C Pin Configurations + ****************************************************************************/ + +/* I2C1 Pin Configurations */ + +#ifdef CONFIG_NUCLEO_H753ZI_I2C1_ENABLE + +# ifdef CONFIG_NUCLEO_H753ZI_I2C1_PINSET_1 + /* AF4: I2C1 on PB6/PB7 (Arduino D10/D9) */ +# define GPIO_I2C1_SCL GPIO_I2C1_SCL_1 /* PB6 - AF4 */ +# define GPIO_I2C1_SDA GPIO_I2C1_SDA_1 /* PB7 - AF4 */ + +# elif defined(CONFIG_NUCLEO_H753ZI_I2C1_PINSET_2) + /* AF4: I2C1 on PB8/PB9 (Morpho) */ +# define GPIO_I2C1_SCL GPIO_I2C1_SCL_2 /* PB8 - AF4 */ +# define GPIO_I2C1_SDA GPIO_I2C1_SDA_2 /* PB9 - AF4 */ +# endif + +# define I2C1_FREQUENCY CONFIG_NUCLEO_H753ZI_I2C1_DEFAULT_FREQUENCY + +#endif /* CONFIG_NUCLEO_H753ZI_I2C1_ENABLE */ + +/* I2C2 Pin Configurations */ + +#ifdef CONFIG_NUCLEO_H753ZI_I2C2_ENABLE + +# ifdef CONFIG_NUCLEO_H753ZI_I2C2_PINSET_1 + /* AF4: I2C2 on PB10/PB11 */ +# define GPIO_I2C2_SCL GPIO_I2C2_SCL_1 /* PB10 - AF4 */ +# define GPIO_I2C2_SDA GPIO_I2C2_SDA_1 /* PB11 - AF4 */ + +# elif defined(CONFIG_NUCLEO_H753ZI_I2C2_PINSET_2) + /* AF4: I2C2 on PF1/PF0 */ +# define GPIO_I2C2_SCL GPIO_I2C2_SCL_2 /* PF1 - AF4 */ +# define GPIO_I2C2_SDA GPIO_I2C2_SDA_2 /* PF0 - AF4 */ + +# elif defined(CONFIG_NUCLEO_H753ZI_I2C2_PINSET_3) + /* AF4: I2C2 on PH4/PH5 */ +# define GPIO_I2C2_SCL GPIO_I2C2_SCL_3 /* PH4 - AF4 */ +# define GPIO_I2C2_SDA GPIO_I2C2_SDA_3 /* PH5 - AF4 */ +# endif + +# define I2C2_FREQUENCY CONFIG_NUCLEO_H753ZI_I2C2_DEFAULT_FREQUENCY + +#endif /* CONFIG_NUCLEO_H753ZI_I2C2_ENABLE */ + +/* I2C3 Pin Configurations */ + +#ifdef CONFIG_NUCLEO_H753ZI_I2C3_ENABLE + +# ifdef CONFIG_NUCLEO_H753ZI_I2C3_PINSET_1 + /* AF4: I2C3 on PA8/PC9 */ +# define GPIO_I2C3_SCL GPIO_I2C3_SCL_1 /* PA8 - AF4 */ +# define GPIO_I2C3_SDA GPIO_I2C3_SDA_1 /* PC9 - AF4 */ + +# elif defined(CONFIG_NUCLEO_H753ZI_I2C3_PINSET_2) + /* AF4: I2C3 on PH7/PH8 */ +# define GPIO_I2C3_SCL GPIO_I2C3_SCL_2 /* PH7 - AF4 */ +# define GPIO_I2C3_SDA GPIO_I2C3_SDA_2 /* PH8 - AF4 */ +# endif + +# define I2C3_FREQUENCY CONFIG_NUCLEO_H753ZI_I2C3_DEFAULT_FREQUENCY + +#endif /* CONFIG_NUCLEO_H753ZI_I2C3_ENABLE */ + +/* I2C4 Pin Configurations */ + +#ifdef CONFIG_NUCLEO_H753ZI_I2C4_ENABLE + +# ifdef CONFIG_NUCLEO_H753ZI_I2C4_PINSET_1 + /* AF4: I2C4 on PD12/PD13 */ +# define GPIO_I2C4_SCL GPIO_I2C4_SCL_1 /* PD12 - AF4 */ +# define GPIO_I2C4_SDA GPIO_I2C4_SDA_1 /* PD13 - AF4 */ + +# elif defined(CONFIG_NUCLEO_H753ZI_I2C4_PINSET_2) + /* AF4: I2C4 on PF14/PF15 */ +# define GPIO_I2C4_SCL GPIO_I2C4_SCL_2 /* PF14 - AF4 */ +# define GPIO_I2C4_SDA GPIO_I2C4_SDA_2 /* PF15 - AF4 */ + +# elif defined(CONFIG_NUCLEO_H753ZI_I2C4_PINSET_3) + /* AF4: I2C4 on PH11/PH12 */ +# define GPIO_I2C4_SCL GPIO_I2C4_SCL_3 /* PH11 - AF4 */ +# define GPIO_I2C4_SDA GPIO_I2C4_SDA_3 /* PH12 - AF4 */ + +# elif defined(CONFIG_NUCLEO_H753ZI_I2C4_PINSET_4) + /* AF6: I2C4 on PB6/PB7 (shared with I2C1!) */ +# define GPIO_I2C4_SCL GPIO_I2C4_SCL_4 /* PB6 - AF6 */ +# define GPIO_I2C4_SDA GPIO_I2C4_SDA_4 /* PB7 - AF6 */ + +# elif defined(CONFIG_NUCLEO_H753ZI_I2C4_PINSET_5) + /* AF6: I2C4 on PB8/PB9 (shared with I2C1!) */ +# define GPIO_I2C4_SCL GPIO_I2C4_SCL_5 /* PB8 - AF6 */ +# define GPIO_I2C4_SDA GPIO_I2C4_SDA_5 /* PB9 - AF6 */ +# endif + +# define I2C4_FREQUENCY CONFIG_NUCLEO_H753ZI_I2C4_DEFAULT_FREQUENCY + +#endif /* CONFIG_NUCLEO_H753ZI_I2C4_ENABLE */ + +/**************************************************************************** + * Sensors + ****************************************************************************/ + +/* MFRC522 - SPI RFID Reader */ + +#ifdef CONFIG_NUCLEO_H753ZI_MFRC522_ENABLE + +/* Validate Kconfig */ + +# ifndef CONFIG_NUCLEO_H753ZI_MFRC522_SPI_BUS +# error "MFRC522 enabled but SPI bus not configured" +# endif + +# ifndef CONFIG_NUCLEO_H753ZI_MFRC522_DEVID +# error "MFRC522 enabled but device ID not configured" +# endif + +# ifndef CONFIG_NUCLEO_H753ZI_MFRC522_CS_PIN +# error "MFRC522 enabled but CS pin not configured" +# endif + +/* Device configuration (from Kconfig) */ + +# define MFRC522_SPI_BUS CONFIG_NUCLEO_H753ZI_MFRC522_SPI_BUS +# define MFRC522_DEVICE_ID CONFIG_NUCLEO_H753ZI_MFRC522_DEVID +# define MFRC522_CS_PIN CONFIG_NUCLEO_H753ZI_MFRC522_CS_PIN + +/* CS Active Level */ + +# if defined(CONFIG_NUCLEO_H753ZI_MFRC522_CS_ACTIVE_LOW) +# define MFRC522_CS_ACTIVE_LOW true +# elif defined(CONFIG_NUCLEO_H753ZI_MFRC522_CS_ACTIVE_HIGH) +# define MFRC522_CS_ACTIVE_LOW false +# else + /* Default to active low if neither is explicitly set */ +# define MFRC522_CS_ACTIVE_LOW true +# endif + +/* IRQ Configuration */ + +# ifdef CONFIG_NUCLEO_H753ZI_MFRC522_IRQ_ENABLE +# ifndef CONFIG_NUCLEO_H753ZI_MFRC522_IRQ_PIN +# error "MFRC522 IRQ enabled but IRQ pin not configured" +# endif +# define MFRC522_IRQ_PIN CONFIG_NUCLEO_H753ZI_MFRC522_IRQ_PIN +# define MFRC522_IRQ_ENABLED true +# else +# define MFRC522_IRQ_ENABLED false +# endif + +#endif /* CONFIG_NUCLEO_H753ZI_MFRC522_ENABLE */ + +/* LPS22HB - I2C Pressure Sensor */ + +#ifdef CONFIG_SENSORS_LPS22HB +# define GPIO_LPS22HB_INT1 (GPIO_INPUT | GPIO_FLOAT | GPIO_PORTB | \ + GPIO_PIN10) +#endif + +/* LSM6DSL - I2C 6-axis IMU */ + +#ifdef CONFIG_SENSORS_LSM6DSL +# define GPIO_LSM6DSL_INT1 (GPIO_INPUT | GPIO_FLOAT | GPIO_PORTB | \ + GPIO_PIN4) +# define GPIO_LSM6DSL_INT2 (GPIO_INPUT | GPIO_FLOAT | GPIO_PORTB | \ + GPIO_PIN5) +#endif + +/* LSM303AGR - I2C Magnetometer/Accelerometer */ + +/* TODO: Add LSM303AGR GPIO and I2C configurations when needed */ + +/* LSM9DS1 - I2C 9-axis IMU */ + +#ifdef CONFIG_SENSORS_LSM9DS1 +# define LMS9DS1_I2CBUS 1 +#endif + +/* TODO: Add new sensors here following this pattern: + * - Validate required Kconfig settings + * - Define GPIO pins (CS for SPI, INT pins, etc) + * - Define bus configuration (SPI/I2C bus number) + * - Add function prototype in SECTION 5 + * - Implement driver in src/stm32_yoursensor.c + */ + +/**************************************************************************** + * Displays + ****************************************************************************/ + +/* ST7796 - SPI LCD Display (480x320) */ + +#ifdef CONFIG_NUCLEO_H753ZI_ST7796_ENABLE + +/* Validate Kconfig */ + +# ifndef CONFIG_NUCLEO_H753ZI_ST7796_SPI_BUS +# error "ST7796 enabled but SPI bus not configured" +# endif + +# ifndef CONFIG_NUCLEO_H753ZI_ST7796_DEVID +# error "ST7796 enabled but device ID not configured" +# endif + +# ifndef CONFIG_NUCLEO_H753ZI_ST7796_CS_PIN +# error "ST7796 enabled but CS pin not configured" +# endif + +# ifndef CONFIG_NUCLEO_H753ZI_ST7796_DC_PIN +# error "ST7796 enabled but DC pin not configured" +# endif + +# ifndef CONFIG_NUCLEO_H753ZI_ST7796_RESET_PIN +# error "ST7796 enabled but RESET pin not configured" +# endif + +# ifndef CONFIG_NUCLEO_H753ZI_ST7796_LED_PIN +# error "ST7796 enabled but LED pin not configured" +# endif + +/* Device configuration (from Kconfig) */ + +# define ST7796_SPI_BUS CONFIG_NUCLEO_H753ZI_ST7796_SPI_BUS +# define ST7796_DEVICE_ID CONFIG_NUCLEO_H753ZI_ST7796_DEVID +# define ST7796_CS_PIN CONFIG_NUCLEO_H753ZI_ST7796_CS_PIN +# define ST7796_DC_PIN CONFIG_NUCLEO_H753ZI_ST7796_DC_PIN +# define ST7796_RESET_PIN CONFIG_NUCLEO_H753ZI_ST7796_RESET_PIN +# define ST7796_LED_PIN CONFIG_NUCLEO_H753ZI_ST7796_LED_PIN + +/* CS Active Level */ + +# if defined(CONFIG_NUCLEO_H753ZI_ST7796_CS_ACTIVE_LOW) +# define ST7796_CS_ACTIVE_LOW true +# elif defined(CONFIG_NUCLEO_H753ZI_ST7796_CS_ACTIVE_HIGH) +# define ST7796_CS_ACTIVE_LOW false +# else + /* Default to active low if neither is explicitly set */ +# define ST7796_CS_ACTIVE_LOW true +# endif + +#endif /* CONFIG_NUCLEO_H753ZI_ST7796_ENABLE */ + +/* SSD1306 - I2C OLED Display (128x64/128x32) */ + +#ifdef CONFIG_NUCLEO_H753ZI_SSD1306_ENABLE + +/* Hardware configuration from Kconfig */ + +# define NUCLEO_SSD1306_I2C_BUS CONFIG_NUCLEO_H753ZI_SSD1306_I2C_BUS +# define NUCLEO_SSD1306_I2C_ADDR CONFIG_NUCLEO_H753ZI_SSD1306_I2C_ADDR +# define NUCLEO_SSD1306_I2C_FREQUENCY \ + CONFIG_NUCLEO_H753ZI_SSD1306_I2C_FREQUENCY +# define NUCLEO_SSD1306_POWER_PERCENT \ + CONFIG_NUCLEO_H753ZI_SSD1306_POWER_PERCENT + +/* System configuration - from Kconfig */ + +# define NUCLEO_SSD1306_DEVPATH CONFIG_NUCLEO_H753ZI_SSD1306_DEVPATH +# define NUCLEO_SSD1306_DEVNO CONFIG_NUCLEO_H753ZI_SSD1306_DEVNO + +/* Device name for internal tracking */ + +# define NUCLEO_SSD1306_DEVNAME "ssd1306" + +#endif /* CONFIG_NUCLEO_H753ZI_SSD1306_ENABLE */ + +/* TODO: Add new displays here following ST7796/SSD1306 pattern: + * - Validate required Kconfig settings + * - Define GPIO pins (CS, DC, RESET, etc) + * - Define bus configuration (SPI/I2C) + * - Add function prototypes in SECTION 5 + * - Implement driver in src/stm32_yourdisplay.c + */ + +/**************************************************************************** + * Wireless Modules + ****************************************************************************/ + +/* NRF24L01 - SPI 2.4GHz Transceiver */ + +#ifdef CONFIG_WL_NRF24L01 +# define GPIO_NRF24L01_CS (GPIO_OUTPUT | GPIO_SPEED_50MHz | \ + GPIO_OUTPUT_SET | GPIO_PORTA | GPIO_PIN4) +# define GPIO_NRF24L01_CE (GPIO_OUTPUT | GPIO_SPEED_50MHz | \ + GPIO_OUTPUT_CLEAR | GPIO_PORTF | GPIO_PIN12) +# define GPIO_NRF24L01_IRQ (GPIO_INPUT | GPIO_FLOAT | GPIO_PORTD | \ + GPIO_PIN15) +#endif + +/* TODO: Add new wireless modules here following NRF24L01 pattern: + * - WiFi modules (ESP8266, ESP32-AT, etc) + * - LoRa modules (SX1276, SX1278, etc) + * - Bluetooth modules (HC-05, nRF52, etc) + * - Validate Kconfig settings + * - Define GPIO pins + * - Add function prototypes in SECTION 5 + * - Implement driver in src/stm32_yourwireless.c + */ + +/**************************************************************************** + * Storage Devices + ****************************************************************************/ + +/* MMCSD - SPI SD Card */ + +#ifdef CONFIG_MMCSD_SPI +# define GPIO_MMCSD_CS (GPIO_OUTPUT | GPIO_PUSHPULL | \ + GPIO_SPEED_50MHz | GPIO_OUTPUT_SET | \ + GPIO_PORTD | GPIO_PIN15) +# define GPIO_MMCSD_NCD (GPIO_INPUT | GPIO_PULLUP | GPIO_EXTI | \ + GPIO_PORTF | GPIO_PIN12) +#endif + +/* TODO: Add new storage devices here following MMCSD pattern: + * - QSPI Flash (W25Q, MX25, etc) + * - I2C EEPROM (AT24C, M24C, etc) + * - SPI Flash (AT25, SST25, etc) + * - Validate Kconfig settings + * - Define GPIO pins (CS, WP, HOLD, etc) + * - Add function prototypes in SECTION 5 + * - Implement driver in src/stm32_yourstorage.c + */ + +/**************************************************************************** + * Actuators & LED Controllers + ****************************************************************************/ + +/* PCA9635 - I2C LED Controller */ + +#ifdef CONFIG_PCA9635PW +# define PCA9635_I2CBUS 1 +# define PCA9635_I2CADDR 0x40 +#endif + +/* PWM Configuration */ + +#define NUCLEOH753ZI_PWMTIMER 1 + +/* TODO: Add new actuators here: + * - Servo controllers (PCA9685, etc) + * - Motor drivers (DRV8833, L298N, etc) + * - Relay modules + * - Define GPIO pins + * - Define bus configuration + * - Add function prototypes in SECTION 5 + * - Implement driver in src/stm32_youractuator.c + */ + +/**************************************************************************** + * SECTION 5: FUNCTION PROTOTYPES + ****************************************************************************/ + +/**************************************************************************** + * Core System Initialization + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_bringup + * + * Description: + * Perform architecture-specific initialization + * + * CONFIG_BOARD_LATE_INITIALIZE=y : + * Called from board_late_initialize(). + * + * CONFIG_BOARD_LATE_INITIALIZE=n && CONFIG_BOARDCTL=y && + * CONFIG_NSH_ARCHINIT: + * Called from the NSH library + * + ****************************************************************************/ + +int stm32_bringup(void); + +/**************************************************************************** + * Communication Bus Drivers - SPI + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_spi_initialize + * + * Description: + * Initialize SPI interfaces and CS pins. + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +#ifdef CONFIG_STM32H7_SPI +int stm32_spi_initialize(void); + +/**************************************************************************** + * Name: stm32_spi_register_cs_device + * + * Description: + * Register a CS device for a specific SPI bus and device ID. + * + * Input Parameters: + * spi_bus - SPI bus number (1-6) + * devid - Device ID (0-15) + * cs_pin - CS pin string (e.g., "PF1") + * active_low - true if CS is active low, false if active high + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_spi_register_cs_device(int spi_bus, uint32_t devid, + const char *cs_pin, bool active_low); + +/**************************************************************************** + * Name: stm32_spi_unregister_cs_device + * + * Description: + * Unregister a CS device. + * + * Input Parameters: + * spi_bus - SPI bus number (1-6) + * devid - Device ID + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_spi_unregister_cs_device(int spi_bus, uint32_t devid); + +#ifdef CONFIG_SPI_CMDDATA + +/**************************************************************************** + * Name: stm32_spi_register_dc_pin + * + * Description: + * Register CMD/DATA pin for SPI devices (e.g., displays). + * + * Input Parameters: + * spi_bus - SPI bus number (1-6) + * devid - Device ID + * dc_pin - DC pin string (e.g., "PF2") + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_spi_register_dc_pin(int spi_bus, uint32_t devid, + const char *dc_pin); + +#endif /* CONFIG_SPI_CMDDATA */ +#endif /* CONFIG_STM32H7_SPI */ + +/**************************************************************************** + * Name: stm32_spidev_initialize + * + * Description: + * Called to configure SPI chip select GPIO pins for the Nucleo-H753ZI + * board. + * + ****************************************************************************/ + +#if defined(CONFIG_STM32H7_SPI1) || defined(CONFIG_STM32H7_SPI2) || \ + defined(CONFIG_STM32H7_SPI3) || defined(CONFIG_STM32H7_SPI4) || \ + defined(CONFIG_STM32H7_SPI5) || defined(CONFIG_STM32H7_SPI6) +void weak_function stm32_spidev_initialize(void); +#endif + +#ifdef CONFIG_SPI_DRIVER + +/**************************************************************************** + * Name: stm32_spidev_register_all + * + * Description: + * Register all SPI devices for userspace access. + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_spidev_register_all(void); + +#endif + +/**************************************************************************** + * Communication Bus Drivers - I2C + ****************************************************************************/ + +#ifdef CONFIG_STM32H7_I2C + +/**************************************************************************** + * Name: stm32_i2c_initialize + * + * Description: + * Initialize I2C buses based on Kconfig configuration. + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_i2c_initialize(void); + +/**************************************************************************** + * Name: stm32_i2c_register_device + * + * Description: + * Register an I2C device with specific address, frequency, and name. + * + * Input Parameters: + * i2c_bus - I2C bus number (1-4) + * addr - I2C slave address (7-bit, 0x08-0x77) + * frequency - Bus frequency for this device (Hz) + * name - Descriptive name for logging (can be NULL) + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_i2c_register_device(int i2c_bus, uint8_t addr, + uint32_t frequency, const char *name); + +/**************************************************************************** + * Name: stm32_i2c_unregister_device + * + * Description: + * Unregister an I2C device by address. + * + * Input Parameters: + * i2c_bus - I2C bus number (1-4) + * addr - I2C slave address to unregister + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_i2c_unregister_device(int i2c_bus, uint8_t addr); + +/**************************************************************************** + * Name: stm32_i2c_get_master + * + * Description: + * Get I2C master interface for a specific bus. + * + * Input Parameters: + * i2c_bus - I2C bus number (1-4) + * + * Returned Value: + * Pointer to I2C master interface, NULL if invalid or not initialized + * + ****************************************************************************/ + +struct i2c_master_s *stm32_i2c_get_master(int i2c_bus); + +#ifdef CONFIG_I2C_RESET + +/**************************************************************************** + * Name: stm32_i2c_scan_bus + * + * Description: + * Scan an I2C bus for connected devices (debugging). + * + * Input Parameters: + * i2c_bus - I2C bus number (1-4) + * + * Returned Value: + * Number of devices found, negative errno on error + * + ****************************************************************************/ + +int stm32_i2c_scan_bus(int i2c_bus); + +#endif + +/**************************************************************************** + * Name: stm32_i2c_list_devices + * + * Description: + * List all registered I2C devices on a specific bus (debugging). + * + * Input Parameters: + * i2c_bus - I2C bus number (1-4), or 0 for all buses + * + * Returned Value: + * Number of registered devices + * + ****************************************************************************/ + +int stm32_i2c_list_devices(int i2c_bus); + +#endif /* CONFIG_STM32H7_I2C */ + +/**************************************************************************** + * CAN/FDCAN Drivers + ****************************************************************************/ + +#ifdef CONFIG_STM32H7_FDCAN + +/**************************************************************************** + * Name: stm32_fdcansockinitialize + * + * Description: + * Initialize FDCAN socket interface. + * + * Input Parameters: + * intf - Interface number (0 for FDCAN1/can0, 1 for FDCAN2/can1) + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_fdcansockinitialize(int intf); + +#endif + +/**************************************************************************** + * USB Drivers + ****************************************************************************/ + +#ifdef CONFIG_STM32H7_OTGFS +void weak_function stm32_usbinitialize(void); +#endif + +#if defined(CONFIG_STM32H7_OTGFS) && defined(CONFIG_USBHOST) + +/**************************************************************************** + * Name: stm32_usbhost_initialize + * + * Description: + * Initialize USB host controller. + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_usbhost_initialize(void); + +#endif + +/**************************************************************************** + * Sensor Drivers + ****************************************************************************/ + +#ifdef CONFIG_NUCLEO_H753ZI_MFRC522_ENABLE + +/**************************************************************************** + * Name: stm32_mfrc522initialize + * + * Description: + * Initialize MFRC522 RFID reader. + * + * Input Parameters: + * devpath - Device path (e.g., "/dev/rfid0") + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_mfrc522initialize(const char *devpath); + +#endif + +#ifdef CONFIG_SENSORS_LSM6DSL + +/**************************************************************************** + * Name: stm32_lsm6dsl_initialize + * + * Description: + * Initialize LSM6DSL 6-axis IMU sensor. + * + * Input Parameters: + * devpath - Device path (e.g., "/dev/lsm6dsl0") + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_lsm6dsl_initialize(char *devpath); + +#endif + +#ifdef CONFIG_SENSORS_LSM303AGR + +/**************************************************************************** + * Name: stm32_lsm303agr_initialize + * + * Description: + * Initialize LSM303AGR magnetometer/accelerometer. + * + * Input Parameters: + * devpath - Device path + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_lsm303agr_initialize(char *devpath); + +#endif + +#ifdef CONFIG_SENSORS_LSM9DS1 + +/**************************************************************************** + * Name: stm32_lsm9ds1_initialize + * + * Description: + * Initialize LSM9DS1 9-axis IMU sensor. + * + * Input Parameters: + * devpath - Device path + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_lsm9ds1_initialize(char *devpath); + +#endif + +/**************************************************************************** + * Display Drivers + ****************************************************************************/ + +/**************************************************************************** + * ST7796 TFT Display Support + ****************************************************************************/ + +#if defined(CONFIG_LCD_ST7796) && defined(CONFIG_NUCLEO_H753ZI_ST7796_ENABLE) + +/**************************************************************************** + * Name: stm32_st7796initialize + * + * Description: + * Initialize and register the ST7796 LCD framebuffer driver. + * + * Input Parameters: + * devno - Device number (0 for /dev/fb0) + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int stm32_st7796initialize(int devno); + +/**************************************************************************** + * Name: stm32_st7796_flush_fb + * + * Description: + * Flush the entire framebuffer to the display. This is needed for SPI + * displays to make the splashscreen visible after fb_register(). + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int stm32_st7796_flush_fb(void); + +/**************************************************************************** + * Name: stm32_st7796_backlight + * + * Description: + * Control the ST7796 backlight LED. + * + * Input Parameters: + * on - true to turn on, false to turn off + * + * Returned Value: + * None + * + ****************************************************************************/ + +void stm32_st7796_backlight(bool on); + +/**************************************************************************** + * Name: stm32_st7796_power + * + * Description: + * Control the ST7796 display power. + * + * Input Parameters: + * on - true to turn on, false to turn off + * + * Returned Value: + * None + * + ****************************************************************************/ + +void stm32_st7796_power(bool on); + +/**************************************************************************** + * Name: stm32_st7796_reset_display + * + * Description: + * Perform hardware reset of the ST7796 display. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void stm32_st7796_reset_display(void); + +/**************************************************************************** + * Name: stm32_st7796_cleanup + * + * Description: + * Cleanup ST7796 resources. + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_st7796_cleanup(void); + +#endif /* CONFIG_LCD_ST7796 && CONFIG_NUCLEO_H753ZI_ST7796_ENABLE */ + +#ifdef CONFIG_NUCLEO_H753ZI_SSD1306_ENABLE +/**************************************************************************** + * Name: stm32_ssd1306_get_devpath + * + * Description: + * Get the configured device path for SSD1306. + * + * Returned Value: + * Pointer to device path string + * + ****************************************************************************/ + +const char *stm32_ssd1306_get_devpath(void); + +/**************************************************************************** + * Name: stm32_ssd1306_set_power + * + * Description: + * Change SSD1306 display power at runtime. + * + * Input Parameters: + * percent - Power level 0-100% (0 = off, 1-100 = on with brightness) + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_ssd1306_set_power(int percent); + +/**************************************************************************** + * Name: stm32_ssd1306_set_brightness + * + * Description: + * Change SSD1306 display brightness at runtime (display must be on). + * + * Input Parameters: + * percent - Brightness level 0-100% + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_ssd1306_set_brightness(int percent); + +#endif /* CONFIG_NUCLEO_H753ZI_SSD1306_ENABLE */ + +/**************************************************************************** + * Wireless Drivers + ****************************************************************************/ + +#ifdef CONFIG_WL_NRF24L01 + +/**************************************************************************** + * Name: stm32_wlinitialize + * + * Description: + * Initialize NRF24L01 wireless module. + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_wlinitialize(void); + +#endif + +/**************************************************************************** + * Storage Drivers + ****************************************************************************/ + +#ifdef CONFIG_MMCSD_SPI + +/**************************************************************************** + * Name: stm32_mmcsd_initialize + * + * Description: + * Initialize MMC/SD card over SPI. + * + * Input Parameters: + * minor - Device minor number + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_mmcsd_initialize(int minor); + +#endif + +#ifdef CONFIG_MTD +#ifdef HAVE_PROGMEM_CHARDEV + +/**************************************************************************** + * Name: stm32_progmem_init + * + * Description: + * Initialize internal flash as MTD device. + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_progmem_init(void); + +#endif /* HAVE_PROGMEM_CHARDEV */ +#endif /* CONFIG_MTD */ + +/**************************************************************************** + * Actuator & LED Controller Drivers + ****************************************************************************/ + +#ifdef CONFIG_PCA9635PW + +/**************************************************************************** + * Name: stm32_pca9635_initialize + * + * Description: + * Initialize PCA9635 I2C LED controller. + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_pca9635_initialize(void); + +#endif + +#ifdef CONFIG_PWM + +/**************************************************************************** + * Name: stm32_pwm_setup + * + * Description: + * Initialize PWM outputs. + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_pwm_setup(void); + +#endif + +/**************************************************************************** + * GPIO & ADC Drivers + ****************************************************************************/ + +#ifdef CONFIG_DEV_GPIO + +/**************************************************************************** + * Name: stm32_gpio_initialize + * + * Description: + * Initialize GPIO drivers for use with /apps/examples/gpio + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_gpio_initialize(void); + +#endif + +#ifdef CONFIG_ADC + +/**************************************************************************** + * Name: stm32_adc_setup + * + * Description: + * Initialize ADC and register the ADC driver. + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_adc_setup(void); + +#endif + +#endif /* __BOARDS_ARM_STM32H7_NUCLEO_H753ZI_SRC_NUCLEO_H753ZI_H */ diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_adc.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_adc.c new file mode 100644 index 0000000000000..d56ebe5de64bd --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_adc.c @@ -0,0 +1,270 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_adc.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include + +#include "chip.h" +#include "stm32_gpio.h" +#include "stm32_adc.h" + +#include "nucleo-h753zi.h" + +#ifdef CONFIG_ADC + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* Up to 3 ADC interfaces are supported */ + +#if defined(CONFIG_STM32H7_ADC1) || defined(CONFIG_STM32H7_ADC2) || \ + defined(CONFIG_STM32H7_ADC3) + +/* The number of ADC channels in the conversion list */ + +#define ADC1_NCHANNELS 7 +#define ADC2_NCHANNELS 5 +#define ADC3_NCHANNELS 1 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_STM32H7_ADC1 +/* Identifying number of each ADC channel: Variable Resistor. + * + * ADC1: {5, 10, 15, 18, 19, 7, 12}; + */ + +static const uint8_t g_adc1_chanlist[ADC1_NCHANNELS] = +{ + 5, 10, 15, 18, 19, 7, 12 +}; + +static const uint32_t g_adc1_pinlist[ADC1_NCHANNELS] = + { + GPIO_ADC12_INP5, + GPIO_ADC123_INP10, + GPIO_ADC12_INP15, + GPIO_ADC12_INP18, + GPIO_ADC12_INP19, + GPIO_ADC123_INP7, + GPIO_ADC123_INP12 + }; + +#endif /* CONFIG_STM32H7_ADC1 */ + +/**************************************************************************** + * ADC2 + ****************************************************************************/ +#ifdef CONFIG_STM32H7_ADC2 + +static const uint8_t g_adc2_chanlist[ADC2_NCHANNELS] = +{ + 2, 3, 14, 4, 8 +}; + +static const uint32_t g_adc2_pinlist[ADC2_NCHANNELS] = +{ + GPIO_ADC2_INP2, + GPIO_ADC12_INP3, + GPIO_ADC12_INP14, + GPIO_ADC12_INP4, + GPIO_ADC12_INP8 +}; +#endif /* CONFIG_STM32H7_ADC2 */ + +#ifdef CONFIG_STM32H7_ADC3 +/* Identifying number of each ADC channel: Variable Resistor. + * + * ADC3: {6,}; + */ + +static const uint8_t g_adc3_chanlist[ADC1_NCHANNELS] = +{ + 11 +}; + +/* Configurations of pins used by each ADC channels + * + * + * ADC3: {GPIO_ADC3_INP6} + */ + +static const uint32_t g_adc3_pinlist[ADC3_NCHANNELS] = +{ + GPIO_ADC123_INP11, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_adc_setup + * + * Description: + * Initialize ADC and register the ADC driver. + * + ****************************************************************************/ + +int stm32_adc_setup(void) +{ +#if defined(CONFIG_STM32H7_ADC1) || defined(CONFIG_STM32H7_ADC3) + static bool initialized = false; + struct adc_dev_s *adc; + int ret; + int i; + char devname[] = "/dev/adc0"; + + /* Check if we have already initialized */ + + if (!initialized) + { +#endif +#if defined(CONFIG_STM32H7_ADC1) + /* Configure the pins as analog inputs for the selected channels */ + + for (i = 0; i < ADC1_NCHANNELS; i++) + { + if (g_adc1_pinlist[i] != 0) + { + stm32_configgpio(g_adc1_pinlist[i]); + } + } + + /* Call stm32_adcinitialize() to get an instance of the ADC interface */ + + adc = stm32h7_adc_initialize(1, g_adc1_chanlist, ADC1_NCHANNELS); + if (adc == NULL) + { + aerr("ERROR: Failed to get ADC1 interface\n"); + return -ENODEV; + } + + /* Register the ADC driver at "/dev/adc0" */ + + ret = adc_register(devname, adc); + if (ret < 0) + { + aerr("ERROR: adc_register(%s) failed: %d\n", devname, ret); + return ret; + } + + devname[8]++; +#endif + +#ifdef CONFIG_STM32H7_ADC2 + /* Configure the pins as analog inputs for the selected channels */ + + for (i = 0; i < ADC2_NCHANNELS; i++) + { + if (g_adc2_pinlist[i] != 0) + { + stm32_configgpio(g_adc2_pinlist[i]); + } + } + + /* Call stm32_adcinitialize() to get an instance of the ADC interface */ + + adc = stm32h7_adc_initialize(2, g_adc2_chanlist, ADC2_NCHANNELS); + if (adc == NULL) + { + aerr("ERROR: Failed to get ADC2 interface\n"); + return -ENODEV; + } + + /* Register the ADC driver at "/dev/adc[0-1]" */ + + ret = adc_register(devname, adc); + if (ret < 0) + { + aerr("ERROR: adc_register(%s) failed: %d\n", devname, ret); + return ret; + } + + devname[8]++; +#endif + +#if defined(CONFIG_STM32H7_ADC3) + /* Configure the pins as analog inputs for the selected channels */ + + for (i = 0; i < ADC3_NCHANNELS; i++) + { + if (g_adc3_pinlist[i] != 0) + { + stm32_configgpio(g_adc3_pinlist[i]); + } + } + + /* Call stm32_adcinitialize() to get an instance of the ADC interface */ + + adc = stm32h7_adc_initialize(3, g_adc3_chanlist, ADC3_NCHANNELS); + if (adc == NULL) + { + aerr("ERROR: Failed to get ADC3 interface\n"); + return -ENODEV; + } + + /* Register the ADC driver at "/dev/adc[0-2]" */ + + ret = adc_register(devname, adc); + if (ret < 0) + { + aerr("ERROR: adc_register(%s) failed: %d\n", devname, ret); + return ret; + } +#endif + +#if defined(CONFIG_STM32H7_ADC1) || defined(CONFIG_STM32H7_ADC2) || \ + defined(CONFIG_STM32H7_ADC3) + /* Now we are initialized */ + + initialized = true; + } + + return OK; +#else + return -ENOSYS; +#endif +} + +#endif /* CONFIG_STM32H7_ADC1 || CONFIG_STM32H7_ADC2 || CONFIG_STM32H7_ADC3 */ +#endif /* CONFIG_ADC */ diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_appinitialize.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_appinitialize.c new file mode 100644 index 0000000000000..0f63bdcb24295 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_appinitialize.c @@ -0,0 +1,78 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_appinitialize.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "nucleo-h753zi.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_app_initialize + * + * Description: + * Perform application specific initialization. This function is never + * called directly from application code, but only indirectly via the + * (non-standard) boardctl() interface using the command BOARDIOC_INIT. + * + * Input Parameters: + * arg - The boardctl() argument is passed to the board_app_initialize() + * implementation without modification. The argument has no + * meaning to NuttX; the meaning of the argument is a contract + * between the board-specific initialization logic and the + * matching application logic. The value could be such things as a + * mode enumeration value, a set of DIP switch switch settings, a + * pointer to configuration data read from a file or serial FLASH, + * or whatever you would like to do with it. Every implementation + * should accept zero/NULL as a default configuration. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure to indicate the nature of the failure. + * + ****************************************************************************/ + +int board_app_initialize(uintptr_t arg) +{ +#ifdef CONFIG_BOARD_LATE_INITIALIZE + /* Board initialization already performed by board_late_initialize() */ + + return OK; +#else + /* Perform board-specific initialization */ + + return stm32_bringup(); +#endif +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_autoleds.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_autoleds.c new file mode 100644 index 0000000000000..df65cfd694d63 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_autoleds.c @@ -0,0 +1,179 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_autoleds.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include +#include + +#include "stm32_gpio.h" +#include "nucleo-h753zi.h" + +/* Only compile when AUTO LEDs mode is enabled */ +#ifdef CONFIG_ARCH_LEDS + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Indexed by BOARD_LED_ */ + +static const uint32_t g_ledmap[BOARD_NLEDS] = +{ + GPIO_LED_GREEN, + GPIO_LED_ORANGE, + GPIO_LED_RED, +}; + +static bool g_initialized; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void phy_set_led(int led, bool state) +{ + /* Active High */ + + stm32_gpiowrite(g_ledmap[led], state); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_autoled_initialize + ****************************************************************************/ + +void board_autoled_initialize(void) +{ + int i; + + /* Configure the LED GPIOs for output. Initial state is OFF */ + + for (i = 0; i < nitems(g_ledmap); i++) + { + stm32_configgpio(g_ledmap[i]); + } + +#ifdef CONFIG_NUCLEO_H753ZI_LEDS_AUTO + + /* Log only when explicitly configured for AUTO mode */ + + ledinfo("Auto LEDs initialized for kernel status indication\n"); +#endif +} + +/**************************************************************************** + * Name: board_autoled_on + ****************************************************************************/ + +void board_autoled_on(int led) +{ + switch (led) + { + default: + break; + + case LED_HEAPALLOCATE: + phy_set_led(BOARD_LED_ORANGE, true); + break; + + case LED_IRQSENABLED: + phy_set_led(BOARD_LED_ORANGE, false); + phy_set_led(BOARD_LED_GREEN, true); + break; + + case LED_STACKCREATED: + phy_set_led(BOARD_LED_GREEN, true); + phy_set_led(BOARD_LED_ORANGE, true); + g_initialized = true; + break; + + case LED_INIRQ: + phy_set_led(BOARD_LED_ORANGE, true); + break; + + case LED_SIGNAL: + phy_set_led(BOARD_LED_GREEN, true); + break; + + case LED_ASSERTION: + phy_set_led(BOARD_LED_RED, true); + phy_set_led(BOARD_LED_ORANGE, true); + break; + + case LED_PANIC: + phy_set_led(BOARD_LED_RED, true); + break; + + case LED_IDLE : /* IDLE */ + phy_set_led(BOARD_LED_RED, true); + break; + } +} + +/**************************************************************************** + * Name: board_autoled_off + ****************************************************************************/ + +void board_autoled_off(int led) +{ + switch (led) + { + default: + break; + + case LED_SIGNAL: + phy_set_led(BOARD_LED_GREEN, false); + break; + + case LED_INIRQ: + phy_set_led(BOARD_LED_ORANGE, false); + break; + + case LED_ASSERTION: + phy_set_led(BOARD_LED_RED, false); + phy_set_led(BOARD_LED_ORANGE, false); + break; + + case LED_PANIC: + phy_set_led(BOARD_LED_RED, false); + break; + + case LED_IDLE : /* IDLE */ + phy_set_led(BOARD_LED_RED, false); + break; + } +} + +#endif /* CONFIG_ARCH_LEDS */ diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_boot.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_boot.c new file mode 100644 index 0000000000000..c2d2774582abe --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_boot.c @@ -0,0 +1,93 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_boot.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include + +#include "arm_internal.h" +#include "stm32_start.h" +#include "nucleo-h753zi.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_boardinitialize + * + * Description: + * All STM32 architectures must provide the following entry point. + * This entry point is called early in the initialization -- after all + * memory has been configured and mapped but before any devices have been + * initialized. + * + ****************************************************************************/ + +void stm32_boardinitialize(void) +{ +#ifdef CONFIG_ARCH_LEDS + /* Configure on-board LEDs if LED support has been selected. */ + + board_autoled_initialize(); +#endif + +#if defined(CONFIG_STM32H7_OTGFS) || defined(CONFIG_STM32H7_HOST) + /* Initialize USB */ + + stm32_usbinitialize(); +#endif + +#ifdef CONFIG_STM32H7_SPI + /* Configure SPI chip selects */ + + stm32_spidev_initialize(); +#endif +} + +/**************************************************************************** + * Name: board_late_initialize + * + * Description: + * If CONFIG_BOARD_LATE_INITIALIZE is selected, then an additional + * initialization call will be performed in the boot-up sequence to a + * function called board_late_initialize(). board_late_initialize() + * will be called immediately after up_initialize() is called and just + * before the initial application is started. This additional + * initialization phase may be used, for example, to initialize board- + * specific device drivers. + * + ****************************************************************************/ + +#ifdef CONFIG_BOARD_LATE_INITIALIZE +void board_late_initialize(void) +{ + stm32_bringup(); +} +#endif diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_boot_image.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_boot_image.c new file mode 100644 index 0000000000000..617977c07d87f --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_boot_image.c @@ -0,0 +1,185 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_boot_image.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "nvic.h" +#include "arm_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure represents the first two entries on NVIC vector table */ + +struct arm_vector_table +{ + uint32_t spr; /* Stack pointer on reset */ + uint32_t reset; /* Pointer to reset exception handler */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void cleanup_arm_nvic(void); +static void systick_disable(void); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cleanup_arm_nvic + * + * Description: + * Acknowledge and disable all interrupts in NVIC + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void cleanup_arm_nvic(void) +{ + int i; + + /* Allow any pending interrupts to be recognized */ + + UP_ISB(); + cpsid(); + + /* Disable all interrupts */ + + for (i = 0; i < NR_IRQS; i += 32) + { + putreg32(0xffffffff, NVIC_IRQ_CLEAR(i)); + } + + /* Clear all pending interrupts */ + + for (i = 0; i < NR_IRQS; i += 32) + { + putreg32(0xffffffff, NVIC_IRQ_CLRPEND(i)); + } +} + +/**************************************************************************** + * Name: systick_disable + * + * Description: + * Disable the SysTick system timer + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void systick_disable(void) +{ + putreg32(0, NVIC_SYSTICK_CTRL); + putreg32(NVIC_SYSTICK_RELOAD_MASK, NVIC_SYSTICK_RELOAD); + putreg32(0, NVIC_SYSTICK_CURRENT); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_boot_image + * + * Description: + * This entry point is called by bootloader to jump to application image. + * + ****************************************************************************/ + +int board_boot_image(const char *path, uint32_t hdr_size) +{ + static struct arm_vector_table vt; + struct file file; + ssize_t bytes; + int ret; + + ret = file_open(&file, path, O_RDONLY | O_CLOEXEC); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to open %s with: %d", path, ret); + return ret; + } + + bytes = file_pread(&file, &vt, sizeof(vt), hdr_size); + if (bytes != sizeof(vt)) + { + syslog(LOG_ERR, "Failed to read ARM vector table: %d", bytes); + return bytes < 0 ? bytes : -1; + } + + systick_disable(); + + cleanup_arm_nvic(); + +#ifdef CONFIG_ARMV7M_DCACHE + up_disable_dcache(); +#endif +#ifdef CONFIG_ARMV7M_ICACHE + up_disable_icache(); +#endif + +#ifdef CONFIG_ARM_MPU + mpu_control(false, false, false); +#endif + + /* Set main and process stack pointers */ + + __asm__ __volatile__("\tmsr msp, %0\n" + "\tmsr control, %1\n" + "\tisb\n" + "\tmov pc, %2\n" + : + : "r" (vt.spr), "r" (0), "r" (vt.reset)); + + return 0; +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_bringup.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_bringup.c new file mode 100644 index 0000000000000..810c70cdbed01 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_bringup.c @@ -0,0 +1,1547 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_bringup.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/* System includes */ + +#include +#include +#include +#include +#include + +/* Filesystem includes */ + +#include + +/* Communication protocol includes */ + +#ifdef CONFIG_I2C +# include +#endif + +#ifdef CONFIG_SPI +# include +#endif + +/* STM32-specific includes */ + +#include "stm32_gpio.h" +#include "hardware/stm32_gpio.h" +#include "arm_internal.h" +#include "hardware/stm32h7x3xx_rcc.h" + +#ifdef CONFIG_STM32H7_I2C +# include "stm32_i2c.h" +#endif + +#ifdef CONFIG_STM32H7_SPI +# include "stm32_spi.h" +#endif + +/* Display includes */ + +#ifdef CONFIG_LCD_ST7796 +# include +# include +#endif + +#ifdef CONFIG_LCD_DEV +# include +#endif + +#ifdef CONFIG_LCD_SSD1306 +# include +# include +#endif + +#include +#include "nucleo-h753zi.h" + +/* USB-related includes */ + +#ifdef CONFIG_USBMONITOR +# include +#endif + +#ifdef CONFIG_STM32H7_OTGFS +# include "stm32_usbhost.h" +#endif + +#ifdef CONFIG_RNDIS +# include +#endif + +/* Input device includes */ + +#ifdef CONFIG_INPUT_BUTTONS +# include +#endif + +/* LED includes */ + +#ifdef CONFIG_USERLED +# include +#endif + +/* Timer-related includes */ + +#ifdef HAVE_RTC_DRIVER +# include +# include "stm32_rtc.h" +#endif + +#ifdef CONFIG_CAPTURE +# include +# include "stm32_capture.h" +#endif + +#ifdef CONFIG_STM32H7_IWDG +# include "stm32_wdg.h" +#endif + +/* Storage includes */ + +#ifdef CONFIG_STM32_ROMFS +# include "drivers/driver_middleware/stm32_romfs.h" +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Initialization functions organized by name length (longest to shortest) */ + +static int nucleo_automotive_initialize(void); +static int nucleo_communication_initialize(void); +static int nucleo_connectivity_initialize(void); +static int nucleo_filesystem_initialize(void); +static int nucleo_watchdog_initialize(void); +static int nucleo_sensors_initialize(void); +static int nucleo_display_initialize(void); +static int nucleo_storage_initialize(void); +static int nucleo_timers_initialize(void); +static int nucleo_input_initialize(void); +static int nucleo_gpio_initialize(void); +static int nucleo_led_initialize(void); +static int nucleo_usb_initialize(void); +static int nucleo_rtc_initialize(void); +static int nucleo_adc_initialize(void); + +#if defined(CONFIG_I2C) && defined(CONFIG_SYSTEM_I2CTOOL) + static int nucleo_i2c_tools_initialize(void); +#endif + +#ifdef CONFIG_CAPTURE + static int nucleo_capture_initialize(void); +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nucleo_led_initialize + * + * Description: + * Initialize LED subsystem based on configuration + * Priority: HIGH (provides early visual feedback) + * + * Dependencies: None + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nucleo_led_initialize(void) +{ + int ret = OK; + +#ifdef CONFIG_NUCLEO_H753ZI_LEDS_USER + + ret = userled_lower_initialize("/dev/userleds"); + if (ret < 0) + { + syslog(LOG_ERR, + "[ERROR: BRINGUP] - userled_lower_initialize() " + "failed: %d\n", ret); + } + else + { + syslog(LOG_INFO, + "[INFO: BRINGUP] - User LEDs initialized at " + "/dev/userleds\n"); + } + +#elif defined(CONFIG_NUCLEO_H753ZI_LEDS_AUTO) + + syslog(LOG_INFO, + "[INFO: BRINGUP] - Auto LEDs enabled for system status " + "indication\n"); + +#elif defined(CONFIG_NUCLEO_H753ZI_LEDS_DISABLED) + + syslog(LOG_INFO, + "[INFO: BRINGUP] - LEDs disabled by configuration\n"); + +#endif + + return ret; +} + +/**************************************************************************** + * Name: nucleo_filesystem_initialize + * + * Description: + * Initialize filesystem support (PROCFS, ROMFS) + * Priority: HIGH (required for logging and configuration) + * + * Dependencies: None + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nucleo_filesystem_initialize(void) +{ + int ret = OK; + +#ifdef CONFIG_FS_PROCFS + + int local_ret = nx_mount(NULL, STM32_PROCFS_MOUNTPOINT, "procfs", 0, NULL); + if (local_ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to mount PROCFS: %d\n", local_ret); + if (ret == OK) + { + ret = local_ret; + } + } + else + { + syslog(LOG_INFO, + "PROCFS mounted at %s\n", STM32_PROCFS_MOUNTPOINT); + } + +#endif /* CONFIG_FS_PROCFS */ + +#ifdef CONFIG_STM32_ROMFS + + int local_ret = stm32_romfs_initialize(); + if (local_ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to mount ROMFS at %s: %d\n", + CONFIG_STM32_ROMFS_MOUNTPOINT, local_ret); + + if (ret == OK) + { + ret = local_ret; + } + } + else + { + syslog(LOG_INFO, + "ROMFS mounted at %s\n", CONFIG_STM32_ROMFS_MOUNTPOINT); + } +#endif + + return ret; +} + +/**************************************************************************** + * Name: nucleo_rtc_initialize + * + * Description: + * Initialize Real-Time Clock driver + * Priority: HIGH (time services for other subsystems) + * + * Dependencies: None + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nucleo_rtc_initialize(void) +{ + int ret = OK; + +#ifdef HAVE_RTC_DRIVER + + struct rtc_lowerhalf_s *lower; + + lower = stm32_rtc_lowerhalf(); + if (!lower) + { + syslog(LOG_ERR, + "ERROR: Failed to instantiate RTC lower-half driver\n"); + return -ENOMEM; + } + + ret = rtc_initialize(0, lower); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to bind/register RTC driver: %d\n", ret); + } + else + { + syslog(LOG_INFO, + "RTC driver registered as /dev/rtc0\n"); + } +#endif + + return ret; +} + +/**************************************************************************** + * Name: nucleo_gpio_initialize + * + * Description: + * Initialize GPIO driver for user applications + * Priority: HIGH (required by many other drivers) + * + * Dependencies: None + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nucleo_gpio_initialize(void) +{ + int ret = OK; + +#ifdef CONFIG_DEV_GPIO + + ret = stm32_gpio_initialize(); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to initialize GPIO driver: %d\n", ret); + } + else + { + syslog(LOG_INFO, + "GPIO driver initialized\n"); + } +#endif + + return ret; +} + +/**************************************************************************** + * Name: nucleo_automotive_initialize + * + * Description: + * Initialize automotive/industrial communication protocols (CAN, LIN, etc.) + * Priority: MEDIUM + * + * Dependencies: GPIO, Clock configuration + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nucleo_automotive_initialize(void) +{ + int ret = OK; + +#ifdef CONFIG_STM32H7_FDCAN1 + + /* syslog(LOG_INFO, + * "[FDCAN1] Starting initialization...\n"); + */ + + /* Initialize FDCAN1 driver FIRST */ + + int local_ret = stm32_fdcansockinitialize(0); + if (local_ret < 0) + { + syslog(LOG_ERR, + "[FDCAN1] ERROR: Failed to initialize: %d\n", local_ret); + + if (ret == OK) + { + ret = local_ret; + } + } + else + { + syslog(LOG_INFO, + "[FDCAN1] Driver initialized as /dev/can0\n"); + + /* DEBUG + * + * NOW force GPIO configuration AFTER driver init + * syslog(LOG_INFO, + * "[FDCAN1] Forcing GPIO reconfiguration...\n"); + * + * syslog(LOG_INFO, + * "[FDCAN1] GPIO_CAN1_RX: 0x%08lx\n", + * (unsigned long)GPIO_CAN1_RX); + * + * syslog(LOG_INFO, + * "[FDCAN1] GPIO_CAN1_TX: 0x%08lx\n", + * (unsigned long)GPIO_CAN1_TX); + * + * + * Verify GPIO and RCC configuration + * syslog(LOG_INFO, + * + * uint32_t rcc_apb1henr = getreg32(STM32_RCC_APB1HENR); + * uint32_t rcc_d2ccip1r = getreg32(STM32_RCC_D2CCIP1R); + * + * uint32_t gpiob_otyper = getreg32(STM32_GPIOB_OTYPER); + * + * "[FDCAN1] POST-CONFIG:\n"); + * syslog(LOG_INFO, + * "[FDCAN1] RCC_APB1HENR: 0x%08lx (bit 8=%d)\n", + * (unsigned long)rcc_apb1henr, + * (int)((rcc_apb1henr >> 8) & 1)); + * syslog(LOG_INFO, "[FDCAN1] RCC_D2CCIP1R: 0x%08lx (clk_sel=%lu)\n", + * (unsigned long)rcc_d2ccip1r, + * (unsigned long)((rcc_d2ccip1r >> 28) & 0x3)); + * syslog(LOG_INFO, "[FDCAN1] GPIOB_MODER: 0x%08lx " + * "(PB8[17:16]=%lu, PB9[19:18]=%lu)\n", + * (unsigned long)gpiob_moder, + * (unsigned long)((gpiob_moder >> 16) & 0x3), + * (unsigned long)((gpiob_moder >> 18) & 0x3)); + * syslog(LOG_INFO, "[FDCAN1] GPIOB_AFRH: 0x%08lx " + * "(PB8[3:0]=%lu, PB9[7:4]=%lu)\n", + * (unsigned long)gpiob_afrh, + * (unsigned long)(gpiob_afrh & 0xf), + * (unsigned long)((gpiob_afrh >> 4) & 0xf)); + * syslog(LOG_INFO, "[FDCAN1] GPIOB_OTYPER: 0x%08lx " + * "(PB8[8]=%d, PB9[9]=%d)\n", + * (unsigned long)gpiob_otyper, + * (int)((gpiob_otyper >> 8) & 1), + * (int)((gpiob_otyper >> 9) & 1)); + * + * + * Expected values: + * MODER: PB8=10b (AF), PB9=10b (AF) + * AFRH: PB8=9 (AF9), PB9=9 (AF9) + * OTYPER: PB8=0 (push-pull), PB9=0 (push-pull) + */ + + stm32_configgpio(GPIO_CAN1_RX); /* PB8 */ + stm32_configgpio(GPIO_CAN1_TX); /* PB9 */ + + uint32_t gpiob_moder = getreg32(STM32_GPIOB_MODER); + uint32_t gpiob_afrh = getreg32(STM32_GPIOB_AFRH); + + if (((gpiob_moder >> 16) & 0x3) != 0x2 || + ((gpiob_moder >> 18) & 0x3) != 0x2) + { + syslog(LOG_ERR, + "[FDCAN1] ERROR: GPIO not in AF mode!\n"); + } + + if ((gpiob_afrh & 0xf) != 9 || ((gpiob_afrh >> 4) & 0xf) != 9) + { + syslog(LOG_ERR, + "[FDCAN1] ERROR: GPIO not set to AF9!\n"); + } + } +#endif + +#ifdef CONFIG_STM32H7_FDCAN2 + + /* Initialize FDCAN2 and register as /dev/can1 */ + + int local_ret = stm32_fdcansockinitialize(1); + if (local_ret < 0) + { + syslog(LOG_ERR, "[FDCAN2] ERROR: Failed to initialize: %d\n", + local_ret); + if (ret == OK) + { + ret = local_ret; + } + } + else + { + syslog(LOG_INFO, + "[FDCAN2] Initialized as /dev/can1\n"); + } +#endif + + /* Future: LIN, FlexRay initialization here */ + + return ret; +} + +/**************************************************************************** + * Name: nucleo_communication_initialize + * + * Description: + * Initialize general-purpose communication bus drivers (SPI, I2C) + * Priority: HIGH (required by sensors and other peripherals) + * + * Dependencies: GPIO + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nucleo_communication_initialize(void) +{ + int ret = OK; + int local_ret; + + UNUSED(local_ret); + +#ifdef CONFIG_STM32H7_SPI + local_ret = stm32_spi_initialize(); + if (local_ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_spi_initialize failed: %d\n", + local_ret); + if (ret == OK) + { + ret = local_ret; + } + } + else + { + syslog(LOG_INFO, "SPI buses initialized\n"); + } +#endif + +#ifdef CONFIG_SPI_DRIVER + local_ret = stm32_spidev_register_all(); + if (local_ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_spidev_register_all failed: %d\n", + local_ret); + } + else + { + syslog(LOG_INFO, "SPI character drivers registered\n"); + } +#endif + +#ifdef CONFIG_STM32H7_I2C + local_ret = stm32_i2c_initialize(); + if (local_ret < 0) + { + syslog(LOG_ERR, "ERROR: I2C bus initialization failed: %d\n", + local_ret); + if (ret == OK) + { + ret = local_ret; + } + } + else + { + syslog(LOG_INFO, "I2C buses initialized\n"); +#if defined(CONFIG_I2C) && defined(CONFIG_SYSTEM_I2CTOOL) + local_ret = nucleo_i2c_tools_initialize(); + if (local_ret < 0) + { + syslog(LOG_ERR, "ERROR: I2C tools registration failed: %d\n", + local_ret); + } +#endif + } +#endif + + return ret; +} + +/**************************************************************************** + * Name: nucleo_input_initialize + * + * Description: + * Initialize input devices (buttons, etc.) + * Priority: MEDIUM + * + * Dependencies: GPIO + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nucleo_input_initialize(void) +{ + int ret = OK; + +#ifdef CONFIG_INPUT_BUTTONS + + ret = btn_lower_initialize("/dev/buttons"); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: btn_lower_initialize() failed: %d\n", ret); + } + else + { + syslog(LOG_INFO, + "Buttons driver registered as /dev/buttons\n"); + } +#endif + + return ret; +} + +/**************************************************************************** + * Name: nucleo_usb_initialize + * + * Description: + * Initialize USB subsystem (host, device, monitoring) + * Priority: MEDIUM + * + * Dependencies: None + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nucleo_usb_initialize(void) +{ + int ret = OK; + +#ifdef HAVE_USBHOST + + int local_ret = stm32_usbhost_initialize(); + if (local_ret != OK) + { + syslog(LOG_ERR, + "ERROR: Failed to initialize USB host: %d\n", local_ret); + if (ret == OK) + { + ret = local_ret; + } + } + else + { + syslog(LOG_INFO, + "USB host initialized\n"); + } +#endif + +#ifdef HAVE_USBMONITOR + + int local_ret = usbmonitor_start(); + if (local_ret != OK) + { + syslog(LOG_ERR, "ERROR: Failed to start USB monitor: %d\n", + local_ret); + if (ret == OK) + { + ret = local_ret; + } + } + else + { + syslog(LOG_INFO, + "USB monitor started\n"); + } +#endif + +#if defined(CONFIG_CDCACM) && !defined(CONFIG_CDCACM_CONSOLE) && \ + !defined(CONFIG_CDCACM_COMPOSITE) + + syslog(LOG_INFO, "Initializing CDC/ACM device\n"); + + int local_ret = cdcacm_initialize(0, NULL); + if (local_ret < 0) + { + syslog(LOG_ERR, "ERROR: cdcacm_initialize failed: %d\n", local_ret); + if (ret == OK) + { + ret = local_ret; + } + } + else + { + syslog(LOG_INFO, + "CDC/ACM device initialized\n"); + } +#endif + +#if defined(CONFIG_RNDIS) && !defined(CONFIG_RNDIS_COMPOSITE) + + uint8_t mac[6]; + mac[0] = 0xa0; + mac[1] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 0)) & 0xff; + mac[2] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 3)) & 0xff; + mac[3] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 2)) & 0xff; + mac[4] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 1)) & 0xff; + mac[5] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 0)) & 0xff; + + int local_ret = usbdev_rndis_initialize(mac); + if (local_ret < 0) + { + syslog(LOG_ERR, "ERROR: RNDIS initialization failed: %d\n", + local_ret); + if (ret == OK) + { + ret = local_ret; + } + } + else + { + syslog(LOG_INFO, + "RNDIS USB device initialized\n"); + } +#endif + + return ret; +} + +/**************************************************************************** + * Name: nucleo_adc_initialize + * + * Description: + * Initialize Analog-to-Digital Converter + * Priority: MEDIUM + * + * Dependencies: GPIO + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nucleo_adc_initialize(void) +{ + int ret = OK; + +#ifdef CONFIG_ADC + + ret = stm32_adc_setup(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_adc_setup failed: %d\n", ret); + } + else + { + syslog(LOG_INFO, + "ADC driver initialized\n"); + } +#endif + + return ret; +} + +/**************************************************************************** + * Name: nucleo_sensors_initialize + * + * Description: + * Initialize sensor drivers (IMU, magnetometer, RFID, etc.) + * Priority: LOW (application-specific) + * + * Dependencies: I2C, SPI, GPIO + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nucleo_sensors_initialize(void) +{ + int ret = OK; + +#ifdef CONFIG_SENSORS_LSM6DSL + + int local_ret = stm32_lsm6dsl_initialize("/dev/lsm6dsl0"); + if (local_ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to initialize LSM6DSL driver: %d\n", + local_ret); + if (ret == OK) + { + ret = local_ret; + } + } + else + { + syslog(LOG_INFO, + "LSM6DSL sensor initialized as /dev/lsm6dsl0\n"); + } +#endif + +#ifdef CONFIG_SENSORS_LSM9DS1 + + int local_ret = stm32_lsm9ds1_initialize(); + if (local_ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to initialize LSM9DS1 driver: %d\n", + local_ret); + if (ret == OK) + { + ret = local_ret; + } + } + else + { + syslog(LOG_INFO, + "LSM9DS1 sensor initialized\n"); + } +#endif + +#ifdef CONFIG_SENSORS_LSM303AGR + + int local_ret = stm32_lsm303agr_initialize("/dev/lsm303mag0"); + if (local_ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to initialize LSM303AGR driver: %d\n", + local_ret); + if (ret == OK) + { + ret = local_ret; + } + } + else + { + syslog(LOG_INFO, + "LSM303AGR magnetometer initialized as /dev/lsm303mag0\n"); + } +#endif + +#ifdef CONFIG_NUCLEO_H753ZI_MFRC522_ENABLE + + int local_ret = stm32_mfrc522initialize(MFRC522_DEVPATH); + if (local_ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_mfrc522initialize() failed: %d\n", + local_ret); + + if (ret == OK) + { + ret = local_ret; + } + } + else + { + syslog(LOG_INFO, + "MFRC522 RFID reader initialized successfully at %s\n", + MFRC522_DEVPATH); + } +#endif + + return ret; +} + +/**************************************************************************** + * Name: nucleo_display_initialize + * + * Description: + * Initialize display drivers (LCD, OLED, TFT, etc.) + * Priority: MEDIUM + * + * Dependencies: SPI, I2C, GPIO + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nucleo_display_initialize(void) +{ + int ret = OK; + +#if defined(CONFIG_LCD_SSD1306) && \ + defined(CONFIG_NUCLEO_H753ZI_SSD1306_ENABLE) + + ret = board_lcd_initialize(); + if (ret == OK) + { + struct lcd_dev_s *lcd = board_lcd_getdev(NUCLEO_SSD1306_DEVNO); + if (lcd != NULL) + { +#ifdef CONFIG_LCD_DEV + + ret = lcddev_register(NUCLEO_SSD1306_DEVNO); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: lcddev_register(%d) failed: %d\n", + NUCLEO_SSD1306_DEVNO, ret); + } + else + { + syslog(LOG_INFO, + "SSD1306 OLED registered at /dev/lcd%d\n", + NUCLEO_SSD1306_DEVNO); + } +#endif + } + } +#endif + +#if defined(CONFIG_LCD_ST7796) && \ + defined(CONFIG_NUCLEO_H753ZI_ST7796_ENABLE) + + /* syslog(LOG_INFO, "Initializing ST7796 TFT display...\n"); */ + + int local_ret = stm32_st7796initialize(0); + if (local_ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_st7796initialize() failed: %d\n", + local_ret); + if (ret == OK) + { + ret = local_ret; + } + } + else + { + /* syslog(LOG_INFO, + * "ST7796 TFT display initialized successfully at %s\n", + * ST7796_FB_PATH); + */ + + /* CRITICAL: Flush splashscreen from RAM to SPI display */ + + local_ret = stm32_st7796_flush_fb(); + if (local_ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to flush splashscreen: %d\n", + local_ret); + } + else + { + /* syslog(LOG_INFO, " + * ST7796: Splashscreen flushed to display\n"); + */ + } + + /* Enable backlight after flush */ + + stm32_st7796_backlight(true); + + /* syslog(LOG_INFO, + * "ST7796 backlight enabled\n"); + */ + } +#endif + + return ret; +} + +/**************************************************************************** + * Name: nucleo_connectivity_initialize + * + * Description: + * Initialize wireless connectivity modules (Wi-Fi, Bluetooth, etc.) + * Priority: LOW (application-specific) + * + * Dependencies: SPI, I2C, GPIO + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nucleo_connectivity_initialize(void) +{ + int ret = OK; + +#ifdef CONFIG_PCA9635PW + + ret = stm32_pca9635_initialize(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_pca9635_initialize failed: %d\n", ret); + } + else + { + syslog(LOG_INFO, "PCA9635 LED controller initialized\n"); + } +#endif + +#ifdef CONFIG_WL_NRF24L01 + + ret = stm32_wlinitialize(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to initialize wireless driver: %d\n", + ret); + } + else + { + syslog(LOG_INFO, "NRF24L01 wireless driver initialized\n"); + } +#endif + + return ret; +} + +/**************************************************************************** + * Name: nucleo_storage_initialize + * + * Description: + * Initialize storage devices (SD card, flash, etc.) + * Priority: MEDIUM + * + * Dependencies: SPI (for SD cards), filesystem + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nucleo_storage_initialize(void) +{ + int ret = OK; + +#ifdef CONFIG_MMCSD_SPI + + ret = stm32_mmcsd_initialize(CONFIG_NSH_MMCSDMINOR); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to initialize SD slot %d: %d\n", + CONFIG_NSH_MMCSDMINOR, ret); + } + else + { + syslog(LOG_INFO, "MMC/SD SPI driver initialized (slot %d)\n", + CONFIG_NSH_MMCSDMINOR); + } +#endif + +#ifdef CONFIG_MTD +#ifdef HAVE_PROGMEM_CHARDEV + + ret = stm32_progmem_init(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to initialize MTD progmem: %d\n", ret); + } + else + { + syslog(LOG_INFO, "MTD program memory initialized\n"); + } +#endif +#endif + + return ret; +} + +/**************************************************************************** + * Name: nucleo_timers_initialize + * + * Description: + * Initialize timer-related drivers (PWM, capture, etc.) + * Priority: LOW + * + * Dependencies: GPIO + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nucleo_timers_initialize(void) +{ + int ret = OK; + +#ifdef CONFIG_PWM + + int local_ret = stm32_pwm_setup(); + if (local_ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_pwm_setup() failed: %d\n", local_ret); + if (ret == OK) + { + ret = local_ret; + } + } + else + { + syslog(LOG_INFO, "PWM drivers initialized\n"); + } +#endif + +#ifdef CONFIG_CAPTURE + + int local_ret = nucleo_capture_initialize(); + if (local_ret < 0) + { + syslog(LOG_ERR, + "ERROR: nucleo_capture_initialize() failed: %d\n", + local_ret); + if (ret == OK) + { + ret = local_ret; + } + } + else + { + syslog(LOG_INFO, "Timer capture drivers initialized\n"); + } +#endif + + return ret; +} + +/**************************************************************************** + * Name: nucleo_watchdog_initialize + * + * Description: + * Initialize watchdog timer + * Priority: LOW (should be last - for system monitoring) + * + * Dependencies: None (intentionally independent) + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nucleo_watchdog_initialize(void) +{ + int ret = OK; + +#ifdef CONFIG_STM32H7_IWDG + + ret = stm32_iwdginitialize("/dev/watchdog0", STM32_LSI_FREQUENCY); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to initialize watchdog: %d\n", ret); + } + else + { + syslog(LOG_INFO, "Watchdog initialized as /dev/watchdog0\n"); + } +#endif + + return ret; +} + +/**************************************************************************** + * Name: nucleo_i2c_tools_initialize + * + * Description: + * Initialize I2C tools for debugging and development. This registers the + * I2C buses as character drivers (e.g., /dev/i2c1) to allow tools like + * i2c-tools to interact with the bus from user space. + * + * Priority: LOW (development/debugging only) + * + * Dependencies: I2C hardware must be initialized first. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +#if defined(CONFIG_I2C) && defined(CONFIG_SYSTEM_I2CTOOL) +static int stm32_i2c_register(int bus) +{ + struct i2c_master_s *i2c; + int ret; + + /* Get the I2C bus instance */ + + i2c = stm32_i2cbus_initialize(bus); + if (i2c == NULL) + { + syslog(LOG_ERR, "ERROR: Failed to get I2C%d interface\n", bus); + return -ENODEV; + } + + /* Register the bus as a character driver (/dev/i2cN) */ + + ret = i2c_register(i2c, bus); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to register I2C%d driver: %d\n", + bus, ret); + + /* Only uninitialize if registration fails and no other + * peripheral is using this bus instance. + */ + + stm32_i2cbus_uninitialize(i2c); + return ret; + } + + syslog(LOG_INFO, "I2C%d registered for tools at /dev/i2c%d\n", bus, bus); + return OK; +} + +static int nucleo_i2c_tools_initialize(void) +{ + int ret = OK; + int local_ret; + +#ifdef CONFIG_STM32H7_I2C1 + local_ret = stm32_i2c_register(1); + if (local_ret < 0) + { + ret = local_ret; + } +#endif + +#ifdef CONFIG_STM32H7_I2C2 + local_ret = stm32_i2c_register(2); + if (local_ret < 0 && ret == OK) + { + ret = local_ret; + } +#endif + +#ifdef CONFIG_STM32H7_I2C3 + local_ret = stm32_i2c_register(3); + if (local_ret < 0 && ret == OK) + { + ret = local_ret; + } +#endif + +#ifdef CONFIG_STM32H7_I2C4 + local_ret = stm32_i2c_register(4); + if (local_ret < 0 && ret == OK) + { + ret = local_ret; + } +#endif + + return ret; +} +#endif + +/**************************************************************************** + * Name: nucleo_capture_initialize + * + * Description: + * Initialize and register capture drivers + * Priority: LOW + * + * Dependencies: Timer peripherals + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_CAPTURE +static int nucleo_capture_initialize(void) +{ + int ret; + + struct cap_lowerhalf_s *lower[] = + { +#if defined(CONFIG_STM32H7_TIM1_CAP) + stm32_cap_initialize(1), +#endif +#if defined(CONFIG_STM32H7_TIM2_CAP) + stm32_cap_initialize(2), +#endif +#if defined(CONFIG_STM32H7_TIM3_CAP) + stm32_cap_initialize(3), +#endif +#if defined(CONFIG_STM32H7_TIM4_CAP) + stm32_cap_initialize(4), +#endif +#if defined(CONFIG_STM32H7_TIM5_CAP) + stm32_cap_initialize(5), +#endif +#if defined(CONFIG_STM32H7_TIM8_CAP) + stm32_cap_initialize(8), +#endif +#if defined(CONFIG_STM32H7_TIM12_CAP) + stm32_cap_initialize(12), +#endif +#if defined(CONFIG_STM32H7_TIM13_CAP) + stm32_cap_initialize(13), +#endif +#if defined(CONFIG_STM32H7_TIM14_CAP) + stm32_cap_initialize(14), +#endif +#if defined(CONFIG_STM32H7_TIM15_CAP) + stm32_cap_initialize(15), +#endif +#if defined(CONFIG_STM32H7_TIM16_CAP) + stm32_cap_initialize(16), +#endif +#if defined(CONFIG_STM32H7_TIM17_CAP) + stm32_cap_initialize(17), +#endif + }; + + size_t count = sizeof(lower) / sizeof(lower[0]); + + if (count == 0) + { + return OK; + } + + ret = cap_register_multiple("/dev/cap", lower, count); + if (ret == EINVAL) + { + syslog(LOG_ERR, "ERROR: cap_register_multiple path is invalid\n"); + } + else if (ret == EEXIST) + { + syslog(LOG_ERR, + "ERROR: cap_register_multiple inode already exists\n"); + } + else if (ret == ENOMEM) + { + syslog(LOG_ERR, + "ERROR: cap_register_multiple not enough memory\n"); + } + else if (ret < 0) + { + syslog(LOG_ERR, "ERROR: cap_register_multiple failed: %d\n", ret); + } + + return ret; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_bringup + * + * Description: + * Perform architecture-specific initialization with dependency-aware + * ordering + * + * This function initializes all board-specific drivers and subsystems + * in a controlled manner, ensuring that dependencies between subsystems + * are respected and failures in one subsystem do not prevent + * initialization of others. + * + * INITIALIZATION PHASES WITH DEPENDENCY MANAGEMENT: + * + * Phase 1 - Basic System & Visual Feedback + * Phase 2 - Hardware Interfaces & Communication Protocols + * Phase 3 - User Interface & USB Services + * Phase 4 - Analog Measurement (ADC) + * Phase 5 - Display Drivers (LCD, OLED, TFT) + * Phase 6 - Sensors & Wireless Connectivity + * Phase 7 - Storage Devices (SD Card, Flash) + * Phase 8 - Timers, PWM & Signal Processing + * Phase 9 - System Monitoring (Watchdog) + * + * ERROR HANDLING STRATEGY: + * Individual subsystem failures are logged via syslog. + * The function continues to initialize other subsystems even if one fails. + * A single return value (ret) tracks the status of the first failure. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int stm32_bringup(void) +{ + int ret = OK; + int subsys_ret; + + /* syslog(LOG_INFO, + * "\n[INFO: BRINGUP] Nucleo-H753ZI initialization...\n"); + */ + + /* PHASE 1: BASIC SYSTEM & VISUAL FEEDBACK */ + + /* syslog(LOG_INFO, + * "[INFO: BRINGUP] Phase 1: Initializing basic system & " + * "visual feedback\n"); + */ + + subsys_ret = nucleo_led_initialize(); + if (subsys_ret != OK && ret == OK) + { + ret = subsys_ret; + } + + subsys_ret = nucleo_filesystem_initialize(); + if (subsys_ret != OK && ret == OK) + { + ret = subsys_ret; + } + + subsys_ret = nucleo_rtc_initialize(); + if (subsys_ret != OK && ret == OK) + { + ret = subsys_ret; + } + + /* PHASE 2: HARDWARE INTERFACES & COMMUNICATION PROTOCOLS */ + + /* syslog(LOG_INFO, + * "[INFO: BRINGUP] Phase 2: Initializing hardware interfaces & " + * "communication protocols\n"); + */ + + subsys_ret = nucleo_gpio_initialize(); + if (subsys_ret != OK && ret == OK) + { + ret = subsys_ret; + } + + subsys_ret = nucleo_communication_initialize(); + if (subsys_ret != OK && ret == OK) + { + ret = subsys_ret; + } + + subsys_ret = nucleo_automotive_initialize(); + if (subsys_ret != OK && ret == OK) + { + ret = subsys_ret; + } + + /* PHASE 3: USER INTERFACE & USB SERVICES */ + + /* syslog(LOG_INFO, + * "[INFO: BRINGUP] Phase 3: Initializing user interface & " + * "USB services\n"); + */ + + subsys_ret = nucleo_input_initialize(); + if (subsys_ret != OK && ret == OK) + { + ret = subsys_ret; + } + + subsys_ret = nucleo_usb_initialize(); + if (subsys_ret != OK && ret == OK) + { + ret = subsys_ret; + } + + /* PHASE 4: ANALOG MEASUREMENT (ADC) */ + + /* syslog(LOG_INFO, + * "[INFO: BRINGUP] Phase 4: Initializing analog measurement " + * "(ADC)\n"); + */ + + subsys_ret = nucleo_adc_initialize(); + if (subsys_ret != OK && ret == OK) + { + ret = subsys_ret; + } + + /* PHASE 5: DISPLAY DRIVERS (LCD, OLED, TFT) */ + + /* syslog(LOG_INFO, + * "[INFO: BRINGUP] Phase 5: Initializing display drivers\n"); + */ + + subsys_ret = nucleo_display_initialize(); + if (subsys_ret != OK && ret == OK) + { + ret = subsys_ret; + } + + /* PHASE 6: SENSORS & WIRELESS CONNECTIVITY */ + + /* syslog(LOG_INFO, + * "[INFO: BRINGUP] Phase 6: Initializing sensors & " + * "wireless connectivity\n"); + */ + + subsys_ret = nucleo_sensors_initialize(); + if (subsys_ret != OK && ret == OK) + { + ret = subsys_ret; + } + + subsys_ret = nucleo_connectivity_initialize(); + if (subsys_ret != OK && ret == OK) + { + ret = subsys_ret; + } + + /* PHASE 7: STORAGE DEVICES (SD CARD, FLASH) */ + + /* syslog(LOG_INFO, + * "[INFO: BRINGUP] Phase 7: Initializing storage devices " + * "(SD card, flash)\n"); + */ + + subsys_ret = nucleo_storage_initialize(); + if (subsys_ret != OK && ret == OK) + { + ret = subsys_ret; + } + + /* PHASE 8: TIMERS, PWM & SIGNAL PROCESSING */ + + /* syslog(LOG_INFO, + * "[INFO: BRINGUP] Phase 8: Initializing timers, PWM & " + * "signal processing\n"); + */ + + subsys_ret = nucleo_timers_initialize(); + if (subsys_ret != OK && ret == OK) + { + ret = subsys_ret; + } + + /* PHASE 9: SYSTEM MONITORING (WATCHDOG) */ + + /* syslog(LOG_INFO, + * "[INFO: BRINGUP] Phase 9: Initializing system monitoring " + * "(watchdog)\n"); + */ + + subsys_ret = nucleo_watchdog_initialize(); + if (subsys_ret != OK && ret == OK) + { + ret = subsys_ret; + } + + /* INITIALIZATION COMPLETE */ + + if (ret == OK) + { + syslog(LOG_INFO, + "[INFO: BRINGUP] Nucleo-H753ZI board initialization " + "completed successfully\n"); + } + else + { + syslog(LOG_WARNING, + "[WARNING: BRINGUP] Nucleo-H753ZI board initialization " + "completed with errors: %d\n", + ret); + syslog(LOG_INFO, + "[INFO: BRINGUP] System is functional, but some drivers " + "may be unavailable\n"); + } + + return ret; +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_buttons.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_buttons.c new file mode 100644 index 0000000000000..a59823ce59d59 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_buttons.c @@ -0,0 +1,806 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_buttons.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "stm32_gpio.h" +#include "nucleo-h753zi.h" + +#ifdef CONFIG_NUCLEO_H753ZI_BUTTON_SUPPORT + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if defined(CONFIG_INPUT_BUTTONS) && !defined(CONFIG_ARCH_IRQBUTTONS) +# error "The NuttX Buttons Driver depends on IRQ support to work!" +#endif + +#define MAX_PIN_CONFIG_LEN 512 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Dynamic button configuration array */ + +static uint32_t g_buttons[CONFIG_NUCLEO_H753ZI_BUTTON_COUNT]; +static int g_button_count = 0; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: get_exti_line + * + * Description: + * Extract EXTI line number from GPIO configuration. + * + * Input Parameters: + * gpio_config - STM32 GPIO configuration + * + * Returned Value: + * EXTI line number (0-15), or -1 on error + * + ****************************************************************************/ + +static int get_exti_line(uint32_t gpio_config) +{ + /* Extract pin number from GPIO_PIN mask */ + + uint32_t pin_mask = gpio_config & GPIO_PIN_MASK; + + switch (pin_mask) + { + case GPIO_PIN0: + return 0; + + case GPIO_PIN1: + return 1; + + case GPIO_PIN2: + return 2; + + case GPIO_PIN3: + return 3; + + case GPIO_PIN4: + return 4; + + case GPIO_PIN5: + return 5; + + case GPIO_PIN6: + return 6; + + case GPIO_PIN7: + return 7; + + case GPIO_PIN8: + return 8; + + case GPIO_PIN9: + return 9; + + case GPIO_PIN10: + return 10; + + case GPIO_PIN11: + return 11; + + case GPIO_PIN12: + return 12; + + case GPIO_PIN13: + return 13; + + case GPIO_PIN14: + return 14; + + case GPIO_PIN15: + return 15; + + default: + return -1; + } +} + +/**************************************************************************** + * Name: get_gpio_port_letter + * + * Description: + * Get port letter from GPIO configuration. + * + * Input Parameters: + * gpio_config - STM32 GPIO configuration + * + * Returned Value: + * Port letter ('A'-'H'), or '?' on error + * + ****************************************************************************/ + +static char get_gpio_port_letter(uint32_t gpio_config) +{ + uint32_t port = gpio_config & GPIO_PORT_MASK; + + switch (port) + { + case GPIO_PORTA: + return 'A'; + + case GPIO_PORTB: + return 'B'; + + case GPIO_PORTC: + return 'C'; + + case GPIO_PORTD: + return 'D'; + + case GPIO_PORTE: + return 'E'; + + case GPIO_PORTF: + return 'F'; + + case GPIO_PORTG: + return 'G'; + + case GPIO_PORTH: + return 'H'; + + default: + return '?'; + } +} + +/**************************************************************************** + * Name: parse_gpio_pin + * + * Description: + * Parse GPIO pin string like "PF15" into STM32 GPIO configuration. + * + * Input Parameters: + * pin_str - GPIO pin string (e.g., "PA0", "PF15", "PC13") + * error - Pointer to error code storage + * + * Returned Value: + * STM32 GPIO configuration value on success, 0 on error + * + ****************************************************************************/ + +static uint32_t parse_gpio_pin(FAR const char *pin_str, FAR int *error) +{ + size_t len; + char port; + FAR const char *pin_num_str; + FAR char *endptr; + long pin_num; + uint32_t port_base; + uint32_t gpio_pin; + + *error = 0; + + if (pin_str == NULL) + { + *error = -EINVAL; + return 0; + } + + /* Remove leading/trailing spaces */ + + while (*pin_str == ' ' || *pin_str == '\t') + { + pin_str++; + } + + len = strlen(pin_str); + if (len < 3 || len > 4) + { + *error = -EINVAL; + return 0; + } + + if (pin_str[0] != 'P') + { + *error = -EINVAL; + return 0; + } + + port = pin_str[1]; + if (port < 'A' || port > 'H') + { + *error = -EINVAL; + return 0; + } + + pin_num_str = &pin_str[2]; + pin_num = strtol(pin_num_str, &endptr, 10); + if (*endptr != '\0' || pin_num < 0 || pin_num > 15) + { + *error = -EINVAL; + return 0; + } + + /* Map port letter to STM32 port base */ + + switch (port) + { + case 'A': + port_base = GPIO_PORTA; + break; + + case 'B': + port_base = GPIO_PORTB; + break; + + case 'C': + port_base = GPIO_PORTC; + break; + + case 'D': + port_base = GPIO_PORTD; + break; + + case 'E': + port_base = GPIO_PORTE; + break; + + case 'F': + port_base = GPIO_PORTF; + break; + + case 'G': + port_base = GPIO_PORTG; + break; + + case 'H': + port_base = GPIO_PORTH; + break; + + default: + *error = -EINVAL; + return 0; + } + + /* Use correct STM32 GPIO pin macros */ + + switch (pin_num) + { + case 0: + gpio_pin = GPIO_PIN0; + break; + + case 1: + gpio_pin = GPIO_PIN1; + break; + + case 2: + gpio_pin = GPIO_PIN2; + break; + + case 3: + gpio_pin = GPIO_PIN3; + break; + + case 4: + gpio_pin = GPIO_PIN4; + break; + + case 5: + gpio_pin = GPIO_PIN5; + break; + + case 6: + gpio_pin = GPIO_PIN6; + break; + + case 7: + gpio_pin = GPIO_PIN7; + break; + + case 8: + gpio_pin = GPIO_PIN8; + break; + + case 9: + gpio_pin = GPIO_PIN9; + break; + + case 10: + gpio_pin = GPIO_PIN10; + break; + + case 11: + gpio_pin = GPIO_PIN11; + break; + + case 12: + gpio_pin = GPIO_PIN12; + break; + + case 13: + gpio_pin = GPIO_PIN13; + break; + + case 14: + gpio_pin = GPIO_PIN14; + break; + + case 15: + gpio_pin = GPIO_PIN15; + break; + + default: + *error = -EINVAL; + return 0; + } + + /* CRITICAL FIX: Use GPIO_PULLDOWN instead of GPIO_FLOAT + * + * The Nucleo-H753ZI board has external pull-down resistors on button + * pins. Using GPIO_FLOAT causes instability due to high impedance state + * combined with variable leakage current. GPIO_PULLDOWN ensures stable + * LOW state when button is not pressed, working in conjunction with the + * external pull-down for robust operation. + */ + + return (GPIO_INPUT | GPIO_PULLDOWN | GPIO_EXTI | port_base | gpio_pin); +} + +/**************************************************************************** + * Name: print_exti_conflict_error + * + * Description: + * Print detailed EXTI conflict error message. + * + * Input Parameters: + * conflicting_button - Index of button that conflicts + * current_button - Index of button being added + * pin_str - Pin string being added + * gpio_config - GPIO config of new pin + * exti_line - EXTI line that conflicts + * + ****************************************************************************/ + +static void print_exti_conflict_error(int conflicting_button, + int current_button, + FAR const char *pin_str, + uint32_t gpio_config, + int exti_line) +{ + char port1 = get_gpio_port_letter(g_buttons[conflicting_button]); + char port2 = get_gpio_port_letter(gpio_config); + int pin1 = get_exti_line(g_buttons[conflicting_button]); + int pin2 = get_exti_line(gpio_config); + int alt; + int i; + bool used; + + syslog(LOG_ERR, "\n"); + syslog(LOG_ERR, + "======================================================\n"); + syslog(LOG_ERR, " CRITICAL ERROR: EXTI LINE CONFLICT DETECTED!\n"); + syslog(LOG_ERR, + "======================================================\n"); + syslog(LOG_ERR, "\n"); + syslog(LOG_ERR, + "Button %d (P%c%d) and Button %d (%s = P%c%d) both use EXTI%d\n", + conflicting_button, port1, pin1, + current_button, pin_str, port2, pin2, + exti_line); + syslog(LOG_ERR, "\n"); + syslog(LOG_ERR, "EXPLANATION:\n"); + syslog(LOG_ERR, + " STM32 EXTI lines are shared across GPIO ports.\n"); + syslog(LOG_ERR, + " Only ONE pin per number can be used as interrupt source.\n"); + syslog(LOG_ERR, + " Example: PA3, PB3, PC3, PD3... all share EXTI3.\n"); + syslog(LOG_ERR, "\n"); + syslog(LOG_ERR, "WHAT WILL HAPPEN IF YOU IGNORE THIS:\n"); + syslog(LOG_ERR, " - The LAST pin (P%c%d) will work\n", port2, pin2); + syslog(LOG_ERR, + " - The FIRST pin (P%c%d) will NOT trigger interrupts\n", + port1, pin1); + syslog(LOG_ERR, " - You will see 'ghost' button presses\n"); + syslog(LOG_ERR, "\n"); + syslog(LOG_ERR, "SOLUTION:\n"); + syslog(LOG_ERR, + " Change one of the conflicting pins to a different number.\n"); + syslog(LOG_ERR, "\n"); + syslog(LOG_ERR, " Example fixes:\n"); + + /* Suggest alternative pins */ + + for (alt = 0; alt < 16; alt++) + { + if (alt == exti_line) + { + continue; + } + + /* Check if this EXTI is already used */ + + used = false; + for (i = 0; i < current_button; i++) + { + if (get_exti_line(g_buttons[i]) == alt) + { + used = true; + break; + } + } + + if (!used) + { + syslog(LOG_ERR, + " - Change P%c%d to P%c%d (EXTI%d is free)\n", + port2, pin2, port2, alt, alt); + break; + } + } + + syslog(LOG_ERR, "\n"); + syslog(LOG_ERR, "Current button configuration:\n"); + for (i = 0; i < current_button; i++) + { + int line = get_exti_line(g_buttons[i]); + char prt = get_gpio_port_letter(g_buttons[i]); + syslog(LOG_ERR, " Button %d: P%c%d (EXTI%d)%s\n", + i, prt, line, line, + (i == conflicting_button) ? " <- CONFLICT" : ""); + } + + syslog(LOG_ERR, " Button %d: %s (P%c%d, EXTI%d) <- CONFLICT\n", + current_button, pin_str, port2, pin2, exti_line); + syslog(LOG_ERR, "\n"); +} + +/**************************************************************************** + * Name: init_button_configs + * + * Description: + * Initialize button configuration from Kconfig settings with validation. + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +static int init_button_configs(void) +{ + int expected_pins; + FAR const char *pins_config; + char pins_str[MAX_PIN_CONFIG_LEN]; + FAR char *pin; + int error; + uint32_t gpio_config; + int i; + int exti_line; + size_t config_len; + + /* EXTI conflict detection */ + + int exti_usage[16]; + + g_button_count = 0; + + /* Initialize EXTI tracking */ + + for (i = 0; i < 16; i++) + { + exti_usage[i] = -1; /* -1 = unused */ + } + + /* Calculate how many external pins we expect */ + +#ifdef CONFIG_NUCLEO_H753ZI_BUTTON_BUILTIN + g_buttons[g_button_count] = GPIO_BTN_BUILT_IN; + + /* Register built-in button EXTI */ + + exti_line = get_exti_line(GPIO_BTN_BUILT_IN); + if (exti_line >= 0) + { + exti_usage[exti_line] = g_button_count; + } + + g_button_count++; + expected_pins = CONFIG_NUCLEO_H753ZI_BUTTON_COUNT - 1; +#else + expected_pins = CONFIG_NUCLEO_H753ZI_BUTTON_COUNT; +#endif + + /* If no external pins needed, we're done */ + + if (expected_pins == 0) + { + return OK; + } + + /* Validate pin string is not empty */ + + pins_config = CONFIG_NUCLEO_H753ZI_BUTTON_PINS; + if (pins_config == NULL || strlen(pins_config) == 0) + { + syslog(LOG_ERR, "ERROR: Button pins not configured!\n"); + syslog(LOG_ERR, + "Expected %d GPIO pins but BUTTON_PINS is empty\n", + expected_pins); + syslog(LOG_ERR, + "Configure in: Board Selection -> Button Configuration\n"); + return -EINVAL; + } + + /* Validate configuration length */ + + config_len = strlen(pins_config); + if (config_len >= MAX_PIN_CONFIG_LEN) + { + syslog(LOG_ERR, + "ERROR: Pin configuration too long (%zu bytes, max %d)\n", + config_len, MAX_PIN_CONFIG_LEN - 1); + return -EINVAL; + } + + /* Make a copy for parsing (strtok modifies the string) */ + + strncpy(pins_str, pins_config, sizeof(pins_str) - 1); + pins_str[sizeof(pins_str) - 1] = '\0'; + + /* Parse and validate each pin */ + + pin = strtok(pins_str, ", \t\n\r"); + while (pin != NULL && g_button_count < CONFIG_NUCLEO_H753ZI_BUTTON_COUNT) + { + /* Parse GPIO pin */ + + gpio_config = parse_gpio_pin(pin, &error); + if (error != 0) + { + syslog(LOG_ERR, "ERROR: Invalid GPIO pin: \"%s\"\n", pin); + syslog(LOG_ERR, + "Use format: PORT+PIN (e.g., \"PA0\", \"PF15\")\n"); + syslog(LOG_ERR, "Valid ports: PA-PH, Valid pins: 0-15\n"); + return -EINVAL; + } + + /* Check for duplicate pins */ + + for (i = 0; i < g_button_count; i++) + { + if (g_buttons[i] == gpio_config) + { + syslog(LOG_ERR, "ERROR: Duplicate GPIO pin: \"%s\"\n", pin); + syslog(LOG_ERR, + "This pin is already used by Button %d\n", i); + return -EINVAL; + } + } + + /* Check for EXTI line conflicts */ + + exti_line = get_exti_line(gpio_config); + if (exti_line < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to determine EXTI line for \"%s\"\n", + pin); + return -EINVAL; + } + + if (exti_usage[exti_line] >= 0) + { + /* EXTI conflict detected */ + + print_exti_conflict_error(exti_usage[exti_line], g_button_count, + pin, gpio_config, exti_line); + return -EINVAL; + } + + /* Register this EXTI line as used */ + + exti_usage[exti_line] = g_button_count; + + /* Add button */ + + g_buttons[g_button_count] = gpio_config; + g_button_count++; + + pin = strtok(NULL, ", \t\n\r"); + } + + /* Validate final count */ + + if (g_button_count != CONFIG_NUCLEO_H753ZI_BUTTON_COUNT) + { + syslog(LOG_ERR, "ERROR: Button count mismatch!\n"); + syslog(LOG_ERR, "Expected: %d, Got: %d\n", + CONFIG_NUCLEO_H753ZI_BUTTON_COUNT, g_button_count); + return -EINVAL; + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_button_initialize + * + * Description: + * board_button_initialize() must be called to initialize button + * resources. After that, board_buttons() may be called to collect the + * current state of all buttons or board_button_irq() may be called to + * register button interrupt handlers. + * + ****************************************************************************/ + +uint32_t board_button_initialize(void) +{ + int ret; + int i; + + ret = init_button_configs(); + if (ret < 0) + { + syslog(LOG_ERR, "\n"); + syslog(LOG_ERR, + "======================================================\n"); + syslog(LOG_ERR, " BUTTON CONFIGURATION FAILED\n"); + syslog(LOG_ERR, + "======================================================\n"); + syslog(LOG_ERR, "\n"); + syslog(LOG_ERR, "Please fix the errors above and rebuild.\n"); + syslog(LOG_ERR, "\n"); + return 0; /* Return 0 to indicate failure */ + } + + /* Configure GPIO pins */ + + for (i = 0; i < g_button_count; i++) + { + ret = stm32_configgpio(g_buttons[i]); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to configure GPIO for button %d " + "(ret=%d)\n", i, ret); + return 0; + } + } + + syslog(LOG_INFO, "Button driver initialized: %d buttons ready\n", + g_button_count); + + return g_button_count; +} + +/**************************************************************************** + * Name: board_buttons + * + * Description: + * board_buttons() may be called to collect the current state of all + * buttons. board_buttons() returns a 32-bit bit set with each bit + * associated with a button. See the BUTTON_*_BIT definitions in + * board.h for the meaning of each bit. + * + * Returned Value: + * 32-bit set of button states. Bit set = button pressed. + * + ****************************************************************************/ + +uint32_t board_buttons(void) +{ + uint32_t ret = 0; + bool pressed; + int i; + + /* Check the state of each button */ + + for (i = 0; i < g_button_count; i++) + { + /* With pull-down: HIGH = pressed, LOW = released */ + + pressed = stm32_gpioread(g_buttons[i]); + + /* Set bit if button is pressed */ + + if (pressed) + { + ret |= (1 << i); + } + } + + return ret; +} + +/**************************************************************************** + * Name: board_button_irq + * + * Description: + * board_button_irq() may be called to register an interrupt handler + * that will be called when a button is depressed or released. The ID + * value is a button enumeration value that uniquely identifies a button + * resource. See the BUTTON_* definitions in board.h for the meaning of + * enumeration value. + * + * Input Parameters: + * id - Button ID (0-based index) + * irqhandler - IRQ handler function + * arg - Argument passed to IRQ handler + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_IRQBUTTONS +int board_button_irq(int id, xcpt_t irqhandler, FAR void *arg) +{ + int ret = -EINVAL; + + /* Validate button ID */ + + if (id < 0 || id >= g_button_count) + { + syslog(LOG_ERR, "Invalid button ID %d (valid: 0-%d)\n", + id, g_button_count - 1); + return ret; + } + + /* Register interrupt for both rising and falling edges */ + + ret = stm32_gpiosetevent(g_buttons[id], true, true, true, + irqhandler, arg); + + if (ret < 0) + { + syslog(LOG_ERR, + "Failed to register IRQ for button %d (ret=%d)\n", + id, ret); + } + + return ret; +} +#endif + +#endif /* CONFIG_NUCLEO_H753ZI_BUTTON_SUPPORT */ diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_composite.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_composite.c new file mode 100644 index 0000000000000..5a888f732ebae --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_composite.c @@ -0,0 +1,349 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_composite.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "stm32_otg.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define COMPOSITE0_DEV (3) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static void *g_mschandle; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_mscclassobject + * + * Description: + * If the mass storage class driver is part of composite device, then + * its instantiation and configuration is a multi-step, board-specific, + * process (See comments for usbmsc_configure below). In this case, + * board-specific logic must provide board_mscclassobject(). + * + * board_mscclassobject() is called from the composite driver. It must + * encapsulate the instantiation and configuration of the mass storage + * class and the return the mass storage device's class driver instance + * to the composite driver. + * + * Input Parameters: + * classdev - The location to return the mass storage class' device + * instance. + * + * Returned Value: + * 0 on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static int board_mscclassobject(int minor, + struct usbdev_devinfo_s *devinfo, + struct usbdevclass_driver_s **classdev) +{ + int ret; + + DEBUGASSERT(g_mschandle == NULL); + + /* Configure the mass storage device */ + + uinfo("Configuring with NLUNS=1\n"); + ret = usbmsc_configure(1, &g_mschandle); + if (ret < 0) + { + uerr("ERROR: usbmsc_configure failed: %d\n", -ret); + return ret; + } + + uinfo("MSC handle=%p\n", g_mschandle); + + /* Bind the LUN(s) */ + + uinfo("Bind LUN=0 to /dev/mmcsd0\n"); + ret = usbmsc_bindlun(g_mschandle, "/dev/mmcsd0", 0, 0, 0, false); + if (ret < 0) + { + uerr("ERROR: usbmsc_bindlun failed for LUN 1 at /dev/mmcsd0: %d\n", + ret); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; + return ret; + } + + /* Get the mass storage device's class object */ + + ret = usbmsc_classobject(g_mschandle, devinfo, classdev); + if (ret < 0) + { + uerr("ERROR: usbmsc_classobject failed: %d\n", -ret); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: board_mscuninitialize + * + * Description: + * Un-initialize the USB storage class driver. + * This is just an application specific wrapper for usbmsc_unitialize() + * that is called form the composite device logic. + * + * Input Parameters: + * classdev - The class driver instance previously given to the composite + * driver by board_mscclassobject(). + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static void board_mscuninitialize(struct usbdevclass_driver_s *classdev) +{ + if (g_mschandle) + { + usbmsc_uninitialize(g_mschandle); + } + + g_mschandle = NULL; +} +#endif + +/**************************************************************************** + * Name: board_composite_connect + * + * Description: + * Connect the USB composite device on the specified USB device port for + * configuration 0. + * + * Input Parameters: + * port - The USB device port. + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +static void *board_composite0_connect(int port) +{ + struct composite_devdesc_s dev[COMPOSITE0_DEV]; + int ifnobase = 0; + int strbase = COMPOSITE_NSTRIDS; + int dev_idx = 0; + int epin = 1; + int epout = 1; + +#ifdef CONFIG_RNDIS_COMPOSITE + /* Configure the RNDIS USB device */ + + /* Ask the rndis driver to fill in the constants we didn't + * know here. + */ + + usbdev_rndis_get_composite_devdesc(&dev[dev_idx]); + + /* Interfaces */ + + dev[dev_idx].devinfo.ifnobase = ifnobase; + dev[dev_idx].minor = 0; + + /* Strings */ + + dev[dev_idx].devinfo.strbase = strbase; + + /* Endpoints */ + + dev[dev_idx].devinfo.epno[RNDIS_EP_INTIN_IDX] = epin++; + dev[dev_idx].devinfo.epno[RNDIS_EP_BULKIN_IDX] = epin++; + dev[dev_idx].devinfo.epno[RNDIS_EP_BULKOUT_IDX] = epout++; + + /* Count up the base numbers */ + + ifnobase += dev[dev_idx].devinfo.ninterfaces; + strbase += dev[dev_idx].devinfo.nstrings; + + dev_idx += 1; +#endif + +#ifdef CONFIG_CDCACM_COMPOSITE + /* Configure the CDC/ACM device */ + + /* Ask the cdcacm driver to fill in the constants we didn't + * know here. + */ + + cdcacm_get_composite_devdesc(&dev[dev_idx]); + + /* Overwrite and correct some values... */ + + /* The callback functions for the CDC/ACM class */ + + dev[dev_idx].classobject = cdcacm_classobject; + dev[dev_idx].uninitialize = cdcacm_uninitialize; + + /* Interfaces */ + + dev[dev_idx].devinfo.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[dev_idx].minor = 0; /* The minor interface number */ + + /* Strings */ + + dev[dev_idx].devinfo.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[dev_idx].devinfo.epno[CDCACM_EP_INTIN_IDX] = epin++; + dev[dev_idx].devinfo.epno[CDCACM_EP_BULKIN_IDX] = epin++; + dev[dev_idx].devinfo.epno[CDCACM_EP_BULKOUT_IDX] = epout++; + + /* Count up the base numbers */ + + ifnobase += dev[dev_idx].devinfo.ninterfaces; + strbase += dev[dev_idx].devinfo.nstrings; + + dev_idx += 1; +#endif + +#ifdef CONFIG_USBMSC_COMPOSITE + /* Configure the mass storage device device */ + + /* Ask the usbmsc driver to fill in the constants we didn't + * know here. + */ + + usbmsc_get_composite_devdesc(&dev[dev_idx]); + + /* Overwrite and correct some values... */ + + /* The callback functions for the USBMSC class */ + + dev[dev_idx].classobject = board_mscclassobject; + dev[dev_idx].uninitialize = board_mscuninitialize; + + /* Interfaces */ + + dev[dev_idx].devinfo.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[dev_idx].minor = 0; /* The minor interface number */ + + /* Strings */ + + dev[dev_idx].devinfo.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[dev_idx].devinfo.epno[USBMSC_EP_BULKIN_IDX] = epin++; + dev[dev_idx].devinfo.epno[USBMSC_EP_BULKOUT_IDX] = epout++; + + /* Count up the base numbers */ + + ifnobase += dev[dev_idx].devinfo.ninterfaces; + strbase += dev[dev_idx].devinfo.nstrings; + + dev_idx += 1; +#endif + + /* Sanity checks */ + + DEBUGASSERT(epin < STM32_NENDPOINTS); + DEBUGASSERT(epout < STM32_NENDPOINTS); + + return composite_initialize(composite_getdevdescs(), dev, dev_idx); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_composite_initialize + * + * Description: + * Perform architecture specific initialization of a composite USB device. + * + ****************************************************************************/ + +int board_composite_initialize(int port) +{ + return OK; +} + +/**************************************************************************** + * Name: board_composite_connect + * + * Description: + * Connect the USB composite device on the specified USB device port using + * the specified configuration. The interpretation of the configid is + * board specific. + * + * Input Parameters: + * port - The USB device port. + * configid - The USB composite configuration + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +void *board_composite_connect(int port, int configid) +{ + if (configid == 0) + { + return board_composite0_connect(port); + } + else + { + return NULL; + } +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_gpio.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_gpio.c new file mode 100644 index 0000000000000..4fe62b5ddce56 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_gpio.c @@ -0,0 +1,953 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_gpio.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "chip.h" +#include "stm32_gpio.h" +#include "nucleo-h753zi.h" + +#if defined(CONFIG_DEV_GPIO) && !defined(CONFIG_GPIO_LOWER_HALF) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* GPIO Driver Validation and Debug Macros */ + +#define STM32_GPIO_VALIDATE_DEVICE(dev) \ + do { \ + DEBUGASSERT((dev) != NULL); \ + } while (0) + +#define STM32_GPIO_VALIDATE_VALUE_PTR(value) \ + do { \ + DEBUGASSERT((value) != NULL); \ + } while (0) + +#define STM32_GPIO_VALIDATE_INDEX(id, max) \ + do { \ + DEBUGASSERT((id) < (max)); \ + } while (0) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Standard GPIO device structure + * + * This structure represents a basic GPIO pin device that can be used + * for either input or output operations. It contains the standard NuttX + * GPIO device structure plus an ID field to identify which specific + * GPIO pin this device represents in the board's GPIO arrays. + */ + +struct stm32gpio_dev_s +{ + struct gpio_dev_s gpio; /* Standard NuttX GPIO device structure */ + uint8_t id; /* Index into the GPIO configuration arrays */ +}; + +/* GPIO interrupt device structure + * + * This structure extends the basic GPIO device to add interrupt capability. + * It includes a callback function pointer that will be invoked when the + * GPIO interrupt is triggered. The structure embeds the basic GPIO device + * rather than inheriting from it to maintain compatibility with NuttX + * device management. + */ + +struct stm32gpint_dev_s +{ + struct stm32gpio_dev_s stm32gpio; /* Base GPIO device structure */ + pin_interrupt_t callback; /* User-provided interrupt callback */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* GPIO Input Operations */ + +static int stm32_gpin_read(struct gpio_dev_s *dev, bool *value); + +/* GPIO Output Operations */ + +static int stm32_gpout_read(struct gpio_dev_s *dev, bool *value); +static int stm32_gpout_write(struct gpio_dev_s *dev, bool value); + +/* GPIO Interrupt Operations */ + +static int stm32_gpint_read(struct gpio_dev_s *dev, bool *value); +static int stm32_gpint_attach(struct gpio_dev_s *dev, + pin_interrupt_t callback); +static int stm32_gpint_enable(struct gpio_dev_s *dev, bool enable); + +/* Interrupt Service Routine */ + +static int stm32_gpio_interrupt_handler(int irq, void *context, void *arg); + +/* Modular Initialization Functions */ + +static int stm32_gpio_init_input_pins(int *pincount); +static int stm32_gpio_init_output_pins(int *pincount); +static int stm32_gpio_init_interrupt_pins(int *pincount); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* GPIO Operations Tables + * + * These structures define the operations available for each type of GPIO. + * Each GPIO type (input, output, interrupt) has different capabilities: + * - Input: Only read operations + * - Output: Read and write operations + * - Interrupt: Read, attach callback, and enable/disable interrupt + */ + +static const struct gpio_operations_s g_gpin_ops = +{ + .go_read = stm32_gpin_read, + .go_write = NULL, /* Input pins cannot be written */ + .go_attach = NULL, /* Regular inputs don't support interrupts */ + .go_enable = NULL, +}; + +static const struct gpio_operations_s g_gpout_ops = +{ + .go_read = stm32_gpout_read, + .go_write = stm32_gpout_write, + .go_attach = NULL, /* Output pins don't support interrupts */ + .go_enable = NULL, +}; + +static const struct gpio_operations_s g_gpint_ops = +{ + .go_read = stm32_gpint_read, + .go_write = NULL, /* Interrupt pins are input-only */ + .go_attach = stm32_gpint_attach, + .go_enable = stm32_gpint_enable, +}; + +/* GPIO Pin Configuration Arrays and Device Instances + * + * These arrays map the logical GPIO numbers used by applications to the + * actual STM32 GPIO pin configurations. The configurations are defined + * in the board header file (nucleo-h753zi.h). + */ + +#if BOARD_NGPIOIN > 0 +static const uint32_t g_gpioinputs[BOARD_NGPIOIN] = +{ + GPIO_BTN_BUILT_IN, /* User button on PC13 - configured as input */ +}; + +static struct stm32gpio_dev_s g_gpin_devices[BOARD_NGPIOIN]; +#endif + +#if BOARD_NGPIOOUT > 0 +static const uint32_t g_gpiooutputs[BOARD_NGPIOOUT] = +{ + GPIO_LD1, /* Green LED on PB0 - configured as output */ + GPIO_LD2, /* Orange LED on PE1 - configured as output */ + GPIO_LD3, /* Red LED on PB14 - configured as output */ +}; + +static struct stm32gpio_dev_s g_gpout_devices[BOARD_NGPIOOUT]; +#endif + +#if BOARD_NGPIOINT > 0 +static const uint32_t g_gpiointinputs[BOARD_NGPIOINT] = +{ + GPIO_INT1, /* Custom interrupt pin - define in board header */ +}; + +static struct stm32gpint_dev_s g_gpint_devices[BOARD_NGPIOINT]; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_gpio_interrupt_handler + * + * Description: + * This is the common interrupt service routine for all GPIO interrupt + * pins. + * + * When a GPIO interrupt occurs, the STM32 interrupt controller will call + * this function with the appropriate arguments. This function then calls + * the user-provided callback function that was registered via the attach + * operation. + * + * The function performs minimal processing in interrupt context - it just + * validates the parameters and calls the user callback. All complex + * processing should be done in the callback function, preferably by + * posting to a work queue or semaphore. + * + * Input Parameters: + * irq -The interrupt request number (not used in this implementation) + * context -Saved processor context (not used in this implementation) + * arg -Pointer to the stm32gpint_dev_s structure for the triggering pin + * + * Returned Value: + * Always returns OK to indicate the interrupt was handled + * + * Assumptions: + * - Called in interrupt context, so keep processing minimal + * - The arg parameter points to a valid stm32gpint_dev_s structure + * - The callback function pointer is valid (checked by caller) + * + ****************************************************************************/ + +static int stm32_gpio_interrupt_handler(int irq, void *context, void *arg) +{ + struct stm32gpint_dev_s *stm32gpint = (struct stm32gpint_dev_s *)arg; + + DEBUGASSERT(stm32gpint != NULL && stm32gpint->callback != NULL); + + gpioinfo("GPIO interrupt %d triggered, calling callback %p\n", + stm32gpint->stm32gpio.id, stm32gpint->callback); + + /* Execute the user-registered callback function. + * The callback receives the GPIO device pointer and the pin ID. + */ + + stm32gpint->callback(&stm32gpint->stm32gpio.gpio, + stm32gpint->stm32gpio.id); + return OK; +} + +/**************************************************************************** + * Name: stm32_gpin_read + * + * Description: + * Read the current logical state of a GPIO input pin. + * + * This function reads the physical state of a GPIO pin configured as an + * input and returns the logical value (true for HIGH, false for LOW). + * The pin configuration (pull-up, pull-down, etc.) affects what voltage + * levels are interpreted as HIGH or LOW. + * + * For the Nucleo-H753ZI, this is typically used to read the user button + * state. The button is active-low (pressed = LOW voltage), but the + * logical interpretation depends on how the pin is configured in the + * board definitions. + * + * Input Parameters: + * dev - Pointer to the GPIO device structure + * value - Pointer to store the read value (true = HIGH, false = LOW) + * + * Returned Value: + * OK on success; a negated errno value on failure + * + * Assumptions: + * - The GPIO pin was previously configured as an input + * - The device structure is valid and properly initialized + * - The pin ID is within the valid range for input pins + * + ****************************************************************************/ + +static int stm32_gpin_read(struct gpio_dev_s *dev, bool *value) +{ + struct stm32gpio_dev_s *stm32gpio = (struct stm32gpio_dev_s *)dev; + + /* Validate all input parameters */ + + STM32_GPIO_VALIDATE_DEVICE(stm32gpio); + STM32_GPIO_VALIDATE_VALUE_PTR(value); + STM32_GPIO_VALIDATE_INDEX(stm32gpio->id, BOARD_NGPIOIN); + + gpioinfo("Reading GPIO input pin %d\n", stm32gpio->id); + + /* Read the current state of the input pin */ + + *value = stm32_gpioread(g_gpioinputs[stm32gpio->id]); + + gpioinfo("GPIO input %d state: %s\n", + stm32gpio->id, *value ? "HIGH" : "LOW"); + + return OK; +} + +/**************************************************************************** + * Name: stm32_gpout_read + * + * Description: + * Read the current logical state of a GPIO output pin. + * + * This function reads back the current state that was written to an output + * pin. This is useful for applications that need to know the current state + * of an output (for example, to toggle a LED state). The function reads + * the actual pin state, not just the last written value, so it reflects + * the real electrical state of the pin. + * + * For the Nucleo-H753ZI LEDs, this allows applications to check if a LED + * is currently on or off before deciding whether to toggle it. + * + * Input Parameters: + * dev - Pointer to the GPIO device structure + * value - Pointer to store the read value (true = HIGH, false = LOW) + * + * Returned Value: + * OK on success; a negated errno value on failure + * + * Assumptions: + * - The GPIO pin was previously configured as an output + * - The device structure is valid and properly initialized + * - The pin ID is within the valid range for output pins + * + ****************************************************************************/ + +static int stm32_gpout_read(struct gpio_dev_s *dev, bool *value) +{ + struct stm32gpio_dev_s *stm32gpio = (struct stm32gpio_dev_s *)dev; + + /* Validate all input parameters */ + + STM32_GPIO_VALIDATE_DEVICE(stm32gpio); + STM32_GPIO_VALIDATE_VALUE_PTR(value); + STM32_GPIO_VALIDATE_INDEX(stm32gpio->id, BOARD_NGPIOOUT); + + gpioinfo("Reading GPIO output pin %d current state\n", stm32gpio->id); + + /* Read the current output state of the pin */ + + *value = stm32_gpioread(g_gpiooutputs[stm32gpio->id]); + + gpioinfo("GPIO output %d current state: %s\n", + stm32gpio->id, *value ? "HIGH" : "LOW"); + + return OK; +} + +/**************************************************************************** + * Name: stm32_gpout_write + * + * Description: + * Write a logical value to a GPIO output pin. + * + * This is the core function that allows applications to control GPIO + * output pins. It sets the electrical state of the pin to either HIGH + * (3.3V) or LOW (0V) based on the boolean value provided. + * + * For the Nucleo-H753ZI LEDs: + * - Writing true (HIGH) will turn ON the LED (LED is active-high) + * - Writing false (LOW) will turn OFF the LED + * + * The function provides debug output to help with troubleshooting GPIO + * operations during development. In production builds with debug disabled, + * this overhead is eliminated by the compiler. + * + * This function is called by the NuttX GPIO framework when user + * applications perform write operations via ioctl(GPIOC_WRITE) + * or gpio_write() calls. + * + * Input Parameters: + * dev - Pointer to the GPIO device structure + * value - Value to write (true = HIGH/3.3V, false = LOW/0V) + * + * Returned Value: + * OK on success; a negated errno value on failure + * + * Assumptions: + * - The GPIO pin was previously configured as an output + * - The device structure is valid and properly initialized + * - The pin ID is within the valid range for output pins + * - The pin is not being used by another driver or function + * + ****************************************************************************/ + +static int stm32_gpout_write(struct gpio_dev_s *dev, bool value) +{ + struct stm32gpio_dev_s *stm32gpio = (struct stm32gpio_dev_s *)dev; + + /* Validate input parameters */ + + STM32_GPIO_VALIDATE_DEVICE(stm32gpio); + STM32_GPIO_VALIDATE_INDEX(stm32gpio->id, BOARD_NGPIOOUT); + + gpioinfo("Writing GPIO output pin %d: %s\n", + stm32gpio->id, value ? "HIGH" : "LOW"); + + /* Write the new state to the GPIO pin. + * This calls the STM32-specific GPIO write function which handles + * the low-level register manipulation to set the pin state. + */ + + stm32_gpiowrite(g_gpiooutputs[stm32gpio->id], value); + + gpioinfo("GPIO output %d write completed successfully\n", stm32gpio->id); + + return OK; +} + +/**************************************************************************** + * Name: stm32_gpint_read + * + * Description: + * Read the current logical state of a GPIO interrupt pin. + * + * This function allows reading the current state of a pin that is + * configured for interrupt generation. Even though the pin is primarily + * used for interrupts, it can still be read synchronously to check its + * current state. This is useful for: + * + * - Polling the pin state when interrupts are disabled + * - Checking initial pin state during initialization + * - Debouncing in software by reading multiple times + * - Diagnostics and debugging + * + * Note that this reads the actual pin electrical state, which may be + * different from the last interrupt trigger if the pin has changed + * since the interrupt occurred. + * + * Input Parameters: + * dev - Pointer to the GPIO device structure + * value - Pointer to store the read value (true = HIGH, false = LOW) + * + * Returned Value: + * OK on success; a negated errno value on failure + * + * Assumptions: + * - The GPIO pin was previously configured for interrupt input + * - The device structure is valid and properly initialized + * - The pin ID is within the valid range for interrupt pins + * + ****************************************************************************/ + +static int stm32_gpint_read(struct gpio_dev_s *dev, bool *value) +{ + struct stm32gpint_dev_s *stm32gpint = (struct stm32gpint_dev_s *)dev; + + /* Validate all input parameters */ + + STM32_GPIO_VALIDATE_DEVICE(stm32gpint); + STM32_GPIO_VALIDATE_VALUE_PTR(value); + STM32_GPIO_VALIDATE_INDEX(stm32gpint->stm32gpio.id, BOARD_NGPIOINT); + + gpioinfo("Reading GPIO interrupt pin %d current state\n", + stm32gpint->stm32gpio.id); + + /* Read the current state of the interrupt pin */ + + *value = stm32_gpioread(g_gpiointinputs[stm32gpint->stm32gpio.id]); + + gpioinfo("GPIO interrupt pin %d current state: %s\n", + stm32gpint->stm32gpio.id, *value ? "HIGH" : "LOW"); + + return OK; +} + +/**************************************************************************** + * Name: stm32_gpint_attach + * + * Description: + * Attach a callback function to a GPIO interrupt pin. + * + * This function registers a user-provided callback function that will be + * executed when the GPIO interrupt is triggered. The callback is stored + * in the device structure and will be called by the interrupt handler. + * + * Key behaviors: + * - Any existing interrupt is automatically disabled during attachment + * - The callback can be changed by calling attach again with a new + * function. + * + * - Setting callback to NULL effectively detaches the interrupt + * - The interrupt must be explicitly enabled after attachment using + * the enable operation + * + * The callback function will be called in interrupt context, so it should: + * - Be as fast as possible + * - Not call blocking functions + * - Consider posting to work queues for complex processing + * - Be reentrant if the same callback is used for multiple pins + * + * Input Parameters: + * dev - Pointer to the GPIO device structure + * callback - Function to call when interrupt occurs + * (can be NULL to detach) + * + * Returned Value: + * OK on success; a negated errno value on failure + * + * Assumptions: + * - The GPIO pin was previously configured for interrupt input + * - The device structure is valid and properly initialized + * - The callback function (if not NULL) is valid and reentrant + * + ****************************************************************************/ + +static int stm32_gpint_attach(struct gpio_dev_s *dev, + pin_interrupt_t callback) +{ + struct stm32gpint_dev_s *stm32gpint = (struct stm32gpint_dev_s *)dev; + + STM32_GPIO_VALIDATE_DEVICE(stm32gpint); + + gpioinfo("Attaching callback %p to GPIO interrupt pin %d\n", + callback, stm32gpint->stm32gpio.id); + + /* Disable any existing interrupt configuration before changing callback. + * This ensures we don't get spurious interrupts during the transition. + */ + + stm32_gpiosetevent(g_gpiointinputs[stm32gpint->stm32gpio.id], + false, false, false, NULL, NULL); + + /* Store the new callback function */ + + stm32gpint->callback = callback; + + if (callback != NULL) + { + gpioinfo("Callback attached successfully to GPIO interrupt %d\n", + stm32gpint->stm32gpio.id); + } + else + { + gpioinfo("Callback detached from GPIO interrupt %d\n", + stm32gpint->stm32gpio.id); + } + + return OK; +} + +/**************************************************************************** + * Name: stm32_gpint_enable + * + * Description: + * Enable or disable GPIO interrupt generation. + * + * This function controls whether the GPIO pin will actually generate + * interrupts when the configured event occurs. The pin must have a + * callback attached before enabling interrupts. + * + * When enabling: + * - Configures the pin for rising edge detection (button release) + * - Registers the interrupt handler with the STM32 interrupt controller + * - The interrupt will fire when the pin transitions from LOW to HIGH + * + * When disabling: + * - Removes interrupt configuration from the pin + * - No interrupts will be generated until re-enabled + * - The callback remains attached and can be re-enabled later + * + * For the Nucleo board button (if used as interrupt): + * - Button is typically active-low (pressed = LOW) + * - Rising edge = button release + * - Falling edge = button press + * - Configure based on desired behavior + * + * Input Parameters: + * dev - Pointer to the GPIO device structure + * enable - true to enable interrupts, false to disable + * + * Returned Value: + * OK on success; -EINVAL if no callback is attached when enabling + * + * Assumptions: + * - The GPIO pin was previously configured for interrupt input + * - For enable=true: a valid callback must be attached first + * - The device structure is valid and properly initialized + * + ****************************************************************************/ + +static int stm32_gpint_enable(struct gpio_dev_s *dev, bool enable) +{ + struct stm32gpint_dev_s *stm32gpint = (struct stm32gpint_dev_s *)dev; + + STM32_GPIO_VALIDATE_DEVICE(stm32gpint); + + if (enable) + { + /* Cannot enable interrupt without a callback function */ + + if (stm32gpint->callback == NULL) + { + gpioerr("ERROR: Cannot enable GPIO interrupt %d \n", + stm32gpint->stm32gpio.id); + return -EINVAL; + } + + gpioinfo("Enabling GPIO interrupt %d with rising edge detection\n", + stm32gpint->stm32gpio.id); + + /* Configure the interrupt for rising edge detection. + * Parameters: pin, rising, falling, filter, handler, arg + * - rising=true: interrupt on LOW->HIGH transition + * - falling=false: no interrupt on HIGH->LOW transition + * - filter=false: no input filtering + */ + + stm32_gpiosetevent(g_gpiointinputs[stm32gpint->stm32gpio.id], + true, false, false, + stm32_gpio_interrupt_handler, + &g_gpint_devices[stm32gpint->stm32gpio.id]); + + gpioinfo("GPIO interrupt %d enabled successfully\n", + stm32gpint->stm32gpio.id); + } + else + { + gpioinfo("Disabling GPIO interrupt %d\n", stm32gpint->stm32gpio.id); + + /* Disable the interrupt by clearing all event configuration */ + + stm32_gpiosetevent(g_gpiointinputs[stm32gpint->stm32gpio.id], + false, false, false, NULL, NULL); + + gpioinfo("GPIO interrupt %d disabled successfully\n", + stm32gpint->stm32gpio.id); + } + + return OK; +} + +/**************************************************************************** + * Name: stm32_gpio_init_input_pins + * + * Description: + * Initialize all GPIO input pins defined for this board. + * + * This function sets up each input pin by: + * 1. Initializing the device structure with proper type and operations + * 2. Registering the pin with the NuttX GPIO framework + * 3. Configuring the physical STM32 GPIO hardware + * + * After this initialization, applications can access the input pins + * via the /dev/gpio device interface using standard read operations. + * + * For Nucleo-H753ZI, this typically configures the user button (PC13) + * as a readable input that applications can poll. + * + * Input Parameters: + * pincount - Pointer to current pin count (updated by this function) + * + * Returned Value: + * Number of input pins initialized + * + * Side Effects: + * - Updates the pincount parameter with number of pins registered + * - Configures STM32 GPIO hardware registers + * - Registers devices with NuttX GPIO framework + * + ****************************************************************************/ + +static int stm32_gpio_init_input_pins(int *pincount) +{ +#if BOARD_NGPIOIN > 0 + int i; + int pins_initialized = 0; + + gpioinfo("Initializing %d GPIO input pins\n", BOARD_NGPIOIN); + + for (i = 0; i < BOARD_NGPIOIN; i++) + { + /* Initialize the GPIO device structure */ + + g_gpin_devices[i].gpio.gp_pintype = GPIO_INPUT_PIN; + g_gpin_devices[i].gpio.gp_ops = &g_gpin_ops; + g_gpin_devices[i].id = i; + + /* Register the GPIO pin with the NuttX GPIO framework */ + + gpio_pin_register(&g_gpin_devices[i].gpio, (*pincount)++); + + /* Configure the physical STM32 GPIO pin hardware */ + + stm32_configgpio(g_gpioinputs[i]); + + pins_initialized++; + + gpioinfo("GPIO input %d: configured and registered as /dev/gpio%d\n", + i, (*pincount) - 1); + } + + gpioinfo("GPIO input initialization completed: %d pins\n", + pins_initialized); + return pins_initialized; +#else + gpioinfo("No GPIO input pins configured for this board\n"); + return 0; +#endif +} + +/**************************************************************************** + * Name: stm32_gpio_init_output_pins + * + * Description: + * Initialize all GPIO output pins defined for this board. + * + * This function sets up each output pin by: + * 1. Initializing the device structure with output type and operations + * 2. Registering the pin with the NuttX GPIO framework + * 3. Setting initial state to LOW (off) for safety + * 4. Configuring the physical STM32 GPIO hardware + * + * The initial LOW state ensures that LEDs start in the OFF state and + * other outputs start in a safe condition. Applications can then control + * the outputs via write operations. + * + * For Nucleo-H753ZI, this configures the three onboard LEDs: + * - LD1 (Green LED on PB0) + * - LD2 (Orange LED on PE1) + * - LD3 (Red LED on PB14) + * + * After initialization, applications can control these LEDs via + * /dev/gpio device interface using ioctl(GPIOC_WRITE) calls. + * + * Input Parameters: + * pincount - Pointer to current pin count (updated by this function) + * + * Returned Value: + * Number of output pins initialized + * + * Side Effects: + * - Updates the pincount parameter with number of pins registered + * - Sets all output pins to LOW state initially + * - Configures STM32 GPIO hardware registers + * - Registers devices with NuttX GPIO framework + * + ****************************************************************************/ + +static int stm32_gpio_init_output_pins(int *pincount) +{ +#if BOARD_NGPIOOUT > 0 + int i; + int pins_initialized = 0; + + gpioinfo("Initializing %d GPIO output pins\n", BOARD_NGPIOOUT); + + for (i = 0; i < BOARD_NGPIOOUT; i++) + { + /* Initialize the GPIO device structure */ + + g_gpout_devices[i].gpio.gp_pintype = GPIO_OUTPUT_PIN; + g_gpout_devices[i].gpio.gp_ops = &g_gpout_ops; + g_gpout_devices[i].id = i; + + /* Register the GPIO pin with the NuttX GPIO framework */ + + gpio_pin_register(&g_gpout_devices[i].gpio, (*pincount)++); + + /* Initialize output to LOW for safety, then configure hardware. + * This ensures LEDs start OFF and other outputs start in safe state. + */ + + stm32_gpiowrite(g_gpiooutputs[i], false); + stm32_configgpio(g_gpiooutputs[i]); + + pins_initialized++; + + gpioinfo("GPIO output %d: configured as LOW at /dev/gpio%d\n", + i, (*pincount) - 1); + } + + gpioinfo("GPIO output initialization completed: %d pins\n", + pins_initialized); + + return pins_initialized; +#else + gpioinfo("No GPIO output pins configured for this board\n"); + return 0; +#endif +} + +/**************************************************************************** + * Name: stm32_gpio_init_interrupt_pins + * + * Description: + * Initialize all GPIO interrupt pins defined for this board. + * + * This function sets up each interrupt-capable pin by: + * 1. Initializing the extended device structure with interrupt capability + * 2. Registering the pin with the NuttX GPIO framework + * 3. Configuring the physical STM32 GPIO hardware for input + * 4. Setting up initial state (callback = NULL, interrupt disabled) + * + * Unlike simple input pins, interrupt pins require additional setup + * to support asynchronous event notification. The pin starts in a safe + * state with no callback attached and interrupts disabled. Applications + * must explicitly attach a callback and enable interrupts to receive + * asynchronous notifications. + * + * The interrupt pins can also be read synchronously like regular inputs, + * providing flexibility in how applications interact with them. + * + * Important: The actual interrupt configuration (edge detection, etc.) + * is done later when the interrupt is enabled, not during initialization. + * + * Input Parameters: + * pincount - Pointer to current pin count (updated by this function) + * + * Returned Value: + * Number of interrupt pins initialized + * + * Side Effects: + * - Updates the pincount parameter with number of pins registered + * - Configures STM32 GPIO hardware registers for input mode + * - Registers devices with NuttX GPIO framework + * - Initializes callback pointers to NULL for safety + * + ****************************************************************************/ + +static int stm32_gpio_init_interrupt_pins(int *pincount) +{ +#if BOARD_NGPIOINT > 0 + int i; + int pins_initialized = 0; + + gpioinfo("Initializing %d GPIO interrupt pins\n", BOARD_NGPIOINT); + + for (i = 0; i < BOARD_NGPIOINT; i++) + { + /* Initialize the GPIO interrupt device structure */ + + g_gpint_devices[i].stm32gpio.gpio.gp_pintype = GPIO_INTERRUPT_PIN; + g_gpint_devices[i].stm32gpio.gpio.gp_ops = &g_gpint_ops; + g_gpint_devices[i].stm32gpio.id = i; + + /* Safe initial state */ + + g_gpint_devices[i].callback = NULL; + + /* Register the GPIO pin with the NuttX GPIO framework */ + + gpio_pin_register(&g_gpint_devices[i].stm32gpio.gpio, (*pincount)++); + + /* Configure the physical STM32 GPIO pin for input. + * Interrupt configuration will be done later when enabled. + */ + + stm32_configgpio(g_gpiointinputs[i]); + + pins_initialized++; + + gpioinfo("GPIO interrupt %d: registered as /dev/gpio%d\n", + i, (*pincount) - 1); + } + + gpioinfo("GPIO interrupt initialization completed: %d pins\n", + pins_initialized); + + return pins_initialized; +#else + gpioinfo("No GPIO interrupt pins configured for this board\n"); + return 0; +#endif +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_gpio_initialize + * + * Description: + * Initialize the GPIO driver for the STM32H7 Nucleo board. + * + * This is the main initialization function that sets up all GPIO pins + * defined for the board. It coordinates the initialization of different + * types of GPIO pins (inputs, outputs, interrupts) and registers them + * with the NuttX GPIO framework. + * + * The function creates device nodes under /dev/gpio* that applications + * can use to interact with the GPIO pins. The numbering is sequential + * across all pin types (inputs first, then outputs, then interrupts). + * + * For the Nucleo-H753ZI board, this typically results in: + * - /dev/gpio0 : User button (input) + * - /dev/gpio1 : LD1 Green LED (output) + * - /dev/gpio2 : LD2 Orange LED (output) + * - /dev/gpio3 : LD3 Red LED (output) + * - /dev/gpio4 : Custom interrupt pin (interrupt) + * + * Applications can then use standard file operations: + * - open("/dev/gpio1", O_RDWR) + * - ioctl(fd, GPIOC_WRITE, 1) // Turn on LED + * - ioctl(fd, GPIOC_READ, &value) // Read current state + * - close(fd) + * + * This function is typically called during board initialization, before + * applications start running. + * + * Input Parameters: + * None + * + * Returned Value: + * OK on success; a negated errno value on failure + * + * Side Effects: + * - Configures STM32 GPIO hardware for all defined pins + * - Creates device nodes in /dev filesystem + * - Initializes all GPIO device structures + * - May enable GPIO peripheral clocks (handled by lower-level functions) + * + * Notes: + * - This function is only compiled if CONFIG_DEV_GPIO is enabled + * - Requires board-specific GPIO definitions in the board header file + * - Safe to call multiple times (GPIO framework handles re-registration) + * + ****************************************************************************/ + +int stm32_gpio_initialize(void) +{ + int total_pins = 0; + int pincount = 0; + + gpioinfo("Starting STM32H7 GPIO driver initialization\n"); + + /* Initialize each type of GPIO pin in logical order */ + + total_pins += stm32_gpio_init_input_pins(&pincount); + total_pins += stm32_gpio_init_output_pins(&pincount); + total_pins += stm32_gpio_init_interrupt_pins(&pincount); + + gpioinfo("STM32H7 GPIO driver initialization completed successfully\n"); + gpioinfo("Total GPIO pins initialized: %d\n", total_pins); + gpioinfo("GPIO devices available: /dev/gpio0 through /dev/gpio%d\n", + pincount - 1); + + return OK; +} + +#endif /* CONFIG_DEV_GPIO && !CONFIG_GPIO_LOWER_HALF */ diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_i2c.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_i2c.c new file mode 100644 index 0000000000000..73249ecbfe777 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_i2c.c @@ -0,0 +1,646 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_i2c.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "stm32_i2c.h" +#include +#include + +#include "nucleo-h753zi.h" + +#ifdef CONFIG_STM32H7_I2C + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MAX_I2C_DEVICES_PER_BUS 16 +#define INVALID_I2C_ADDR 0xff + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* I2C device registration structure */ + +struct i2c_device_s +{ + uint8_t addr; /* I2C slave address (7-bit) */ + uint32_t frequency; /* Bus frequency for this device */ + char name[16]; /* Device instance name (for logging) */ + bool in_use; /* true = slot occupied */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* I2C master interfaces (cached after initialization) */ + +#ifdef CONFIG_STM32H7_I2C1 +static struct i2c_master_s *g_i2c1_master = NULL; +static struct i2c_device_s g_i2c1_devices[MAX_I2C_DEVICES_PER_BUS]; +#endif + +#ifdef CONFIG_STM32H7_I2C2 +static struct i2c_master_s *g_i2c2_master = NULL; +static struct i2c_device_s g_i2c2_devices[MAX_I2C_DEVICES_PER_BUS]; +#endif + +#ifdef CONFIG_STM32H7_I2C3 +static struct i2c_master_s *g_i2c3_master = NULL; +static struct i2c_device_s g_i2c3_devices[MAX_I2C_DEVICES_PER_BUS]; +#endif + +#ifdef CONFIG_STM32H7_I2C4 +static struct i2c_master_s *g_i2c4_master = NULL; +static struct i2c_device_s g_i2c4_devices[MAX_I2C_DEVICES_PER_BUS]; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: get_i2c_master_ptr + * + * Description: + * Get pointer to I2C master interface storage for a specific bus. + * + * Input Parameters: + * i2c_bus - I2C bus number (1-4) + * + * Returned Value: + * Pointer to I2C master pointer storage, NULL if invalid bus + * + ****************************************************************************/ + +static struct i2c_master_s **get_i2c_master_ptr(int i2c_bus) +{ + switch (i2c_bus) + { +#ifdef CONFIG_STM32H7_I2C1 + case 1: + return &g_i2c1_master; +#endif +#ifdef CONFIG_STM32H7_I2C2 + case 2: + return &g_i2c2_master; +#endif +#ifdef CONFIG_STM32H7_I2C3 + case 3: + return &g_i2c3_master; +#endif +#ifdef CONFIG_STM32H7_I2C4 + case 4: + return &g_i2c4_master; +#endif + default: + return NULL; + } +} + +/**************************************************************************** + * Name: get_i2c_devices_array + * + * Description: + * Get I2C devices array for a specific bus. + * + * Input Parameters: + * i2c_bus - I2C bus number (1-4) + * + * Returned Value: + * Pointer to I2C devices array, NULL if invalid bus + * + ****************************************************************************/ + +static struct i2c_device_s *get_i2c_devices_array(int i2c_bus) +{ + switch (i2c_bus) + { +#ifdef CONFIG_STM32H7_I2C1 + case 1: + return g_i2c1_devices; +#endif +#ifdef CONFIG_STM32H7_I2C2 + case 2: + return g_i2c2_devices; +#endif +#ifdef CONFIG_STM32H7_I2C3 + case 3: + return g_i2c3_devices; +#endif +#ifdef CONFIG_STM32H7_I2C4 + case 4: + return g_i2c4_devices; +#endif + default: + return NULL; + } +} + +/**************************************************************************** + * Name: validate_i2c_addr + * + * Description: + * Validate I2C 7-bit address. + * Reserved addresses: 0x00-0x07, 0x78-0x7F + * + * Input Parameters: + * addr - I2C address to validate + * + * Returned Value: + * true if valid, false if reserved or out of range + * + ****************************************************************************/ + +static bool validate_i2c_addr(uint8_t addr) +{ + /* I2C 7-bit addressing: + * 0x00-0x07: Reserved addresses + * 0x08-0x77: Valid addresses + * 0x78-0x7F: Reserved addresses + */ + + if (addr < 0x08 || addr > 0x77) + { + return false; + } + + return true; +} + +/**************************************************************************** + * Name: find_device_slot + * + * Description: + * Find a free slot in the I2C devices array. + * + * Input Parameters: + * devices - Pointer to I2C devices array + * + * Returned Value: + * Index of free slot, -ENOMEM if no slots available + * + ****************************************************************************/ + +static int find_device_slot(struct i2c_device_s *devices) +{ + int i; + + for (i = 0; i < MAX_I2C_DEVICES_PER_BUS; i++) + { + if (!devices[i].in_use) + { + return i; + } + } + + return -ENOMEM; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_i2c_initialize + * + * Description: + * Initialize I2C buses based on Kconfig configuration. + * Pins are selected via board.h pinset configuration. + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_i2c_initialize(void) +{ + syslog(LOG_INFO, "Initializing I2C interfaces\n"); + +#ifdef CONFIG_NUCLEO_H753ZI_I2C1_ENABLE + g_i2c1_master = stm32_i2cbus_initialize(1); + if (!g_i2c1_master) + { + syslog(LOG_ERR, "ERROR: Failed to initialize I2C1\n"); + return -ENODEV; + } + + memset(g_i2c1_devices, 0, sizeof(g_i2c1_devices)); + syslog(LOG_INFO, "I2C1 initialized successfully\n"); +#endif + +#ifdef CONFIG_NUCLEO_H753ZI_I2C2_ENABLE + g_i2c2_master = stm32_i2cbus_initialize(2); + if (!g_i2c2_master) + { + syslog(LOG_ERR, "ERROR: Failed to initialize I2C2\n"); + return -ENODEV; + } + + memset(g_i2c2_devices, 0, sizeof(g_i2c2_devices)); + syslog(LOG_INFO, "I2C2 initialized successfully\n"); +#endif + +#ifdef CONFIG_NUCLEO_H753ZI_I2C3_ENABLE + g_i2c3_master = stm32_i2cbus_initialize(3); + if (!g_i2c3_master) + { + syslog(LOG_ERR, "ERROR: Failed to initialize I2C3\n"); + return -ENODEV; + } + + memset(g_i2c3_devices, 0, sizeof(g_i2c3_devices)); + syslog(LOG_INFO, "I2C3 initialized successfully\n"); +#endif + +#ifdef CONFIG_NUCLEO_H753ZI_I2C4_ENABLE + g_i2c4_master = stm32_i2cbus_initialize(4); + if (!g_i2c4_master) + { + syslog(LOG_ERR, "ERROR: Failed to initialize I2C4\n"); + return -ENODEV; + } + + memset(g_i2c4_devices, 0, sizeof(g_i2c4_devices)); + syslog(LOG_INFO, "I2C4 initialized successfully\n"); +#endif + + syslog(LOG_INFO, "I2C initialization completed\n"); + return OK; +} + +/**************************************************************************** + * Name: stm32_i2c_register_device + * + * Description: + * Register an I2C device with specific address, frequency, and name. + * This function tracks device configurations for debugging and + * provides validation. + * + * Input Parameters: + * i2c_bus - I2C bus number (1-4) + * addr - I2C slave address (7-bit, 0x08-0x77) + * frequency - Bus frequency for this device (Hz) + * name - Descriptive name for logging (can be NULL) + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_i2c_register_device(int i2c_bus, uint8_t addr, + uint32_t frequency, const char *name) +{ + struct i2c_device_s *devices; + struct i2c_device_s *device; + int slot; + int i; + + /* Validate bus */ + + devices = get_i2c_devices_array(i2c_bus); + if (!devices) + { + syslog(LOG_ERR, "ERROR: Invalid I2C bus %d\n", i2c_bus); + return -EINVAL; + } + + /* Validate address */ + + if (!validate_i2c_addr(addr)) + { + syslog(LOG_ERR, + "ERROR: Invalid I2C address 0x%02x " + "(reserved or out of range)\n", addr); + syslog(LOG_ERR, " Valid range: 0x08-0x77\n"); + return -EINVAL; + } + + /* Check for duplicate address */ + + for (i = 0; i < MAX_I2C_DEVICES_PER_BUS; i++) + { + if (devices[i].in_use && devices[i].addr == addr) + { + syslog(LOG_WARNING, + "WARNING: Address 0x%02x already registered on I2C%d " + "as '%s'\n", addr, i2c_bus, devices[i].name); + syslog(LOG_WARNING, + " Allowing duplicate (multi-function device?)\n"); + + /* Continue anyway - might be multi-function device like LSM303 */ + } + } + + /* Find free slot */ + + slot = find_device_slot(devices); + if (slot < 0) + { + syslog(LOG_ERR, + "ERROR: No free slots for I2C%d devices " + "(max %d devices per bus)\n", + i2c_bus, MAX_I2C_DEVICES_PER_BUS); + return -ENOMEM; + } + + /* Register device */ + + device = &devices[slot]; + device->addr = addr; + device->frequency = frequency; + device->in_use = true; + + if (name != NULL) + { + strncpy(device->name, name, sizeof(device->name) - 1); + device->name[sizeof(device->name) - 1] = '\0'; + } + else + { + snprintf(device->name, sizeof(device->name), "dev_0x%02x", addr); + } + + syslog(LOG_INFO, "Registered I2C%d device [%d]: '%s' @ 0x%02x, %lu Hz\n", + i2c_bus, slot, device->name, addr, (unsigned long)frequency); + + return OK; +} + +/**************************************************************************** + * Name: stm32_i2c_unregister_device + * + * Description: + * Unregister an I2C device by address. + * + * Input Parameters: + * i2c_bus - I2C bus number (1-4) + * addr - I2C slave address to unregister + * + * Returned Value: + * OK on success, -ENOENT if not found, other negative errno on error + * + ****************************************************************************/ + +int stm32_i2c_unregister_device(int i2c_bus, uint8_t addr) +{ + struct i2c_device_s *devices; + int i; + + devices = get_i2c_devices_array(i2c_bus); + if (!devices) + { + return -EINVAL; + } + + /* Find and remove device */ + + for (i = 0; i < MAX_I2C_DEVICES_PER_BUS; i++) + { + if (devices[i].in_use && devices[i].addr == addr) + { + syslog(LOG_INFO, + "Unregistered I2C%d device [%d]: '%s' @ 0x%02x\n", + i2c_bus, i, devices[i].name, addr); + + memset(&devices[i], 0, sizeof(struct i2c_device_s)); + return OK; + } + } + + syslog(LOG_WARNING, "WARNING: Device 0x%02x not found on I2C%d\n", + addr, i2c_bus); + return -ENOENT; +} + +/**************************************************************************** + * Name: stm32_i2c_get_master + * + * Description: + * Get I2C master interface for a specific bus. + * This is the main function used by sensor drivers to get the I2C + * interface they need. + * + * Input Parameters: + * i2c_bus - I2C bus number (1-4) + * + * Returned Value: + * Pointer to I2C master interface, NULL if invalid bus or not initialized + * + ****************************************************************************/ + +struct i2c_master_s *stm32_i2c_get_master(int i2c_bus) +{ + struct i2c_master_s **master_ptr; + + master_ptr = get_i2c_master_ptr(i2c_bus); + if (!master_ptr) + { + syslog(LOG_ERR, "ERROR: Invalid I2C bus %d\n", i2c_bus); + return NULL; + } + + if (!(*master_ptr)) + { + syslog(LOG_ERR, "ERROR: I2C%d not initialized\n", i2c_bus); + return NULL; + } + + return *master_ptr; +} + +/**************************************************************************** + * Name: stm32_i2c_scan_bus + * + * Description: + * Scan an I2C bus for connected devices. + * Useful for debugging and hardware validation. + * + * Input Parameters: + * i2c_bus - I2C bus number (1-4) + * + * Returned Value: + * Number of devices found, negative errno on error + * + ****************************************************************************/ + +#ifdef CONFIG_I2C_RESET +int stm32_i2c_scan_bus(int i2c_bus) +{ + struct i2c_master_s *i2c; + struct i2c_msg_s msg; + uint8_t buffer[1]; + uint8_t addr; + int found = 0; + int ret; + + i2c = stm32_i2c_get_master(i2c_bus); + if (!i2c) + { + return -ENODEV; + } + + syslog(LOG_INFO, "Scanning I2C%d bus (addresses 0x08-0x77)...\n", + i2c_bus); + syslog(LOG_INFO, + " 0 1 2 3 4 5 6 7 8 9 A B C D E F\n"); + + for (addr = 0x00; addr <= 0x7f; addr++) + { + if ((addr & 0x0f) == 0) + { + syslog(LOG_INFO, "%02x: ", addr); + } + + /* Skip reserved addresses */ + + if (addr < 0x08 || addr > 0x77) + { + syslog(LOG_INFO, " "); + } + else + { + /* Try to communicate with device */ + + msg.frequency = 100000; /* 100 kHz for scanning */ + msg.addr = addr; + msg.flags = 0; + msg.buffer = buffer; + msg.length = 0; + + ret = I2C_TRANSFER(i2c, &msg, 1); + if (ret == OK) + { + syslog(LOG_INFO, "%02x ", addr); + found++; + } + else + { + syslog(LOG_INFO, "-- "); + } + } + + if ((addr & 0x0f) == 0x0f) + { + syslog(LOG_INFO, "\n"); + } + } + + syslog(LOG_INFO, "\nScan complete: %d devices found on I2C%d\n", + found, i2c_bus); + + return found; +} +#endif /* CONFIG_I2C_RESET */ + +/**************************************************************************** + * Name: stm32_i2c_list_devices + * + * Description: + * List all registered I2C devices on a specific bus. + * Useful for debugging. + * + * Input Parameters: + * i2c_bus - I2C bus number (1-4), or 0 for all buses + * + * Returned Value: + * Number of registered devices + * + ****************************************************************************/ + +int stm32_i2c_list_devices(int i2c_bus) +{ + struct i2c_device_s *devices; + int total = 0; + int bus; + int i; + int start_bus; + int end_bus; + + if (i2c_bus == 0) + { + /* List all buses */ + + start_bus = 1; + end_bus = 4; + } + else + { + /* List specific bus */ + + start_bus = i2c_bus; + end_bus = i2c_bus; + } + + syslog(LOG_INFO, "\nRegistered I2C Devices:\n"); + syslog(LOG_INFO, "%-5s %-4s %-12s %-8s %-10s\n", + "Bus", "Slot", "Name", "Address", "Frequency"); + syslog(LOG_INFO, "%-5s %-4s %-12s %-8s %-10s\n", + "---", "----", "------------", "--------", "----------"); + + for (bus = start_bus; bus <= end_bus; bus++) + { + devices = get_i2c_devices_array(bus); + if (!devices) + { + continue; + } + + for (i = 0; i < MAX_I2C_DEVICES_PER_BUS; i++) + { + if (devices[i].in_use) + { + syslog(LOG_INFO, + "I2C%-2d %-4d %-12s 0x%02x %-10lu\n", + bus, i, devices[i].name, devices[i].addr, + (unsigned long)devices[i].frequency); + total++; + } + } + } + + if (total == 0) + { + syslog(LOG_INFO, "(No devices registered)\n"); + } + else + { + syslog(LOG_INFO, "\nTotal: %d device(s)\n", total); + } + + return total; +} + +#endif /* CONFIG_STM32H7_I2C */ diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_lsm303agr.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_lsm303agr.c new file mode 100644 index 0000000000000..ba0133163bd85 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_lsm303agr.c @@ -0,0 +1,85 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_lsm303agr.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include + +#include +#include "stm32.h" +#include "nucleo-h753zi.h" +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_STM32H7_I2C1 +# error "LSM303AGR driver requires CONFIG_STM32H7_I2C1 to be enabled" +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_lsm303agr_initialize + * + * Description: + * Initialize I2C-based LSM303AGR. + * + ****************************************************************************/ + +int stm32_lsm303agr_initialize(char *devpath) +{ + struct i2c_master_s *i2c; + int ret = OK; + + sninfo("INFO: Initializing LMS303AGR sensor over I2C\n"); + +#if defined(CONFIG_STM32H7_I2C1) + i2c = stm32_i2cbus_initialize(1); + if (i2c == NULL) + { + return -ENODEV; + } + + ret = lsm303agr_sensor_register("/dev/lsm303agr0", i2c, + LSM303AGRMAGNETO_ADDR); + if (ret < 0) + { + snerr("ERROR: Failed to initialize LMS303AGR magneto driver %s\n", + devpath); + return -ENODEV; + } + + sninfo("INFO: LMS303AGR sensor has been initialized successfully\n"); +#endif + + return ret; +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_lsm6dsl.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_lsm6dsl.c new file mode 100644 index 0000000000000..18440d3b3fc8e --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_lsm6dsl.c @@ -0,0 +1,91 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_lsm6dsl.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include + +#include +#include "stm32.h" +#include "nucleo-h753zi.h" +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_STM32H7_I2C1 +# error "LSM6DSL driver requires CONFIG_STM32H7_I2C1 to be enabled" +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_lsm6dsl_initialize + * + * Description: + * Initialize I2C-based LSM6DSL. + * + ****************************************************************************/ + +int stm32_lsm6dsl_initialize(char *devpath) +{ + struct i2c_master_s *i2c; + int ret = OK; + + sninfo("Initializing LMS6DSL!\n"); + + /* Configure the GPIO interrupt */ + + stm32_configgpio(GPIO_LPS22HB_INT1); + +#if defined(CONFIG_STM32H7_I2C1) + i2c = stm32_i2cbus_initialize(1); + if (i2c == NULL) + { + return -ENODEV; + } + + sninfo("INFO: Initializing LMS6DSL accelero-gyro sensor over I2C%d\n", + ret); + + ret = lsm6dsl_sensor_register(devpath, i2c, LSM6DSLACCEL_ADDR1); + if (ret < 0) + { + snerr("ERROR: Failed to initialize LMS6DSL accelero-gyro driver %s\n", + devpath); + return -ENODEV; + } + + sninfo("INFO: LMS6DSL sensor has been initialized successfully\n"); +#endif + + return ret; +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_lsm9ds1.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_lsm9ds1.c new file mode 100644 index 0000000000000..c8d8b467b6a88 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_lsm9ds1.c @@ -0,0 +1,107 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_lsm9ds1.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include + +#include +#include "stm32.h" +#include "nucleo-h753zi.h" +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_STM32H7_I2C1 +# error "LSM9DS1 driver requires CONFIG_STM32H7_I2C1 to be enabled" +#endif + +#define LSM9DS1MAG_DEVPATH "/dev/lsm9ds1mag0" +#define LSM9DS1ACC_DEVPATH "/dev/lsm9ds1acc0" +#define LSM9DS1GYR_DEVPATH "/dev/lsm9ds1gyr0" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_lsm9ds1_initialize + * + * Description: + * Initialize I2C-based LSM9DS1. + * + ****************************************************************************/ + +int stm32_lsm9ds1_initialize(void) +{ + struct i2c_master_s *i2c; + int ret = OK; + + sninfo("Initializing LMS9DS1!\n"); + +#if defined(CONFIG_STM32H7_I2C1) + i2c = stm32_i2cbus_initialize(LMS9DS1_I2CBUS); + if (i2c == NULL) + { + return -ENODEV; + } + + sninfo("INFO: Initializing LMS9DS1 9DoF sensor over I2C%d\n", + LMS9DS1_I2CBUS); + + ret = lsm9ds1mag_register(LSM9DS1MAG_DEVPATH, i2c, LSM9DS1MAG_ADDR1); + if (ret < 0) + { + snerr("ERROR: Failed to initialize LMS9DS1 mag driver %s\n", + LSM9DS1MAG_DEVPATH); + return -ENODEV; + } + + ret = lsm9ds1gyro_register(LSM9DS1GYR_DEVPATH, i2c, LSM9DS1GYRO_ADDR1); + if (ret < 0) + { + snerr("ERROR: Failed to initialize LMS9DS1 gyro driver %s\n", + LSM9DS1MAG_DEVPATH); + return -ENODEV; + } + + ret = lsm9ds1accel_register(LSM9DS1ACC_DEVPATH, i2c, LSM9DS1ACCEL_ADDR1); + if (ret < 0) + { + snerr("ERROR: Failed to initialize LMS9DS1 accel driver %s\n", + LSM9DS1MAG_DEVPATH); + return -ENODEV; + } + + sninfo("INFO: LMS9DS1 sensor has been initialized successfully\n"); +#endif + + return ret; +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_mfrc522.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_mfrc522.c new file mode 100644 index 0000000000000..89897421849e2 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_mfrc522.c @@ -0,0 +1,270 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_mfrc522.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "nucleo-h753zi.h" +#include "stm32_spi.h" + +#if defined(CONFIG_SPI) && defined(CONFIG_CL_MFRC522) && \ + defined(CONFIG_NUCLEO_H753ZI_MFRC522_ENABLE) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Determine which SPI port to use based on Kconfig selection */ + +#ifdef CONFIG_NUCLEO_H753ZI_MFRC522_SPI1 +# define MFRC522_SPI_PORTNO 1 +# ifndef CONFIG_STM32H7_SPI1 +# error "MFRC522 configured for SPI1 but CONFIG_STM32H7_SPI1 not enabled" +# endif +# ifndef CONFIG_NUCLEO_H753ZI_SPI1_ENABLE +# error "MFRC522 on SPI1 needs CONFIG_NUCLEO_H753ZI_SPI1_ENABLE" +# endif +#elif defined(CONFIG_NUCLEO_H753ZI_MFRC522_SPI2) +# define MFRC522_SPI_PORTNO 2 +# ifndef CONFIG_STM32H7_SPI2 +# error "MFRC522 configured for SPI2 but CONFIG_STM32H7_SPI2 not enabled" +# endif +# ifndef CONFIG_NUCLEO_H753ZI_SPI2_ENABLE +# error "MFRC522 on SPI2 needs CONFIG_NUCLEO_H753ZI_SPI2_ENABLE" +# endif +#elif defined(CONFIG_NUCLEO_H753ZI_MFRC522_SPI3) +# define MFRC522_SPI_PORTNO 3 +# ifndef CONFIG_STM32H7_SPI3 +# error "MFRC522 configured for SPI3 but CONFIG_STM32H7_SPI3 not enabled" +# endif +# ifndef CONFIG_NUCLEO_H753ZI_SPI3_ENABLE +# error "MFRC522 on SPI3 needs CONFIG_NUCLEO_H753ZI_SPI3_ENABLE" +# endif +#elif defined(CONFIG_NUCLEO_H753ZI_MFRC522_SPI4) +# define MFRC522_SPI_PORTNO 4 +# ifndef CONFIG_STM32H7_SPI4 +# error "MFRC522 configured for SPI4 but CONFIG_STM32H7_SPI4 not enabled" +# endif +# ifndef CONFIG_NUCLEO_H753ZI_SPI4_ENABLE +# error "MFRC522 on SPI4 needs CONFIG_NUCLEO_H753ZI_SPI4_ENABLE" +# endif +#elif defined(CONFIG_NUCLEO_H753ZI_MFRC522_SPI5) +# define MFRC522_SPI_PORTNO 5 +# ifndef CONFIG_STM32H7_SPI5 +# error "MFRC522 configured for SPI5 but CONFIG_STM32H7_SPI5 not enabled" +# endif +# ifndef CONFIG_NUCLEO_H753ZI_SPI5_ENABLE +# error "MFRC522 on SPI5 needs CONFIG_NUCLEO_H753ZI_SPI5_ENABLE" +# endif +#elif defined(CONFIG_NUCLEO_H753ZI_MFRC522_SPI6) +# define MFRC522_SPI_PORTNO 6 +# ifndef CONFIG_STM32H7_SPI6 +# error "MFRC522 configured for SPI6 but CONFIG_STM32H7_SPI6 not enabled" +# endif +# ifndef CONFIG_NUCLEO_H753ZI_SPI6_ENABLE +# error "MFRC522 on SPI6 needs CONFIG_NUCLEO_H753ZI_SPI6_ENABLE" +# endif +#else +# error "No SPI port selected for MFRC522" +#endif + +/* Default device path if not specified */ + +#ifndef CONFIG_NUCLEO_H753ZI_MFRC522_DEVPATH +# define CONFIG_NUCLEO_H753ZI_MFRC522_DEVPATH "/dev/rfid0" +#endif + +/* Default CS pin configuration if not specified */ + +#ifndef CONFIG_NUCLEO_H753ZI_MFRC522_CS_PIN +# define CONFIG_NUCLEO_H753ZI_MFRC522_CS_PIN "PF1" +#endif + +/* Default active level (most MFRC522 modules are active low) */ + +#ifndef CONFIG_NUCLEO_H753ZI_MFRC522_CS_ACTIVE_LOW +# define CONFIG_NUCLEO_H753ZI_MFRC522_CS_ACTIVE_LOW true +#endif + +/* Device ID calculation - must match the scheme in stm32_spi.c + * SPI1: IDs 0-7, SPI2: IDs 8-15, SPI3: IDs 16-23, etc. + */ + +#ifndef CONFIG_NUCLEO_H753ZI_MFRC522_DEVID +# if MFRC522_SPI_PORTNO == 1 +# define CONFIG_NUCLEO_H753ZI_MFRC522_DEVID 0 +# elif MFRC522_SPI_PORTNO == 2 +# define CONFIG_NUCLEO_H753ZI_MFRC522_DEVID 8 +# elif MFRC522_SPI_PORTNO == 3 +# define CONFIG_NUCLEO_H753ZI_MFRC522_DEVID 16 +# elif MFRC522_SPI_PORTNO == 4 +# define CONFIG_NUCLEO_H753ZI_MFRC522_DEVID 24 +# elif MFRC522_SPI_PORTNO == 5 +# define CONFIG_NUCLEO_H753ZI_MFRC522_DEVID 32 +# elif MFRC522_SPI_PORTNO == 6 +# define CONFIG_NUCLEO_H753ZI_MFRC522_DEVID 40 +# endif +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_mfrc522initialize + * + * Description: + * Initialize and register the MFRC522 RFID driver. + * This function uses the board-specific CS registration system. + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/rfid0". + * If NULL, the default path from Kconfig is used. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int stm32_mfrc522initialize(FAR const char *devpath) +{ + FAR struct spi_dev_s *spi; + FAR const char *path; + int ret; + + path = devpath ? devpath : MFRC522_DEVPATH; + + syslog(LOG_INFO, + "Initializing MFRC522 on SPI%d, device ID: %d, path: %s\n", + MFRC522_SPI_PORTNO, CONFIG_NUCLEO_H753ZI_MFRC522_DEVID, path); + + /* Register the CS device with the SPI system */ + + ret = stm32_spi_register_cs_device( + MFRC522_SPI_PORTNO, + CONFIG_NUCLEO_H753ZI_MFRC522_DEVID, + CONFIG_NUCLEO_H753ZI_MFRC522_CS_PIN, + CONFIG_NUCLEO_H753ZI_MFRC522_CS_ACTIVE_LOW); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to register CS device for MFRC522: %d\n", ret); + return ret; + } + + /* Initialize the SPI bus */ + + spi = stm32_spibus_initialize(MFRC522_SPI_PORTNO); + if (!spi) + { + syslog(LOG_ERR, "ERROR: Failed to initialize SPI%d\n", + MFRC522_SPI_PORTNO); + + /* Cleanup: unregister the CS device */ + + stm32_spi_unregister_cs_device(MFRC522_SPI_PORTNO, + CONFIG_NUCLEO_H753ZI_MFRC522_DEVID); + return -ENODEV; + } + + /* Register the MFRC522 driver */ + + ret = mfrc522_register(path, spi); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to register MFRC522 driver: %d\n", + ret); + + /* Cleanup: unregister the CS device */ + + stm32_spi_unregister_cs_device(MFRC522_SPI_PORTNO, + CONFIG_NUCLEO_H753ZI_MFRC522_DEVID); + return ret; + } + + syslog(LOG_INFO, "MFRC522 driver registered successfully at %s\n", path); + + /* Note: The MFRC522 driver will use device ID 0 by default for SPI + * transactions. Our CS registration system will handle CS control + * based on the registered device ID. If the driver uses a different + * device ID, you may need to modify the driver or use a different + * registration approach. + */ + + return OK; +} + +/**************************************************************************** + * Name: stm32_mfrc522_get_devid + * + * Description: + * Get the device ID used by the MFRC522 for CS pin control. + * This is useful for debugging or advanced applications. + * + * Returned Value: + * Device ID used by MFRC522 + * + ****************************************************************************/ + +uint32_t stm32_mfrc522_get_devid(void) +{ + return CONFIG_NUCLEO_H753ZI_MFRC522_DEVID; +} + +/**************************************************************************** + * Name: stm32_mfrc522_cleanup + * + * Description: + * Cleanup MFRC522 resources. This function can be called during + * shutdown or error recovery. + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_mfrc522_cleanup(void) +{ + int ret; + + ret = stm32_spi_unregister_cs_device(MFRC522_SPI_PORTNO, + MFRC522_DEVICE_ID); + if (ret < 0) + { + syslog(LOG_WARNING, + "WARNING: Failed to unregister MFRC522 CS device: %d\n", ret); + } + + return ret; +} + +#endif /* CONFIG_SPI && CONFIG_CL_MFRC522 && + * CONFIG_NUCLEO_H753ZI_MFRC522_ENABLE */ diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_mmcsd.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_mmcsd.c new file mode 100644 index 0000000000000..2294ccb930cea --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_mmcsd.c @@ -0,0 +1,90 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_mmcsd.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include "stm32_spi.h" + +#include "nucleo-h753zi.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_DISABLE_MOUNTPOINT +# error "SD driver requires CONFIG_DISABLE_MOUNTPOINT to be disabled" +#endif + +#ifndef CONFIG_STM32H7_SPI3 +# error "MMC/SD requires SPI3 enabled" +#endif + +#define MMCSD_SPI_PORT (3) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_mmcsd_initialize + * + * Description: + * Initialize SPI-based SD card and card detect thread. + * + ****************************************************************************/ + +int stm32_mmcsd_initialize(int minor) +{ + struct spi_dev_s *spi; + int ret; + + mcinfo("INFO: Initializing mmcsd port %d minor %d\n", + MMCSD_SPI_PORT, minor); + + spi = stm32_spibus_initialize(MMCSD_SPI_PORT); + if (spi == NULL) + { + mcerr("ERROR: Failed to initialize SPI port %d\n", MMCSD_SPI_PORT); + return -ENODEV; + } + + ret = mmcsd_spislotinitialize(minor, 0, spi); + if (ret < 0) + { + mcerr("ERROR: Failed to bind SPI port %d to SD slot %d\n", + MMCSD_SPI_PORT, minor); + return ret; + } + + mcinfo("INFO: mmcsd card has been initialized successfully\n"); + return OK; +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_nrf24l01.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_nrf24l01.c new file mode 100644 index 0000000000000..e4b7cbf79ee23 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_nrf24l01.c @@ -0,0 +1,123 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_nrf24l01.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "arm_internal.h" +#include "chip.h" +#include "stm32.h" +#include "nucleo-h753zi.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NRF24L01_SPI 3 + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int nrf24l01_irq_attach(xcpt_t isr, void *arg); +static void nrf24l01_chip_enable(bool enable); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct nrf24l01_config_s nrf_cfg = +{ + .irqattach = nrf24l01_irq_attach, + .chipenable = nrf24l01_chip_enable, +}; + +static xcpt_t g_isr; +static void *g_arg; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int nrf24l01_irq_attach(xcpt_t isr, void *arg) +{ + wlinfo("Attach IRQ\n"); + g_isr = isr; + g_arg = arg; + stm32_gpiosetevent(GPIO_NRF24L01_IRQ, false, true, false, g_isr, g_arg); + return OK; +} + +static void nrf24l01_chip_enable(bool enable) +{ + wlinfo("CE:%d\n", enable); + stm32_gpiowrite(GPIO_NRF24L01_CE, enable); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int stm32_wlinitialize(void) +{ + struct spi_dev_s *spidev; + int ret = OK; + + syslog(LOG_INFO, "Register the nRF24L01 module\n"); + + /* Setup CE & IRQ line IOs */ + + stm32_configgpio(GPIO_NRF24L01_CE); + stm32_configgpio(GPIO_NRF24L01_IRQ); + + /* Init SPI bus */ + + spidev = stm32_spibus_initialize(NRF24L01_SPI); + if (!spidev) + { + wlerr("ERROR: Failed to initialize SPI %d bus\n", NRF24L01_SPI); + ret = -ENODEV; + goto errout; + } + + ret = nrf24l01_register(spidev, &nrf_cfg); + if (ret != OK) + { + wlerr("ERROR: Failed to register initialize SPI bus\n"); + goto errout; + } + +errout: + return ret; +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_pca9635.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_pca9635.c new file mode 100644 index 0000000000000..c1ce7206644aa --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_pca9635.c @@ -0,0 +1,84 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_pca9635.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include "stm32.h" +#include "nucleo-h753zi.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_pca9635_initialize + * + * Description: + * This function is called by board initialization logic to configure the + * LED PWM chip. This function will register the driver as /dev/leddrv0. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int stm32_pca9635_initialize(void) +{ + struct i2c_master_s *i2c; + int ret; + + /* Get the I2C driver that interfaces with the pca9635 */ + + i2c = stm32_i2cbus_initialize(PCA9635_I2CBUS); + if (!i2c) + { + i2cerr("ERROR: Failed to initialize I2C%d\n", PCA9635_I2CBUS); + return -1; + } + + ret = pca9635pw_register("/dev/leddrv0", i2c, PCA9635_I2CADDR); + if (ret < 0) + { + snerr("ERROR: Failed to register PCA9635 driver: %d\n", ret); + return ret; + } + + return OK; +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_progmem.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_progmem.c new file mode 100644 index 0000000000000..bf434459f5b76 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_progmem.c @@ -0,0 +1,254 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_progmem.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include "nucleo-h753zi.h" +#include + +#ifdef HAVE_PROGMEM_CHARDEV + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PARTITION_LABEL_LEN 16 + +/* Configuration ************************************************************/ + +/* Make sure that support for MTD partitions is enabled */ +#ifdef CONFIG_MTD + +#ifndef CONFIG_MTD_PARTITION +# error "CONFIG_MTD_PARTITION is required" +#endif + +#endif +/**************************************************************************** + * Private Types + ****************************************************************************/ + +#if defined(CONFIG_STM32_PROGMEM_OTA_PARTITION) + +struct ota_partition_s +{ + uint32_t offset; /* Partition offset from the beginning of MTD */ + uint32_t size; /* Partition size in bytes */ + const char *devpath; /* Partition device path */ +}; + +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#if defined(CONFIG_STM32_PROGMEM_OTA_PARTITION) +static struct mtd_dev_s *progmem_alloc_mtdpart(uint32_t mtd_offset, + uint32_t mtd_size); +static int init_ota_partitions(void); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct mtd_dev_s *g_progmem_mtd; + +#if defined(CONFIG_STM32_PROGMEM_OTA_PARTITION) +static const struct ota_partition_s g_ota_partition_table[] = +{ + { + .offset = CONFIG_STM32_OTA_PRIMARY_SLOT_OFFSET, + .size = CONFIG_STM32_OTA_SLOT_SIZE, + .devpath = CONFIG_STM32_OTA_PRIMARY_SLOT_DEVPATH + }, + { + .offset = CONFIG_STM32_OTA_SECONDARY_SLOT_OFFSET, + .size = CONFIG_STM32_OTA_SLOT_SIZE, + .devpath = CONFIG_STM32_OTA_SECONDARY_SLOT_DEVPATH + }, + { + .offset = CONFIG_STM32_OTA_SCRATCH_OFFSET, + .size = CONFIG_STM32_OTA_SCRATCH_SIZE, + .devpath = CONFIG_STM32_OTA_SCRATCH_DEVPATH + } +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#if defined(CONFIG_STM32_PROGMEM_OTA_PARTITION) + +/**************************************************************************** + * Name: sam_progmem_alloc_mtdpart + * + * Description: + * Allocate an MTD partition from FLASH. + * + * Input Parameters: + * mtd_offset - MTD Partition offset from the base address in FLASH. + * mtd_size - Size for the MTD partition. + * + * Returned Value: + * MTD partition data pointer on success, NULL on failure. + * + ****************************************************************************/ + +static struct mtd_dev_s *progmem_alloc_mtdpart(uint32_t mtd_offset, + uint32_t mtd_size) +{ + uint32_t blocks; + ssize_t startblock; + + ASSERT((mtd_offset % up_progmem_pagesize(0)) == 0); + ASSERT((mtd_size % up_progmem_pagesize(0)) == 0); + + finfo("\tMTD offset = 0x%"PRIx32"\n", mtd_offset); + finfo("\tMTD size = 0x%"PRIx32"\n", mtd_size); + + startblock = up_progmem_getpage(mtd_offset + up_progmem_getaddress(0)); + if (startblock < 0) + { + return NULL; + } + + blocks = mtd_size / up_progmem_pagesize(0); + + return mtd_partition(g_progmem_mtd, startblock, blocks); +} + +/**************************************************************************** + * Name: init_ota_partitions + * + * Description: + * Initialize partitions that are dedicated to firmware OTA update. + * + * Input Parameters: + * None. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int init_ota_partitions(void) +{ + int i; + struct mtd_dev_s *mtd; + int ret = 0; + char path[PARTITION_LABEL_LEN + 1]; + + for (i = 0; i < nitems(g_ota_partition_table); ++i) + { + const struct ota_partition_s *part = &g_ota_partition_table[i]; + mtd = progmem_alloc_mtdpart(part->offset, part->size); + + strlcpy(path, (char *)part->devpath, PARTITION_LABEL_LEN); + + finfo("INFO: [label]: %s\n", path); + finfo("INFO: [offset]: 0x%08" PRIx32 "\n", part->offset); + finfo("INFO: [size]: 0x%08" PRIx32 "\n", part->size); + + if (!mtd) + { + ferr("ERROR: Failed to create MTD partition\n"); + ret = -1; + } + + ret = register_mtddriver(path, mtd, 0777, NULL); + if (ret < 0) + { + ferr("ERROR: Failed to register MTD @ %s\n", path); + ret = -1; + } + } + + return ret; +} +#endif /* CONFIG_STM32_PROGMEM_OTA_PARTITION */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_progmem_init + * + * Initialize Progmem partition. Read partition information, and use + * these data for creating MTD. + * + * Input Parameters: + * None + * + * Returned Value: + * 0 if success or a negative value if fail. + * + ****************************************************************************/ + +int stm32_progmem_init(void) +{ + int ret = 0; + + g_progmem_mtd = progmem_initialize(); + if (g_progmem_mtd == NULL) + { + ferr("ERROR: Failed to get progmem flash MTD\n"); + ret = -EIO; + } + +#ifdef CONFIG_STM32_PROGMEM_OTA_PARTITION + ret = init_ota_partitions(); + if (ret < 0) + { + ferr("ERROR: Failed to create OTA partition from MTD\n"); + ret = -EIO; + } +#endif + + return ret; +} + +#endif /* HAVE_PROGMEM_CHARDEV */ diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_pwm.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_pwm.c new file mode 100644 index 0000000000000..7489d9400f78d --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_pwm.c @@ -0,0 +1,110 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_pwm.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include "chip.h" +#include "arm_internal.h" +#include "stm32_pwm.h" +#include "nucleo-h753zi.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#define HAVE_PWM 1 + +#ifndef CONFIG_PWM +# undef HAVE_PWM +#endif + +#ifndef CONFIG_STM32H7_TIM1 +# undef HAVE_PWM +#endif + +#ifndef CONFIG_STM32H7_TIM1_PWM +# undef HAVE_PWM +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_pwm_setup + * + * Description: + * Initialize PWM and register the PWM device. + * + ****************************************************************************/ + +int stm32_pwm_setup(void) +{ +#ifdef HAVE_PWM + static bool initialized = false; + struct pwm_lowerhalf_s *pwm; + int ret; + + /* Have we already initialized? */ + + if (!initialized) + { + /* Get an instance of the PWM interface */ + + pwm = stm32_pwminitialize(NUCLEOH753ZI_PWMTIMER); + if (!pwm) + { + tmrerr("ERROR: Failed to get the STM32 PWM lower half\n"); + return -ENODEV; + } + + /* Register the PWM driver at "/dev/pwm0" */ + + ret = pwm_register("/dev/pwm0", pwm); + if (ret < 0) + { + tmrerr("ERROR: pwm_register failed: %d\n", ret); + return ret; + } + + /* Now we are initialized */ + + initialized = true; + } + + return OK; +#else + return -ENODEV; +#endif +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_reset.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_reset.c new file mode 100644 index 0000000000000..5eb902c30fc6d --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_reset.c @@ -0,0 +1,64 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_reset.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#ifdef CONFIG_BOARDCTL_RESET + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_reset + * + * Description: + * Reset board. Support for this function is required by board-level + * logic if CONFIG_BOARDCTL_RESET is selected. + * + * Input Parameters: + * status - Status information provided with the reset event. This + * meaning of this status information is board-specific. If not + * used by a board, the value zero may be provided in calls to + * board_reset(). + * + * Returned Value: + * If this function returns, then it was not possible to power-off the + * board due to some constraints. The return value int this case is a + * board-specific reason for the failure to shutdown. + * + ****************************************************************************/ + +int board_reset(int status) +{ + up_systemreset(); + return 0; +} + +#endif /* CONFIG_BOARDCTL_RESET */ diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_romfs.h b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_romfs.h new file mode 100644 index 0000000000000..c0a6ebf6e3469 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_romfs.h @@ -0,0 +1,63 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_romfs.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM_STM32H7_NUCLEO_H753ZI_SRC_STM32_ROMFS_H +#define __BOARDS_ARM_STM32H7_NUCLEO_H753ZI_SRC_STM32_ROMFS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifdef CONFIG_STM32_ROMFS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define ROMFS_SECTOR_SIZE 64 + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_romfs_initialize + * + * Description: + * Registers built-in ROMFS image as block device and mounts it. + * + * Returned Value: + * Zero (OK) on success, a negated errno value on error. + * + * Assumptions/Limitations: + * Memory addresses [romfs_data_begin .. romfs_data_end) should contain + * ROMFS volume data, as included in the assembly snippet above (l. 84). + * + ****************************************************************************/ + +int stm32_romfs_initialize(void); + +#endif /* CONFIG_STM32_ROMFS */ + +#endif /* __BOARDS_ARM_STM32H7_NUCLEO_H753ZI_SRC_STM32_ROMFS_H */ diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_romfs_initialize.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_romfs_initialize.c new file mode 100644 index 0000000000000..6496a7707d8ef --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_romfs_initialize.c @@ -0,0 +1,139 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_romfs_initialize.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include "stm32_romfs.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_STM32_ROMFS +# error "CONFIG_STM32_ROMFS must be defined" +#else + +#ifndef CONFIG_STM32_ROMFS_IMAGEFILE +# error "CONFIG_STM32_ROMFS_IMAGEFILE must be defined" +#endif + +#ifndef CONFIG_STM32_ROMFS_DEV_MINOR +# error "CONFIG_STM32_ROMFS_DEV_MINOR must be defined" +#endif + +#ifndef CONFIG_STM32_ROMFS_MOUNTPOINT +# error "CONFIG_STM32_ROMFS_MOUNTPOINT must be defined" +#endif + +#define NSECTORS(size) (((size) + ROMFS_SECTOR_SIZE - 1)/ROMFS_SECTOR_SIZE) + +#define STR2(m) #m +#define STR(m) STR2(m) + +#define MKMOUNT_DEVNAME(m) "/dev/ram" STR(m) +#define MOUNT_DEVNAME MKMOUNT_DEVNAME(CONFIG_STM32_ROMFS_DEV_MINOR) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +__asm__ ( + " .section .rodata \n" + " .balign 16 \n" + " .globl romfs_data_begin \n" + "romfs_data_begin: \n" + " .incbin " STR(CONFIG_STM32_ROMFS_IMAGEFILE)"\n" + " .balign " STR(ROMFS_SECTOR_SIZE) "\n" + " .globl romfs_data_end \n" + "romfs_data_end: \n" + ); + +extern const uint8_t romfs_data_begin[]; +extern const uint8_t romfs_data_end[]; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_romfs_initialize + * + * Description: + * Registers the aboveincluded binary file as block device. + * Then mounts the block device as ROMFS filesystems. + * + * Returned Value: + * Zero (OK) on success, a negated errno value on error. + * + * Assumptions/Limitations: + * Memory addresses [romfs_data_begin .. romfs_data_end) should contain + * ROMFS volume data, as included in the assembly snippet above (l. 84). + * + ****************************************************************************/ + +int stm32_romfs_initialize(void) +{ + size_t romfs_data_len; + int ret; + + /* Create a ROM disk for the /etc filesystem */ + + romfs_data_len = romfs_data_end - romfs_data_begin; + + ret = romdisk_register(CONFIG_STM32_ROMFS_DEV_MINOR, romfs_data_begin, + NSECTORS(romfs_data_len), ROMFS_SECTOR_SIZE); + if (ret < 0) + { + ferr("ERROR: romdisk_register failed: %d\n", -ret); + return ret; + } + + /* Mount the file system */ + + finfo("Mounting ROMFS filesystem at target=%s with source=%s\n", + CONFIG_STM32_ROMFS_MOUNTPOINT, MOUNT_DEVNAME); + + ret = nx_mount(MOUNT_DEVNAME, CONFIG_STM32_ROMFS_MOUNTPOINT, + "romfs", MS_RDONLY, NULL); + if (ret < 0) + { + ferr("ERROR: nx_mount(%s,%s,romfs) failed: %d\n", + MOUNT_DEVNAME, CONFIG_STM32_ROMFS_MOUNTPOINT, ret); + return ret; + } + + return OK; +} + +#endif /* CONFIG_STM32_ROMFS */ diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_spi.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_spi.c new file mode 100644 index 0000000000000..843f9105b1a12 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_spi.c @@ -0,0 +1,1037 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_spi.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "stm32_gpio.h" +#include "stm32_spi.h" +#include "nucleo-h753zi.h" +#include + +#ifdef CONFIG_STM32H7_SPI + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MAX_CS_DEVICES_PER_SPI 16 +#define INVALID_CS_PIN 0 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* CS pin registration structure */ + +struct spi_cs_device_s +{ + uint32_t gpio_config; /* GPIO configuration for CS pin */ + bool active_low; /* true = active low, false = active high */ + bool in_use; /* true = slot occupied */ +}; + +/* DC pin registration structure */ + +#ifdef CONFIG_SPI_CMDDATA +struct spi_dc_device_s +{ + uint32_t gpio_config; /* GPIO configuration for DC pin */ + bool in_use; /* true = slot occupied */ +}; +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* CS device registrations for each SPI bus */ + +#ifdef CONFIG_STM32H7_SPI1 +static struct spi_cs_device_s g_spi1_cs_devices[MAX_CS_DEVICES_PER_SPI]; +#ifdef CONFIG_SPI_CMDDATA +static struct spi_dc_device_s g_spi1_dc_devices[MAX_CS_DEVICES_PER_SPI]; +#endif +#endif + +#ifdef CONFIG_STM32H7_SPI2 +static struct spi_cs_device_s g_spi2_cs_devices[MAX_CS_DEVICES_PER_SPI]; +#ifdef CONFIG_SPI_CMDDATA +static struct spi_dc_device_s g_spi2_dc_devices[MAX_CS_DEVICES_PER_SPI]; +#endif +#endif + +#ifdef CONFIG_STM32H7_SPI3 +static struct spi_cs_device_s g_spi3_cs_devices[MAX_CS_DEVICES_PER_SPI]; +#ifdef CONFIG_SPI_CMDDATA +static struct spi_dc_device_s g_spi3_dc_devices[MAX_CS_DEVICES_PER_SPI]; +#endif +#endif + +#ifdef CONFIG_STM32H7_SPI4 +static struct spi_cs_device_s g_spi4_cs_devices[MAX_CS_DEVICES_PER_SPI]; +#ifdef CONFIG_SPI_CMDDATA +static struct spi_dc_device_s g_spi4_dc_devices[MAX_CS_DEVICES_PER_SPI]; +#endif +#endif + +#ifdef CONFIG_STM32H7_SPI5 +static struct spi_cs_device_s g_spi5_cs_devices[MAX_CS_DEVICES_PER_SPI]; +#ifdef CONFIG_SPI_CMDDATA +static struct spi_dc_device_s g_spi5_dc_devices[MAX_CS_DEVICES_PER_SPI]; +#endif +#endif + +#ifdef CONFIG_STM32H7_SPI6 +static struct spi_cs_device_s g_spi6_cs_devices[MAX_CS_DEVICES_PER_SPI]; +#ifdef CONFIG_SPI_CMDDATA +static struct spi_dc_device_s g_spi6_dc_devices[MAX_CS_DEVICES_PER_SPI]; +#endif +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: parse_gpio_pin + * + * Description: + * Parse GPIO pin string like "PA0" into STM32 GPIO configuration. + * + * Input Parameters: + * pin_str - GPIO pin string (e.g., "PA0", "PF15", "PC13") + * error - Pointer to error code storage + * + * Returned Value: + * STM32 GPIO configuration value on success, 0 on error + * + ****************************************************************************/ + +static uint32_t parse_gpio_pin(FAR const char *pin_str, FAR int *error) +{ + size_t len; + char port; + FAR const char *pin_num_str; + FAR char *endptr; + long pin_num; + uint32_t port_base; + uint32_t gpio_pin; + + *error = 0; + + if (pin_str == NULL) + { + *error = -EINVAL; + return 0; + } + + /* Remove leading/trailing spaces */ + + while (*pin_str == ' ' || *pin_str == '\t') + { + pin_str++; + } + + len = strlen(pin_str); + if (len < 3 || len > 4) + { + *error = -EINVAL; + return 0; + } + + if (pin_str[0] != 'P') + { + *error = -EINVAL; + return 0; + } + + port = pin_str[1]; + if (port < 'A' || port > 'H') + { + *error = -EINVAL; + return 0; + } + + pin_num_str = &pin_str[2]; + pin_num = strtol(pin_num_str, &endptr, 10); + if (*endptr != '\0' || pin_num < 0 || pin_num > 15) + { + *error = -EINVAL; + return 0; + } + + /* Map port letter to STM32 port base */ + + switch (port) + { + case 'A': + port_base = GPIO_PORTA; break; + case 'B': + port_base = GPIO_PORTB; break; + case 'C': + port_base = GPIO_PORTC; break; + case 'D': + port_base = GPIO_PORTD; break; + case 'E': + port_base = GPIO_PORTE; break; + case 'F': + port_base = GPIO_PORTF; break; + case 'G': + port_base = GPIO_PORTG; break; + case 'H': + port_base = GPIO_PORTH; break; + default: + *error = -EINVAL; + return 0; + } + + /* Use correct STM32 GPIO pin macros */ + + switch (pin_num) + { + case 0: + gpio_pin = GPIO_PIN0; break; + case 1: + gpio_pin = GPIO_PIN1; break; + case 2: + gpio_pin = GPIO_PIN2; break; + case 3: + gpio_pin = GPIO_PIN3; break; + case 4: + gpio_pin = GPIO_PIN4; break; + case 5: + gpio_pin = GPIO_PIN5; break; + case 6: + gpio_pin = GPIO_PIN6; break; + case 7: + gpio_pin = GPIO_PIN7; break; + case 8: + gpio_pin = GPIO_PIN8; break; + case 9: + gpio_pin = GPIO_PIN9; break; + case 10: + gpio_pin = GPIO_PIN10; break; + case 11: + gpio_pin = GPIO_PIN11; break; + case 12: + gpio_pin = GPIO_PIN12; break; + case 13: + gpio_pin = GPIO_PIN13; break; + case 14: + gpio_pin = GPIO_PIN14; break; + case 15: + gpio_pin = GPIO_PIN15; break; + default: + *error = -EINVAL; + return 0; + } + + return (GPIO_OUTPUT | GPIO_OUTPUT_SET | GPIO_SPEED_50MHz | GPIO_FLOAT | + port_base | gpio_pin); +} + +/**************************************************************************** + * Name: get_cs_devices_array + * + * Description: + * Get CS devices array for a specific SPI bus. + * + * Input Parameters: + * spi_bus - SPI bus number (1-6) + * + * Returned Value: + * Pointer to CS devices array, NULL if invalid bus + * + ****************************************************************************/ + +static struct spi_cs_device_s *get_cs_devices_array(int spi_bus) +{ + switch (spi_bus) + { +#ifdef CONFIG_STM32H7_SPI1 + case 1: + return g_spi1_cs_devices; +#endif +#ifdef CONFIG_STM32H7_SPI2 + case 2: + return g_spi2_cs_devices; +#endif +#ifdef CONFIG_STM32H7_SPI3 + case 3: + return g_spi3_cs_devices; +#endif +#ifdef CONFIG_STM32H7_SPI4 + case 4: + return g_spi4_cs_devices; +#endif +#ifdef CONFIG_STM32H7_SPI5 + case 5: + return g_spi5_cs_devices; +#endif +#ifdef CONFIG_STM32H7_SPI6 + case 6: + return g_spi6_cs_devices; +#endif + default: + return NULL; + } +} + +/**************************************************************************** + * Name: get_dc_devices_array + * + * Description: + * Get DC devices array for a specific SPI bus. + * + * Input Parameters: + * spi_bus - SPI bus number (1-6) + * + * Returned Value: + * Pointer to DC devices array, NULL if invalid bus + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_CMDDATA +static struct spi_dc_device_s *get_dc_devices_array(int spi_bus) +{ + switch (spi_bus) + { +#ifdef CONFIG_STM32H7_SPI1 + case 1: + return g_spi1_dc_devices; +#endif +#ifdef CONFIG_STM32H7_SPI2 + case 2: + return g_spi2_dc_devices; +#endif +#ifdef CONFIG_STM32H7_SPI3 + case 3: + return g_spi3_dc_devices; +#endif +#ifdef CONFIG_STM32H7_SPI4 + case 4: + return g_spi4_dc_devices; +#endif +#ifdef CONFIG_STM32H7_SPI5 + case 5: + return g_spi5_dc_devices; +#endif +#ifdef CONFIG_STM32H7_SPI6 + case 6: + return g_spi6_dc_devices; +#endif + default: + return NULL; + } +} +#endif + +/**************************************************************************** + * Name: spi_cs_control + * + * Description: + * Control SPI chip select pin based on registered device. + * + * Input Parameters: + * spi_bus - SPI bus number (1-6) + * devid - Device ID within the bus + * selected - Select (true) or deselect (false) + * + ****************************************************************************/ + +static void spi_cs_control(int spi_bus, uint32_t devid, bool selected) +{ + struct spi_cs_device_s *cs_devices; + struct spi_cs_device_s *device; + bool pin_state; + uint32_t actual_devid = devid; + + cs_devices = get_cs_devices_array(spi_bus); + if (cs_devices == NULL) + { + spierr("ERROR: Invalid SPI bus %d\n", spi_bus); + return; + } + + /* Handle SPIDEV_* types */ + + if ((devid & 0xffff0000) != 0) + { + actual_devid = (devid & 0x0000ffff); + spiinfo("Detected SPIDEV type 0x%04lX, using index %lu for SPI%d\n", + (unsigned long)(devid >> 16), (unsigned long)actual_devid, + spi_bus); + } + else if (devid >= MAX_CS_DEVICES_PER_SPI) + { + spiwarn("WARNING: Device ID %lu >= maximum %d for SPI%d, " + "trying fallback to ID 0\n", + (unsigned long)devid, MAX_CS_DEVICES_PER_SPI, spi_bus); + + if (cs_devices[0].in_use) + { + actual_devid = 0; + spiinfo("SUCCESS: Using fallback device ID 0 for invalid ID %lu\n", + (unsigned long)devid); + } + else + { + spierr("ERROR: Device ID %lu >= maximum %d and no fallback " + "available for SPI%d\n", + (unsigned long)devid, MAX_CS_DEVICES_PER_SPI, spi_bus); + return; + } + } + + device = &cs_devices[actual_devid]; + if (!device->in_use) + { + spierr("ERROR: Device ID %lu (actual %lu) not registered for SPI%d\n", + (unsigned long)devid, (unsigned long)actual_devid, spi_bus); + return; + } + + /* Calculate pin state */ + + if (device->active_low) + { + pin_state = !selected; + } + else + { + pin_state = selected; + } + + stm32_gpiowrite(device->gpio_config, pin_state); + + spiinfo("SPI%d CS%lu->%lu: %s (pin %s)\n", + spi_bus, (unsigned long)devid, (unsigned long)actual_devid, + selected ? "SELECT" : "DESELECT", + pin_state ? "HIGH" : "LOW"); +} + +/**************************************************************************** + * Name: spi_dc_control + * + * Description: + * Control SPI DC (Data/Command) pin for registered device. + * + * Input Parameters: + * spi_bus - SPI bus number (1-6) + * devid - Device ID within the bus + * cmd - true = command mode, false = data mode + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_CMDDATA +static void spi_dc_control(int spi_bus, uint32_t devid, bool cmd) +{ + struct spi_dc_device_s *dc_devices; + struct spi_dc_device_s *device; + uint32_t actual_devid = devid; + + dc_devices = get_dc_devices_array(spi_bus); + if (dc_devices == NULL) + { + spierr("ERROR: Invalid SPI bus %d for DC control\n", spi_bus); + return; + } + + /* Handle SPIDEV_* types */ + + if ((devid & 0xffff0000) != 0) + { + actual_devid = (devid & 0x0000ffff); + } + else if (devid >= MAX_CS_DEVICES_PER_SPI) + { + spierr("ERROR: Device ID %lu >= maximum %d for DC control on SPI%d\n", + (unsigned long)devid, MAX_CS_DEVICES_PER_SPI, spi_bus); + return; + } + + device = &dc_devices[actual_devid]; + if (!device->in_use) + { + spierr("ERROR: DC pin not registered for SPI%d device %lu\n", + spi_bus, (unsigned long)actual_devid); + return; + } + + /* Set DC pin: LOW for command, HIGH for data + * This is the standard convention for SPI displays + */ + + stm32_gpiowrite(device->gpio_config, !cmd); + + /* DEBUG SESSION + * spiinfo("SPI%d DC%lu: %s (pin %s)\n", + * spi_bus, (unsigned long)actual_devid, + * cmd ? "COMMAND" : "DATA", + * cmd ? "LOW" : "HIGH"); + * + * syslog(LOG_INFO, "SPI%d DC%lu: %s (pin %s) [GPIO=0x%08lx]\n", + * spi_bus, (unsigned long)actual_devid, + * cmd ? "COMMAND" : "DATA", + * cmd ? "LOW" : "HIGH", + * (unsigned long)device->gpio_config); + */ +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_spi_initialize + * + * Description: + * Initialize SPI interfaces. + * + * Returned Value: + * OK on success, negative errno on error + * + ****************************************************************************/ + +int stm32_spi_initialize(void) +{ + spiinfo("stm32_spi_initialize: Initializing SPI interfaces\n"); + +#ifdef CONFIG_STM32H7_SPI1 + memset(g_spi1_cs_devices, 0, sizeof(g_spi1_cs_devices)); +#ifdef CONFIG_SPI_CMDDATA + memset(g_spi1_dc_devices, 0, sizeof(g_spi1_dc_devices)); +#endif + spiinfo("SPI1 CS/DC registry initialized\n"); +#endif + +#ifdef CONFIG_STM32H7_SPI2 + memset(g_spi2_cs_devices, 0, sizeof(g_spi2_cs_devices)); +#ifdef CONFIG_SPI_CMDDATA + memset(g_spi2_dc_devices, 0, sizeof(g_spi2_dc_devices)); +#endif + spiinfo("SPI2 CS/DC registry initialized\n"); +#endif + +#ifdef CONFIG_STM32H7_SPI3 + memset(g_spi3_cs_devices, 0, sizeof(g_spi3_cs_devices)); +#ifdef CONFIG_SPI_CMDDATA + memset(g_spi3_dc_devices, 0, sizeof(g_spi3_dc_devices)); +#endif + spiinfo("SPI3 CS/DC registry initialized\n"); +#endif + +#ifdef CONFIG_STM32H7_SPI4 + memset(g_spi4_cs_devices, 0, sizeof(g_spi4_cs_devices)); +#ifdef CONFIG_SPI_CMDDATA + memset(g_spi4_dc_devices, 0, sizeof(g_spi4_dc_devices)); +#endif + spiinfo("SPI4 CS/DC registry initialized\n"); +#endif + +#ifdef CONFIG_STM32H7_SPI5 + memset(g_spi5_cs_devices, 0, sizeof(g_spi5_cs_devices)); +#ifdef CONFIG_SPI_CMDDATA + memset(g_spi5_dc_devices, 0, sizeof(g_spi5_dc_devices)); +#endif + spiinfo("SPI5 CS/DC registry initialized\n"); +#endif + +#ifdef CONFIG_STM32H7_SPI6 + memset(g_spi6_cs_devices, 0, sizeof(g_spi6_cs_devices)); +#ifdef CONFIG_SPI_CMDDATA + memset(g_spi6_dc_devices, 0, sizeof(g_spi6_dc_devices)); +#endif + spiinfo("SPI6 CS/DC registry initialized\n"); +#endif + + spiinfo("SPI initialization completed\n"); + return OK; +} + +/**************************************************************************** + * Name: stm32_spi_register_cs_device + * + * Description: + * Register a CS device for a specific SPI bus and device ID. + * + ****************************************************************************/ + +int stm32_spi_register_cs_device(int spi_bus, uint32_t devid, + const char *cs_pin, bool active_low) +{ + struct spi_cs_device_s *cs_devices; + struct spi_cs_device_s *device; + uint32_t gpio_config; + int error; + int ret; + + cs_devices = get_cs_devices_array(spi_bus); + if (cs_devices == NULL) + { + spierr("ERROR: Invalid SPI bus %d\n", spi_bus); + return -EINVAL; + } + + if (devid >= MAX_CS_DEVICES_PER_SPI) + { + spierr("ERROR: Device ID %lu >= maximum %d\n", + (unsigned long)devid, MAX_CS_DEVICES_PER_SPI); + return -EINVAL; + } + + device = &cs_devices[devid]; + if (device->in_use) + { + spierr("ERROR: Device ID %lu already registered for SPI%d\n", + (unsigned long)devid, spi_bus); + return -EBUSY; + } + + gpio_config = parse_gpio_pin(cs_pin, &error); + if (error != 0) + { + spierr("ERROR: Invalid CS pin '%s': %d\n", cs_pin, error); + return error; + } + + ret = stm32_configgpio(gpio_config); + if (ret < 0) + { + spierr("ERROR: Failed to configure CS pin %s: %d\n", cs_pin, ret); + return ret; + } + + stm32_gpiowrite(gpio_config, active_low ? true : false); + + device->gpio_config = gpio_config; + device->active_low = active_low; + device->in_use = true; + + spiinfo("Registered SPI%d device %lu: pin %s (%s)\n", + spi_bus, (unsigned long)devid, cs_pin, + active_low ? "active_low" : "active_high"); + + return OK; +} + +/**************************************************************************** + * Name: stm32_spi_register_dc_pin + * + * Description: + * Register a DC (Data/Command) pin for a specific SPI device. + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_CMDDATA +int stm32_spi_register_dc_pin(int spi_bus, uint32_t devid, + const char *dc_pin) +{ + struct spi_dc_device_s *dc_devices; + struct spi_dc_device_s *device; + uint32_t gpio_config; + int error; + int ret; + + dc_devices = get_dc_devices_array(spi_bus); + if (dc_devices == NULL) + { + spierr("ERROR: Invalid SPI bus %d\n", spi_bus); + return -EINVAL; + } + + if (devid >= MAX_CS_DEVICES_PER_SPI) + { + spierr("ERROR: Device ID %lu >= maximum %d\n", + (unsigned long)devid, MAX_CS_DEVICES_PER_SPI); + return -EINVAL; + } + + device = &dc_devices[devid]; + if (device->in_use) + { + spierr("ERROR: DC pin already registered for SPI%d device %lu\n", + spi_bus, (unsigned long)devid); + return -EBUSY; + } + + gpio_config = parse_gpio_pin(dc_pin, &error); + if (error != 0) + { + spierr("ERROR: Invalid DC pin '%s': %d\n", dc_pin, error); + return error; + } + + ret = stm32_configgpio(gpio_config); + if (ret < 0) + { + spierr("ERROR: Failed to configure DC pin %s: %d\n", dc_pin, ret); + return ret; + } + + /* Initialize DC pin to data mode (HIGH) */ + + stm32_gpiowrite(gpio_config, true); + + device->gpio_config = gpio_config; + device->in_use = true; + + spiinfo("Registered SPI%d device %lu DC pin: %s\n", + spi_bus, (unsigned long)devid, dc_pin); + + return OK; +} +#endif + +/**************************************************************************** + * Name: stm32_spi_unregister_cs_device + * + * Description: + * Unregister a CS device. + * + ****************************************************************************/ + +int stm32_spi_unregister_cs_device(int spi_bus, uint32_t devid) +{ + struct spi_cs_device_s *cs_devices; + struct spi_cs_device_s *device; + + cs_devices = get_cs_devices_array(spi_bus); + if (cs_devices == NULL) + { + return -EINVAL; + } + + if (devid >= MAX_CS_DEVICES_PER_SPI) + { + return -EINVAL; + } + + device = &cs_devices[devid]; + if (!device->in_use) + { + return -ENOENT; + } + + device->gpio_config = INVALID_CS_PIN; + device->active_low = false; + device->in_use = false; + + spiinfo("Unregistered SPI%d device %lu\n", spi_bus, + (unsigned long)devid); + return OK; +} + +/**************************************************************************** + * Name: stm32_spidev_register_all + * + * Description: + * Register SPI devices for user access. + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_DRIVER +int stm32_spidev_register_all(void) +{ + int ret = OK; + +#ifdef CONFIG_STM32H7_SPI1 + FAR struct spi_dev_s *spi1; + + spi1 = stm32_spibus_initialize(1); + if (spi1) + { + ret = spi_register(spi1, 1); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to register SPI1: %d\n", ret); + } + else + { + syslog(LOG_INFO, "SPI1 registered as /dev/spi1\n"); + } + } +#endif + +#ifdef CONFIG_STM32H7_SPI2 + FAR struct spi_dev_s *spi2; + + spi2 = stm32_spibus_initialize(2); + if (spi2) + { + ret = spi_register(spi2, 2); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to register SPI2: %d\n", ret); + } + else + { + syslog(LOG_INFO, "SPI2 registered as /dev/spi2\n"); + } + } +#endif + +#ifdef CONFIG_STM32H7_SPI3 + FAR struct spi_dev_s *spi3; + + spi3 = stm32_spibus_initialize(3); + if (spi3) + { + ret = spi_register(spi3, 3); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to register SPI3: %d\n", ret); + } + else + { + syslog(LOG_INFO, "SPI3 registered as /dev/spi3\n"); + } + } +#endif + +#ifdef CONFIG_STM32H7_SPI4 + FAR struct spi_dev_s *spi4; + + spi4 = stm32_spibus_initialize(4); + if (spi4) + { + ret = spi_register(spi4, 4); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to register SPI4: %d\n", ret); + } + else + { + syslog(LOG_INFO, "SPI4 registered as /dev/spi4\n"); + } + } +#endif + +#ifdef CONFIG_STM32H7_SPI5 + FAR struct spi_dev_s *spi5; + + spi5 = stm32_spibus_initialize(5); + if (spi5) + { + ret = spi_register(spi5, 5); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to register SPI5: %d\n", ret); + } + else + { + syslog(LOG_INFO, "SPI5 registered as /dev/spi5\n"); + } + } +#endif + +#ifdef CONFIG_STM32H7_SPI6 + FAR struct spi_dev_s *spi6; + + spi6 = stm32_spibus_initialize(6); + if (spi6) + { + ret = spi_register(spi6, 6); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to register SPI6: %d\n", ret); + } + else + { + syslog(LOG_INFO, "SPI6 registered as /dev/spi6\n"); + } + } +#endif + + return ret; +} +#endif + +/**************************************************************************** + * Name: stm32_spi1/2/3/4/5/6_select + * + * Description: + * SPI select functions - called by STM32 SPI driver + * + ****************************************************************************/ + +#ifdef CONFIG_STM32H7_SPI1 +void stm32_spi1select(FAR struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("SPI1 CS: devid=%lu, %s\n", + (unsigned long)devid, selected ? "SELECT" : "DESELECT"); + spi_cs_control(1, devid, selected); +} + +uint8_t stm32_spi1status(FAR struct spi_dev_s *dev, uint32_t devid) +{ + return SPI_STATUS_PRESENT; +} + +#ifdef CONFIG_SPI_CMDDATA +int stm32_spi1cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd) +{ + spiinfo("SPI1 CMDDATA: devid=%lu, %s\n", + (unsigned long)devid, cmd ? "COMMAND" : "DATA"); + spi_dc_control(1, devid, cmd); + return OK; +} +#endif +#endif + +#ifdef CONFIG_STM32H7_SPI2 +void stm32_spi2select(FAR struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("SPI2 CS: devid=%lu, %s\n", + (unsigned long)devid, selected ? "SELECT" : "DESELECT"); + spi_cs_control(2, devid, selected); +} + +uint8_t stm32_spi2status(FAR struct spi_dev_s *dev, uint32_t devid) +{ + return SPI_STATUS_PRESENT; +} + +#ifdef CONFIG_SPI_CMDDATA +int stm32_spi2cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd) +{ + spiinfo("SPI2 CMDDATA: devid=%lu, %s\n", + (unsigned long)devid, cmd ? "COMMAND" : "DATA"); + spi_dc_control(2, devid, cmd); + return OK; +} +#endif +#endif + +#ifdef CONFIG_STM32H7_SPI3 +void stm32_spi3select(FAR struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("SPI3 CS: devid=%lu, %s\n", + (unsigned long)devid, selected ? "SELECT" : "DESELECT"); + spi_cs_control(3, devid, selected); +} + +uint8_t stm32_spi3status(FAR struct spi_dev_s *dev, uint32_t devid) +{ + return SPI_STATUS_PRESENT; +} + +#ifdef CONFIG_SPI_CMDDATA +int stm32_spi3cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd) +{ + spiinfo("SPI3 CMDDATA: devid=%lu, %s\n", + (unsigned long)devid, cmd ? "COMMAND" : "DATA"); + spi_dc_control(3, devid, cmd); + return OK; +} +#endif +#endif + +#ifdef CONFIG_STM32H7_SPI4 +void stm32_spi4select(FAR struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("SPI4 CS: devid=%lu, %s\n", + (unsigned long)devid, selected ? "SELECT" : "DESELECT"); + spi_cs_control(4, devid, selected); +} + +uint8_t stm32_spi4status(FAR struct spi_dev_s *dev, uint32_t devid) +{ + return SPI_STATUS_PRESENT; +} + +#ifdef CONFIG_SPI_CMDDATA +int stm32_spi4cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd) +{ + spiinfo("SPI4 CMDDATA: devid=%lu, %s\n", + (unsigned long)devid, cmd ? "COMMAND" : "DATA"); + spi_dc_control(4, devid, cmd); + return OK; +} +#endif +#endif + +#ifdef CONFIG_STM32H7_SPI5 +void stm32_spi5select(FAR struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("SPI5 CS: devid=%lu, %s\n", + (unsigned long)devid, selected ? "SELECT" : "DESELECT"); + spi_cs_control(5, devid, selected); +} + +uint8_t stm32_spi5status(FAR struct spi_dev_s *dev, uint32_t devid) +{ + return SPI_STATUS_PRESENT; +} + +#ifdef CONFIG_SPI_CMDDATA +int stm32_spi5cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd) +{ + spiinfo("SPI5 CMDDATA: devid=%lu, %s\n", + (unsigned long)devid, cmd ? "COMMAND" : "DATA"); + spi_dc_control(5, devid, cmd); + return OK; +} +#endif +#endif + +#ifdef CONFIG_STM32H7_SPI6 +void stm32_spi6select(FAR struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("SPI6 CS: devid=%lu, %s\n", + (unsigned long)devid, selected ? "SELECT" : "DESELECT"); + spi_cs_control(6, devid, selected); +} + +uint8_t stm32_spi6status(FAR struct spi_dev_s *dev, uint32_t devid) +{ + return SPI_STATUS_PRESENT; +} + +#ifdef CONFIG_SPI_CMDDATA +int stm32_spi6cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd) +{ + spiinfo("SPI6 CMDDATA: devid=%lu, %s\n", + (unsigned long)devid, cmd ? "COMMAND" : "DATA"); + spi_dc_control(6, devid, cmd); + return OK; +} +#endif +#endif + +#endif /* CONFIG_STM32H7_SPI */ diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_ssd1306.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_ssd1306.c new file mode 100644 index 0000000000000..1baa42f18c6e3 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_ssd1306.c @@ -0,0 +1,760 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_ssd1306.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * About this driver + ****************************************************************************/ + +/* This is the board-level driver for the SSD1306 OLED display. + * + * WHAT IS SSD1306? + * ---------------- + * The SSD1306 is a small monochrome OLED display controller. Common sizes + * are 128x64 or 128x32 pixels. It communicates via I2C or SPI. + * This driver uses I2C. + * + * DRIVER ARCHITECTURE IN NUTTX: + * ----------------------------- + * NuttX uses a layered driver architecture: + * + * +---------------------+ + * | Application | <- Your app opens /dev/lcd0 + * +---------------------+ + * | + * +---------------------+ + * | LCD Dev Layer | <- lcddev_register() creates /dev/lcdX + * +---------------------+ + * | + * +---------------------+ + * | SSD1306 Driver | <- ssd1306_initialize() from NuttX + * +---------------------+ + * | + * +---------------------+ + * | I2C Master | <- stm32_i2cbus_initialize() from arch + * +---------------------+ + * | + * +---------------------+ + * | Hardware (I2C2) | <- Physical pins PF0/PF1 + * +---------------------+ + * + * THIS FILE'S ROLE: + * ----------------- + * This file is the "glue" that connects the NuttX SSD1306 driver to our + * specific board (Nucleo-H753ZI). It: + * 1. Gets the I2C bus interface + * 2. Passes it to the SSD1306 driver + * 3. Provides helper functions for power control + * + * IMPORTANT: The lcddev_register() call must be made from stm32_bringup.c + * AFTER board_lcd_getdev() returns, NOT inside board_lcd_getdev(). + * This is because lcddev_register() internally calls board_lcd_getdev(), + * which would create infinite recursion. + * + * WHY /dev/lcdX AND NOT /dev/fbX? + * ------------------------------- + * - /dev/fbX (framebuffer): Used for displays that need a full memory + * buffer in RAM. Good for large color displays (like ST7796 480x320). + * + * - /dev/lcdX (LCD interface): Used for smaller displays with internal + * memory. The SSD1306 has 1KB RAM inside the chip itself, so we don't + * need a big framebuffer in our MCU's RAM. + * + * BRIGHTNESS CONTROL: + * ------------------- + * The SSD1306 requires 3 registers to effectively control brightness: + * - 0x81: Contrast (0-255) + * - 0xD9: Pre-charge period + * - 0xDB: VCOMH deselect level + * + * The NuttX driver only sets contrast (0x81), which has minimal visual + * effect. This driver sends all 3 commands directly via I2C for real + * brightness control. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/* Standard C headers */ + +#include /* Error codes like ENODEV, EINVAL */ +#include /* For logging messages */ +#include /* Debug macros */ + +/* NuttX system headers */ + +#include /* Board-level interfaces */ + +/* LCD-related headers */ + +#include /* Generic LCD interface */ +#include /* SSD1306-specific driver */ + +/* I2C header */ + +#include /* I2C master interface */ + +/* Our board-specific header with pin definitions and prototypes */ + +#include "nucleo-h753zi.h" + +/**************************************************************************** + * Conditional Compilation + ****************************************************************************/ + +/* This entire file is only compiled if BOTH conditions are true: + * + * 1. CONFIG_LCD_SSD1306: The NuttX SSD1306 driver is enabled + * (menuconfig: Device Drivers -> LCD -> SSD1306) + * + * 2. CONFIG_NUCLEO_H753ZI_SSD1306_ENABLE: Our board-specific option + * (menuconfig: Board Selection -> I2C Devices -> SSD1306) + * + * If either is missing, this file compiles to nothing (empty). + */ + +#if defined(CONFIG_LCD_SSD1306) && \ + defined(CONFIG_NUCLEO_H753ZI_SSD1306_ENABLE) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* These macros translate the Kconfig values (accessed via nucleo-h753zi.h) + * to simpler names used in this file. + * + * WHY THIS INDIRECTION? + * The Kconfig values have long names like NUCLEO_SSD1306_I2C_BUS. + * Using shorter names makes the code more readable. + * Also, if we ever need to change the source of these values, + * we only change it here. + */ + +#define SSD1306_I2C_BUS NUCLEO_SSD1306_I2C_BUS /* Which I2C: 1-4 */ +#define SSD1306_I2C_ADDR NUCLEO_SSD1306_I2C_ADDR /* 0x3C or 0x3D */ +#define SSD1306_I2C_FREQUENCY NUCLEO_SSD1306_I2C_FREQUENCY /* 100k or 400k */ +#define SSD1306_POWER_PERCENT NUCLEO_SSD1306_POWER_PERCENT /* 0-100% */ +#define SSD1306_DEVPATH NUCLEO_SSD1306_DEVPATH /* "/dev/lcd0" */ +#define SSD1306_DEVNO NUCLEO_SSD1306_DEVNO /* 0 */ +#define SSD1306_DEVNAME NUCLEO_SSD1306_DEVNAME /* "ssd1306" */ + +/* SSD1306 Command Bytes */ + +#define SSD1306_CMD_BYTE 0x00 /* Control byte: Co=0, D/C#=0 */ +#define SSD1306_CMD_SETCONTRAST 0x81 /* Set contrast control */ +#define SSD1306_CMD_SETPRECHARGE 0xd9 /* Set pre-charge period */ +#define SSD1306_CMD_SETVCOMDETECT 0xdb /* Set VCOMH deselect level */ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* These are module-level variables (static = only visible in this file). + * + * g_ssd1306_i2c: Pointer to the I2C master interface. We get this from + * our board's I2C driver and pass it to the SSD1306 driver. + * + * g_ssd1306_lcd: Pointer to the LCD device structure. The SSD1306 driver + * returns this, and we use it to control the display. + * + * Both start as NULL and are set during initialization. + */ + +static struct i2c_master_s *g_ssd1306_i2c = NULL; +static struct lcd_dev_s *g_ssd1306_lcd = NULL; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ssd1306_send_cmd_arg + * + * Description: + * Send a command with one argument byte to the SSD1306 via I2C. + * + * Input Parameters: + * cmd - Command byte + * arg - Argument byte + * + * Returned Value: + * OK on success, negative errno on failure + * + ****************************************************************************/ + +static int ssd1306_send_cmd_arg(uint8_t cmd, uint8_t arg) +{ + struct i2c_msg_s msg; + uint8_t buf[3]; + int ret; + + if (!g_ssd1306_i2c) + { + return -ENODEV; + } + + /* SSD1306 I2C protocol for double-byte commands: + * [Control byte: 0x00] [Command] [Argument] + * + * Control byte 0x00 = Co=0 (continuous), D/C#=0 (command mode) + * This tells SSD1306 that following bytes are all commands. + */ + + buf[0] = SSD1306_CMD_BYTE; /* Control byte: command mode */ + buf[1] = cmd; + buf[2] = arg; + + msg.frequency = SSD1306_I2C_FREQUENCY; + msg.addr = SSD1306_I2C_ADDR; + msg.flags = 0; /* Write */ + msg.buffer = buf; + msg.length = 3; + + ret = I2C_TRANSFER(g_ssd1306_i2c, &msg, 1); + if (ret < 0) + { + syslog(LOG_ERR, "SSD1306: I2C cmd 0x%02x arg 0x%02x failed: %d\n", + cmd, arg, ret); + } + + return ret; +} + +/**************************************************************************** + * Name: ssd1306_set_brightness_raw + * + * Description: + * Set display brightness using all 3 required SSD1306 registers. + * This bypasses the NuttX driver to provide real brightness control. + * + * The SSD1306 brightness is controlled by: + * - Contrast register (0x81): 0-255, controls OLED segment current + * - Pre-charge period (0xD9): affects charge pump timing + * - VCOMH level (0xDB): affects voltage levels + * + * For effective dimming, all 3 must be adjusted together. + * + * Input Parameters: + * percent - Brightness 0-100% + * + * Returned Value: + * OK on success, negative errno on failure + * + ****************************************************************************/ + +static int ssd1306_set_brightness_raw(int percent) +{ + uint8_t contrast; + uint8_t precharge; + uint8_t vcomh; + int ret; + + /* Clamp to valid range */ + + if (percent < 0) + { + percent = 0; + } + else if (percent > 100) + { + percent = 100; + } + + /* Calculate register values based on percentage. + * + * Contrast: Linear scale 0-255 + * + * Pre-charge (0xD9): Controls charge/discharge time + * - Low nibble: phase 1 (1-15 DCLKs) + * - High nibble: phase 2 (1-15 DCLKs) + * - Range: 0x11 (dimmest) to 0xFF (brightest) + * + * VCOMH (0xDB): Deselect voltage level + * - 0x00 = 0.65 x VCC (dimmest) + * - 0x20 = 0.77 x VCC + * - 0x30 = 0.83 x VCC + * - 0x40 = 1.00 x VCC (brightest, may cause damage on some displays) + * + * Using linear interpolation for smoother transitions. + */ + + /* Contrast: direct linear mapping */ + + contrast = (uint8_t)((percent * 255) / 100); + + /* Pre-charge: scale from 0x11 to 0xF1 + * phase1 = 1 + (percent * 14 / 100) -> 1 to 15 + * phase2 = 1 + (percent * 14 / 100) -> 1 to 15 + */ + + { + uint8_t phase1; + uint8_t phase2; + + phase1 = 1 + (uint8_t)((percent * 14) / 100); + phase2 = 1 + (uint8_t)((percent * 14) / 100); + precharge = (phase2 << 4) | phase1; + } + + /* VCOMH: scale from 0x00 to 0x30 (avoid 0x40 for safety) + * Linear: 0x00 at 0%, 0x30 at 100% + */ + + vcomh = (uint8_t)((percent * 0x30) / 100); + + syslog(LOG_INFO, + "SSD1306: Brightness %d%% -> con=0x%02x pre=0x%02x vcom=0x%02x\n", + percent, contrast, precharge, vcomh); + + /* Send all three commands */ + + ret = ssd1306_send_cmd_arg(SSD1306_CMD_SETCONTRAST, contrast); + if (ret < 0) + { + return ret; + } + + ret = ssd1306_send_cmd_arg(SSD1306_CMD_SETPRECHARGE, precharge); + if (ret < 0) + { + return ret; + } + + ret = ssd1306_send_cmd_arg(SSD1306_CMD_SETVCOMDETECT, vcomh); + if (ret < 0) + { + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: calculate_power_level + * + * Description: + * Convert a percentage (0-100) to an SSD1306 power level. + * + * The SSD1306 driver only understands two power states: + * - 0 = display OFF (sleep mode, low power) + * - 1 = display ON (normal operation) + * + * So any percentage > 0 means "turn on", and 0 means "turn off". + * Brightness/contrast is a separate setting handled by the driver. + * + * Input Parameters: + * percent - Power level as percentage (0-100) + * + * Returned Value: + * 0 = power off, 1 = power on + * + ****************************************************************************/ + +static int calculate_power_level(int percent) +{ + if (percent <= 0) + { + return 0; /* Power off */ + } + else + { + return 1; /* Power on */ + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_lcd_initialize + * + * Description: + * Initialize the LCD hardware. This is called early during boot from + * stm32_bringup.c in the display initialization phase. + * + * This function does NOT initialize the display itself - it only + * prepares the I2C interface. The actual display initialization + * happens in board_lcd_getdev(). + * + * Why split into two functions? + * This follows the NuttX LCD driver pattern: + * - board_lcd_initialize(): Prepare the bus (I2C/SPI) + * - board_lcd_getdev(): Initialize and return the LCD device + * + * Returned Value: + * OK (0) on success + * Negative errno on failure (e.g., -ENODEV if I2C bus not available) + * + ****************************************************************************/ + +int board_lcd_initialize(void) +{ + int ret; + + /* Log what we're doing - helps with debugging */ + + lcdinfo("SSD1306: Initializing OLED display\n"); + lcdinfo("SSD1306: I2C Bus: I2C%d\n", SSD1306_I2C_BUS); + lcdinfo("SSD1306: Address: 0x%02X\n", SSD1306_I2C_ADDR); + lcdinfo("SSD1306: Frequency: %lu Hz\n", + (unsigned long)SSD1306_I2C_FREQUENCY); + lcdinfo("SSD1306: Brightness: %d%%\n", SSD1306_POWER_PERCENT); + + /* Step 1: Register I2C device for tracking and debugging + * + * This is OPTIONAL but useful. Our stm32_i2c.c driver keeps a list + * of all I2C devices on each bus. This helps when debugging to see + * what devices are registered. + * + * If this fails, we continue anyway - it's not critical. + */ + + ret = stm32_i2c_register_device(SSD1306_I2C_BUS, + SSD1306_I2C_ADDR, + SSD1306_I2C_FREQUENCY, + SSD1306_DEVNAME); + if (ret < 0) + { + syslog(LOG_WARNING, + "SSD1306: WARNING - Failed to register I2C device: %d\n", ret); + + /* Continue anyway - registration is optional */ + } + + /* Step 2: Get the I2C master interface + * + * stm32_i2c_get_master() returns a pointer to the I2C bus structure. + * This structure contains function pointers for I2C operations + * (transfer, reset, etc.) that the SSD1306 driver will use. + * + * If this fails, we cannot continue - we need I2C to talk to display. + */ + + g_ssd1306_i2c = stm32_i2c_get_master(SSD1306_I2C_BUS); + if (!g_ssd1306_i2c) + { + syslog(LOG_ERR, "SSD1306: ERROR - Failed to get I2C%d master\n", + SSD1306_I2C_BUS); + + /* Cleanup: unregister the device we registered in step 1 */ + + stm32_i2c_unregister_device(SSD1306_I2C_BUS, SSD1306_I2C_ADDR); + return -ENODEV; + } + + lcdinfo("SSD1306: I2C interface ready\n"); + return OK; +} + +/**************************************************************************** + * Name: board_lcd_getdev + * + * Description: + * Get the LCD device structure and initialize the display. + * + * This function: + * 1. Calls ssd1306_initialize() to init the display hardware + * 2. Turns on the display if configured to do so + * 3. Sets the brightness level from Kconfig (using direct I2C) + * + * IMPORTANT: Do NOT call lcddev_register() from inside this function! + * lcddev_register() internally calls board_lcd_getdev(), which would + * create infinite recursion. The lcddev_register() call must be made + * from stm32_bringup.c AFTER this function returns. + * + * Input Parameters: + * devno - Device number (0 for first LCD, 1 for second, etc.) + * This becomes the X in /dev/lcdX + * + * Returned Value: + * Pointer to lcd_dev_s structure on success + * NULL on failure + * + ****************************************************************************/ + +struct lcd_dev_s *board_lcd_getdev(int devno) +{ + int power_level; + + /* Safety check: make sure board_lcd_initialize() was called first */ + + if (!g_ssd1306_i2c) + { + syslog(LOG_ERR, + "SSD1306: ERROR - I2C not initialized. " + "Call board_lcd_initialize() first\n"); + return NULL; + } + + /* If already initialized, just return the existing device. + * This prevents re-initialization if called multiple times. + */ + + if (g_ssd1306_lcd != NULL) + { + return g_ssd1306_lcd; + } + + /* Step 1: Initialize the SSD1306 driver + * + * ssd1306_initialize() is provided by NuttX (drivers/lcd/ssd1306.c). + * It: + * - Sends initialization commands to the display via I2C + * - Allocates internal structures + * - Returns a lcd_dev_s pointer we can use to control the display + * + * Parameters: + * g_ssd1306_i2c: The I2C interface to use + * NULL: No SPI interface (we're using I2C) + * devno: Device number for this LCD + */ + + lcdinfo("SSD1306: Binding to I2C%d (device %d)\n", + SSD1306_I2C_BUS, devno); + + g_ssd1306_lcd = ssd1306_initialize(g_ssd1306_i2c, NULL, devno); + if (!g_ssd1306_lcd) + { + syslog(LOG_ERR, + "SSD1306: ERROR - ssd1306_initialize() failed\n"); + return NULL; + } + + lcdinfo("SSD1306: Driver initialized successfully\n"); + + /* Step 2: Turn on the display (if configured) + * + * The power level comes from Kconfig (SSD1306_POWER_PERCENT). + * - 0%: Keep display off + * - 1-100%: Turn display on + * + * setpower() is a function pointer in the lcd_dev_s structure. + * The SSD1306 driver implements it to send the "Display ON" command. + */ + + power_level = calculate_power_level(SSD1306_POWER_PERCENT); + + if (power_level > 0) + { + lcdinfo("SSD1306: Turning on display\n"); + g_ssd1306_lcd->setpower(g_ssd1306_lcd, power_level); + + /* Step 3: Set display brightness using direct I2C commands + * + * The NuttX setcontrast() only sends the contrast register (0x81), + * which has minimal visual effect on brightness. For real brightness + * control, we need to also adjust pre-charge and VCOMH registers. + */ + + ssd1306_set_brightness_raw(SSD1306_POWER_PERCENT); + } + else + { + lcdinfo("SSD1306: Display is OFF (power: 0%%)\n"); + } + + /* NOTE: Do NOT call lcddev_register() here! + * + * lcddev_register() internally calls board_lcd_getdev() to get + * the LCD device. If we call it here, we create infinite recursion: + * + * board_lcd_getdev() -> lcddev_register() -> board_lcd_getdev() -> ... + * + * The lcddev_register() call must be made from stm32_bringup.c + * AFTER this function returns successfully. + */ + + return g_ssd1306_lcd; +} + +/**************************************************************************** + * Name: board_lcd_uninitialize + * + * Description: + * Uninitialize the LCD and release resources. + * + * This should be called when the system is shutting down or if you + * need to reconfigure the LCD. It: + * - Turns off the display (saves power) + * - Unregisters the I2C device from our tracking system + * - Clears the global pointers + * + * Note: We don't uninitialize the I2C bus itself because other + * devices might be using it (sensors, etc.). + * + ****************************************************************************/ + +void board_lcd_uninitialize(void) +{ + lcdinfo("SSD1306: Uninitializing display\n"); + + /* Power off display to save energy */ + + if (g_ssd1306_lcd) + { + g_ssd1306_lcd->setpower(g_ssd1306_lcd, 0); + g_ssd1306_lcd = NULL; + } + + /* Unregister from our I2C device tracking system */ + + stm32_i2c_unregister_device(SSD1306_I2C_BUS, SSD1306_I2C_ADDR); + + /* Clear the I2C pointer but don't uninitialize the bus + * because other devices might be using it. + */ + + g_ssd1306_i2c = NULL; + + lcdinfo("SSD1306: Uninitialized\n"); +} + +/**************************************************************************** + * Name: stm32_ssd1306_get_devpath + * + * Description: + * Get the configured device path for the SSD1306. + * + * Useful when an application needs to know which /dev/lcdX to open. + * Instead of hardcoding "/dev/lcd0", the app can call this function. + * + * Example usage in an application: + * const char *path = stm32_ssd1306_get_devpath(); + * int fd = open(path, O_RDWR); + * + * Returned Value: + * Pointer to device path string (e.g., "/dev/lcd0") + * + ****************************************************************************/ + +const char *stm32_ssd1306_get_devpath(void) +{ + return SSD1306_DEVPATH; +} + +/**************************************************************************** + * Name: stm32_ssd1306_set_power + * + * Description: + * Change SSD1306 display power at runtime. + * + * This allows turning the display on/off after initialization. + * Useful for: + * - Power saving (turn off when not needed) + * - Screen blanking + * - User-controlled display toggle + * + * Input Parameters: + * percent - Power level 0-100% + * 0 = off, 1-100 = on (and sets brightness) + * + * Returned Value: + * OK on success + * -ENODEV if LCD not initialized + * -EINVAL if percentage is invalid + * + ****************************************************************************/ + +int stm32_ssd1306_set_power(int percent) +{ + int power_level; + + /* Check if the LCD was initialized */ + + if (!g_ssd1306_lcd) + { + syslog(LOG_ERR, "SSD1306: ERROR - Not initialized\n"); + return -ENODEV; + } + + /* Validate input range */ + + if (percent < 0 || percent > 100) + { + syslog(LOG_ERR, + "SSD1306: ERROR - Invalid power: %d (must be 0-100)\n", + percent); + return -EINVAL; + } + + /* Convert percentage to power level and apply */ + + power_level = calculate_power_level(percent); + + lcdinfo("SSD1306: Setting power to %d%%\n", percent); + + g_ssd1306_lcd->setpower(g_ssd1306_lcd, power_level); + + /* If turning on, also set brightness */ + + if (power_level > 0) + { + ssd1306_set_brightness_raw(percent); + } + + return OK; +} + +/**************************************************************************** + * Name: stm32_ssd1306_set_brightness + * + * Description: + * Change SSD1306 display brightness at runtime using direct I2C. + * + * This function provides real brightness control by adjusting all 3 + * required SSD1306 registers (contrast, pre-charge, VCOMH). + * + * Input Parameters: + * percent - Brightness level 0-100% + * + * Returned Value: + * OK on success + * -ENODEV if LCD not initialized + * -EINVAL if percentage is invalid + * + ****************************************************************************/ + +int stm32_ssd1306_set_brightness(int percent) +{ + /* Check if the I2C interface was initialized */ + + if (!g_ssd1306_i2c) + { + syslog(LOG_ERR, "SSD1306: ERROR - Not initialized\n"); + return -ENODEV; + } + + /* Validate input range */ + + if (percent < 0 || percent > 100) + { + syslog(LOG_ERR, + "SSD1306: ERROR - Invalid brightness: %d (must be 0-100)\n", + percent); + return -EINVAL; + } + + return ssd1306_set_brightness_raw(percent); +} + +#endif /* CONFIG_LCD_SSD1306 && CONFIG_NUCLEO_H753ZI_SSD1306_ENABLE */ diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_st7796.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_st7796.c new file mode 100644 index 0000000000000..02407f8d0960b --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_st7796.c @@ -0,0 +1,700 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_st7796.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "nucleo-h753zi.h" +#include "stm32_gpio.h" +#include "stm32_spi.h" + +#if defined(CONFIG_LCD_ST7796) && defined(CONFIG_NUCLEO_H753ZI_ST7796_ENABLE) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* SPI port selection from Kconfig */ + +#ifdef CONFIG_NUCLEO_H753ZI_ST7796_SPI1 +# define ST7796_SPI_PORTNO 1 +# ifndef CONFIG_STM32H7_SPI1 +# error "ST7796 configured for SPI1 but CONFIG_STM32H7_SPI1 not enabled" +# endif +# ifndef CONFIG_NUCLEO_H753ZI_SPI1_ENABLE +# error "ST7796 configured for SPI1 but board SPI1 not enabled" +# endif +#elif defined(CONFIG_NUCLEO_H753ZI_ST7796_SPI2) +# define ST7796_SPI_PORTNO 2 +# ifndef CONFIG_STM32H7_SPI2 +# error "ST7796 configured for SPI2 but CONFIG_STM32H7_SPI2 not enabled" +# endif +# ifndef CONFIG_NUCLEO_H753ZI_SPI2_ENABLE +# error "ST7796 configured for SPI2 but board SPI2 not enabled" +# endif +#elif defined(CONFIG_NUCLEO_H753ZI_ST7796_SPI3) +# define ST7796_SPI_PORTNO 3 +# ifndef CONFIG_STM32H7_SPI3 +# error "ST7796 configured for SPI3 but CONFIG_STM32H7_SPI3 not enabled" +# endif +# ifndef CONFIG_NUCLEO_H753ZI_SPI3_ENABLE +# error "ST7796 configured for SPI3 but board SPI3 not enabled" +# endif +#elif defined(CONFIG_NUCLEO_H753ZI_ST7796_SPI4) +# define ST7796_SPI_PORTNO 4 +# ifndef CONFIG_STM32H7_SPI4 +# error "ST7796 configured for SPI4 but CONFIG_STM32H7_SPI4 not enabled" +# endif +# ifndef CONFIG_NUCLEO_H753ZI_SPI4_ENABLE +# error "ST7796 configured for SPI4 but board SPI4 not enabled" +# endif +#elif defined(CONFIG_NUCLEO_H753ZI_ST7796_SPI5) +# define ST7796_SPI_PORTNO 5 +# ifndef CONFIG_STM32H7_SPI5 +# error "ST7796 configured for SPI5 but CONFIG_STM32H7_SPI5 not enabled" +# endif +# ifndef CONFIG_NUCLEO_H753ZI_SPI5_ENABLE +# error "ST7796 configured for SPI5 but board SPI5 not enabled" +# endif +#elif defined(CONFIG_NUCLEO_H753ZI_ST7796_SPI6) +# define ST7796_SPI_PORTNO 6 +# ifndef CONFIG_STM32H7_SPI6 +# error "ST7796 configured for SPI6 but CONFIG_STM32H7_SPI6 not enabled" +# endif +# ifndef CONFIG_NUCLEO_H753ZI_SPI6_ENABLE +# error "ST7796 configured for SPI6 but board SPI6 not enabled" +# endif +#else +# error "No SPI port selected for ST7796" +#endif + +/* Verify CONFIG_SPI_CMDDATA is enabled */ + +#ifndef CONFIG_SPI_CMDDATA +# error "CONFIG_SPI_CMDDATA must be enabled for ST7796 driver" +#endif + +/* Pin configuration from Kconfig with defaults */ + +#ifndef CONFIG_NUCLEO_H753ZI_ST7796_CS_PIN +# define CONFIG_NUCLEO_H753ZI_ST7796_CS_PIN "PA4" +#endif + +#ifndef CONFIG_NUCLEO_H753ZI_ST7796_DC_PIN +# define CONFIG_NUCLEO_H753ZI_ST7796_DC_PIN "PA3" +#endif + +#ifndef CONFIG_NUCLEO_H753ZI_ST7796_RESET_PIN +# define CONFIG_NUCLEO_H753ZI_ST7796_RESET_PIN "PA2" +#endif + +#ifndef CONFIG_NUCLEO_H753ZI_ST7796_LED_PIN +# define CONFIG_NUCLEO_H753ZI_ST7796_LED_PIN "PA1" +#endif + +#ifndef CONFIG_NUCLEO_H753ZI_ST7796_CS_ACTIVE_LOW +# define CONFIG_NUCLEO_H753ZI_ST7796_CS_ACTIVE_LOW true +#endif + +#ifndef CONFIG_NUCLEO_H753ZI_ST7796_DEVID +# define CONFIG_NUCLEO_H753ZI_ST7796_DEVID 0 +#endif + +/* SPI frequency from Kconfig with default */ + +#ifndef CONFIG_NUCLEO_H753ZI_ST7796_FREQUENCY +# define CONFIG_NUCLEO_H753ZI_ST7796_FREQUENCY ST7796_SPI_MAXFREQUENCY +#endif + +/* Reset timing (from ST7796 datasheet) */ + +#define ST7796_RESET_DELAY_MS 10 +#define ST7796_RESET_HOLD_MS 10 +#define ST7796_RESET_RELEASE_MS 120 + +/* GPIO helper macros */ + +#define ST7796_GPIO_CONFIG_MASK 0xffff0000 +#define ST7796_GPIO_IN_FLOAT (GPIO_INPUT | GPIO_FLOAT | GPIO_SPEED_50MHz) + +/* Display resolution based on orientation from Kconfig */ + +#if defined(CONFIG_NUCLEO_H753ZI_ST7796_LANDSCAPE) || \ + defined(CONFIG_NUCLEO_H753ZI_ST7796_RLANDSCAPE) +# define ST7796_XRES ST7796_YRES_RAW +# define ST7796_YRES ST7796_XRES_RAW +#else +# define ST7796_XRES ST7796_XRES_RAW +# define ST7796_YRES ST7796_YRES_RAW +#endif + +/* Base MADCTL value based on orientation and BGR from Kconfig */ + +#if defined(CONFIG_NUCLEO_H753ZI_ST7796_LANDSCAPE) +# ifdef CONFIG_NUCLEO_H753ZI_ST7796_BGR +# define ST7796_MADCTL_BASE ST7796_MADCTL_LANDSCAPE_BGR +# else +# define ST7796_MADCTL_BASE ST7796_MADCTL_LANDSCAPE +# endif +#elif defined(CONFIG_NUCLEO_H753ZI_ST7796_RPORTRAIT) +# ifdef CONFIG_NUCLEO_H753ZI_ST7796_BGR +# define ST7796_MADCTL_BASE ST7796_MADCTL_RPORTRAIT_BGR +# else +# define ST7796_MADCTL_BASE ST7796_MADCTL_RPORTRAIT +# endif +#elif defined(CONFIG_NUCLEO_H753ZI_ST7796_RLANDSCAPE) +# ifdef CONFIG_NUCLEO_H753ZI_ST7796_BGR +# define ST7796_MADCTL_BASE ST7796_MADCTL_RLANDSCAPE_BGR +# else +# define ST7796_MADCTL_BASE ST7796_MADCTL_RLANDSCAPE +# endif +#else /* Portrait (default) */ +# ifdef CONFIG_NUCLEO_H753ZI_ST7796_BGR +# define ST7796_MADCTL_BASE ST7796_MADCTL_PORTRAIT_BGR +# else +# define ST7796_MADCTL_BASE ST7796_MADCTL_PORTRAIT +# endif +#endif + +/* Initial rotation from Kconfig */ + +#ifdef CONFIG_NUCLEO_H753ZI_ST7796_ROTATION_180 +# define ST7796_INIT_ROTATION 180 +#else +# define ST7796_INIT_ROTATION 0 +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static uint32_t g_reset_pin; +static uint32_t g_led_pin; +static bool g_st7796_initialized = false; +static FAR struct spi_dev_s *g_spi_dev = NULL; +static FAR struct fb_vtable_s *g_fb_vtable = NULL; + +/* Board-specific configuration passed to generic driver */ + +static struct st7796_config_s g_st7796_config = +{ + .frequency = CONFIG_NUCLEO_H753ZI_ST7796_FREQUENCY, + .xres = ST7796_XRES, + .yres = ST7796_YRES, + .bpp = 16, + .madctl = ST7796_MADCTL_BASE /* 0x28 -> will fix it */, + .rotation = ST7796_INIT_ROTATION, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: parse_gpio_pin + * + * Description: + * Parse GPIO pin string like "PA0" into STM32 GPIO configuration. + * + ****************************************************************************/ + +static uint32_t parse_gpio_pin(FAR const char *pin_str, FAR int *error) +{ + size_t len; + char port; + FAR const char *pin_num_str; + FAR char *endptr; + long pin_num; + uint32_t port_base; + uint32_t gpio_pin; + + *error = 0; + + if (pin_str == NULL) + { + *error = -EINVAL; + return 0; + } + + while (*pin_str == ' ' || *pin_str == '\t') + { + pin_str++; + } + + len = strlen(pin_str); + if (len < 3 || len > 4) + { + *error = -EINVAL; + return 0; + } + + if (pin_str[0] != 'P') + { + *error = -EINVAL; + return 0; + } + + port = pin_str[1]; + if (port < 'A' || port > 'K') + { + *error = -EINVAL; + return 0; + } + + pin_num_str = &pin_str[2]; + pin_num = strtol(pin_num_str, &endptr, 10); + if (*endptr != '\0' || pin_num < 0 || pin_num > 15) + { + *error = -EINVAL; + return 0; + } + + switch (port) + { + case 'A': + port_base = GPIO_PORTA; break; + case 'B': + port_base = GPIO_PORTB; break; + case 'C': + port_base = GPIO_PORTC; break; + case 'D': + port_base = GPIO_PORTD; break; + case 'E': + port_base = GPIO_PORTE; break; + case 'F': + port_base = GPIO_PORTF; break; + case 'G': + port_base = GPIO_PORTG; break; + case 'H': + port_base = GPIO_PORTH; break; + default: + *error = -EINVAL; + return 0; + } + + switch (pin_num) + { + case 0: + gpio_pin = GPIO_PIN0; break; + case 1: + gpio_pin = GPIO_PIN1; break; + case 2: + gpio_pin = GPIO_PIN2; break; + case 3: + gpio_pin = GPIO_PIN3; break; + case 4: + gpio_pin = GPIO_PIN4; break; + case 5: + gpio_pin = GPIO_PIN5; break; + case 6: + gpio_pin = GPIO_PIN6; break; + case 7: + gpio_pin = GPIO_PIN7; break; + case 8: + gpio_pin = GPIO_PIN8; break; + case 9: + gpio_pin = GPIO_PIN9; break; + case 10: + gpio_pin = GPIO_PIN10; break; + case 11: + gpio_pin = GPIO_PIN11; break; + case 12: + gpio_pin = GPIO_PIN12; break; + case 13: + gpio_pin = GPIO_PIN13; break; + case 14: + gpio_pin = GPIO_PIN14; break; + case 15: + gpio_pin = GPIO_PIN15; break; + default: + *error = -EINVAL; + return 0; + } + + return (GPIO_OUTPUT | GPIO_OUTPUT_SET | GPIO_SPEED_50MHz | GPIO_FLOAT | + port_base | gpio_pin); +} + +/**************************************************************************** + * Name: stm32_st7796_gpio_initialize + * + * Description: + * Initialize GPIO pins for ST7796 (RESET, LED). + * + ****************************************************************************/ + +static int stm32_st7796_gpio_initialize(void) +{ + int ret; + int error; + + g_reset_pin = parse_gpio_pin(CONFIG_NUCLEO_H753ZI_ST7796_RESET_PIN, + &error); + if (error != 0) + { + syslog(LOG_ERR, "ERROR: Invalid RESET pin '%s': %d\n", + CONFIG_NUCLEO_H753ZI_ST7796_RESET_PIN, error); + return error; + } + + ret = stm32_configgpio(g_reset_pin); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to configure RESET pin: %d\n", ret); + return ret; + } + + g_led_pin = parse_gpio_pin(CONFIG_NUCLEO_H753ZI_ST7796_LED_PIN, &error); + if (error != 0) + { + syslog(LOG_ERR, "ERROR: Invalid LED pin '%s': %d\n", + CONFIG_NUCLEO_H753ZI_ST7796_LED_PIN, error); + return error; + } + + ret = stm32_configgpio(g_led_pin); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to configure LED pin: %d\n", ret); + return ret; + } + + stm32_gpiowrite(g_reset_pin, true); + stm32_gpiowrite(g_led_pin, false); /* Start with backlight OFF */ + + return OK; +} + +/**************************************************************************** + * Name: stm32_st7796_hardware_reset + * + * Description: + * Perform hardware reset of ST7796 display. + * + ****************************************************************************/ + +static void stm32_st7796_hardware_reset(void) +{ + stm32_gpiowrite(g_reset_pin, true); + nxsig_usleep(ST7796_RESET_DELAY_MS * 1000); + + stm32_gpiowrite(g_reset_pin, false); + nxsig_usleep(ST7796_RESET_HOLD_MS * 1000); + + stm32_gpiowrite(g_reset_pin, true); + nxsig_usleep(ST7796_RESET_RELEASE_MS * 1000); +} + +/**************************************************************************** + * Name: stm32_st7796_spi_initialize + * + * Description: + * Initialize SPI bus and register CS/DC pins for ST7796. + * + ****************************************************************************/ + +static int stm32_st7796_spi_initialize(void) +{ + int ret; + + stm32_st7796_hardware_reset(); + + ret = stm32_spi_register_cs_device(ST7796_SPI_PORTNO, + CONFIG_NUCLEO_H753ZI_ST7796_DEVID, + CONFIG_NUCLEO_H753ZI_ST7796_CS_PIN, + CONFIG_NUCLEO_H753ZI_ST7796_CS_ACTIVE_LOW); + + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to register CS: %d\n", ret); + return ret; + } + + ret = stm32_spi_register_dc_pin(ST7796_SPI_PORTNO, + CONFIG_NUCLEO_H753ZI_ST7796_DEVID, + CONFIG_NUCLEO_H753ZI_ST7796_DC_PIN); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to register DC: %d\n", ret); + stm32_spi_unregister_cs_device(ST7796_SPI_PORTNO, + CONFIG_NUCLEO_H753ZI_ST7796_DEVID); + return ret; + } + + g_spi_dev = stm32_spibus_initialize(ST7796_SPI_PORTNO); + if (g_spi_dev == NULL) + { + syslog(LOG_ERR, "ERROR: Failed to initialize SPI%d\n", + ST7796_SPI_PORTNO); + stm32_spi_unregister_cs_device(ST7796_SPI_PORTNO, + CONFIG_NUCLEO_H753ZI_ST7796_DEVID); + return -ENODEV; + } + + g_st7796_initialized = true; + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_fbinitialize + * + * Description: + * Initialize the framebuffer video hardware. Called by fb_register(). + * + ****************************************************************************/ + +int up_fbinitialize(int display) +{ + if (!g_st7796_initialized || g_spi_dev == NULL) + { + syslog(LOG_ERR, "ERROR: ST7796 not initialized\n"); + return -ENODEV; + } + + if (display != 0) + { + syslog(LOG_ERR, "ERROR: Invalid display: %d\n", display); + return -EINVAL; + } + + g_fb_vtable = st7796_fbinitialize(g_spi_dev, &g_st7796_config); + if (g_fb_vtable == NULL) + { + syslog(LOG_ERR, "ERROR: st7796_fbinitialize() failed\n"); + return -ENODEV; + } + + return OK; +} + +/**************************************************************************** + * Name: up_fbgetvplane + * + * Description: + * Return a reference to the framebuffer object for the specified plane. + * + ****************************************************************************/ + +FAR struct fb_vtable_s *up_fbgetvplane(int display, int vplane) +{ + if (display != 0 || vplane != 0) + { + return NULL; + } + + return g_fb_vtable; +} + +/**************************************************************************** + * Name: up_fbuninitialize + * + * Description: + * Uninitialize the framebuffer hardware. + * + ****************************************************************************/ + +void up_fbuninitialize(int display) +{ + if (display != 0) + { + return; + } + + stm32_gpiowrite(g_led_pin, false); + g_fb_vtable = NULL; +} + +/**************************************************************************** + * Name: stm32_st7796initialize + * + * Description: + * Initialize and register the ST7796 LCD driver. + * Called from board bringup. + * + ****************************************************************************/ + +int stm32_st7796initialize(int devno) +{ + int ret; + + /* Step 1: Initialize GPIO pins (RESET, LED) */ + + ret = stm32_st7796_gpio_initialize(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: GPIO init failed: %d\n", ret); + return ret; + } + + /* Step 2: Initialize SPI bus and register CS/DC */ + + ret = stm32_st7796_spi_initialize(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: SPI init failed: %d\n", ret); + return ret; + } + + /* Step 3: Register framebuffer device + * This calls up_fbinitialize() which initializes the display + * and applies initial rotation from config + */ + + ret = fb_register(0, 0); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: fb_register() failed: %d\n", ret); + stm32_spi_unregister_cs_device(ST7796_SPI_PORTNO, + CONFIG_NUCLEO_H753ZI_ST7796_DEVID); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: stm32_st7796_flush_fb + * + * Description: + * Flush the entire framebuffer to the display. Call this after + * fb_register() to make splashscreen visible on SPI displays. + * + ****************************************************************************/ + +int stm32_st7796_flush_fb(void) +{ + struct fb_area_s area; + + if (g_fb_vtable == NULL || g_fb_vtable->updatearea == NULL) + { + syslog(LOG_ERR, "ERROR: Framebuffer not ready for flush\n"); + return -ENODEV; + } + + area.x = 0; + area.y = 0; + area.w = ST7796_XRES; + area.h = ST7796_YRES; + + return g_fb_vtable->updatearea(g_fb_vtable, &area); +} + +/**************************************************************************** + * Name: stm32_st7796_backlight + * + * Description: + * Control backlight LED. + * + ****************************************************************************/ + +void stm32_st7796_backlight(bool on) +{ + stm32_gpiowrite(g_led_pin, on); +} + +/**************************************************************************** + * Name: stm32_st7796_power + * + * Description: + * Control display power. + * + ****************************************************************************/ + +void stm32_st7796_power(bool on) +{ + if (on) + { + stm32_st7796_hardware_reset(); + stm32_gpiowrite(g_led_pin, true); + } + else + { + stm32_gpiowrite(g_led_pin, false); + } +} + +/**************************************************************************** + * Name: stm32_st7796_reset_display + * + * Description: + * Public function to reset the display. + * + ****************************************************************************/ + +void stm32_st7796_reset_display(void) +{ + stm32_st7796_hardware_reset(); +} + +/**************************************************************************** + * Name: stm32_st7796_cleanup + * + * Description: + * Cleanup ST7796 resources. + * + ****************************************************************************/ + +int stm32_st7796_cleanup(void) +{ + int ret; + + stm32_gpiowrite(g_led_pin, false); + + stm32_configgpio((g_reset_pin & ST7796_GPIO_CONFIG_MASK) | + ST7796_GPIO_IN_FLOAT); + stm32_configgpio((g_led_pin & ST7796_GPIO_CONFIG_MASK) | + ST7796_GPIO_IN_FLOAT); + + ret = stm32_spi_unregister_cs_device(ST7796_SPI_PORTNO, + CONFIG_NUCLEO_H753ZI_ST7796_DEVID); + if (ret < 0) + { + syslog(LOG_WARNING, "WARNING: CS unregister failed: %d\n", ret); + } + + g_st7796_initialized = false; + g_spi_dev = NULL; + g_fb_vtable = NULL; + + return ret; +} + +#endif /* CONFIG_LCD_ST7796 && CONFIG_NUCLEO_H753ZI_ST7796_ENABLE */ diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_uid.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_uid.c new file mode 100644 index 0000000000000..9e76c34c082c8 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_uid.c @@ -0,0 +1,69 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_uid.c + * + * SPDX-License-Identifier: BSD-3-Clause + * SPDX-FileCopyrightText: 2015 Marawan Ragab. All rights reserved. + * SPDX-FileContributor: Marawan Ragab + * SPDX-FileContributor: David Sidrane + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include "stm32_uid.h" + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#if defined(CONFIG_BOARDCTL_UNIQUEID) +int board_uniqueid(uint8_t *uniqueid) +{ + if (uniqueid == NULL) + { + return -EINVAL; + } + + stm32_get_uniqueid(uniqueid); + return OK; +} +#endif diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_usb.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_usb.c new file mode 100644 index 0000000000000..bc94ce2b02171 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_usb.c @@ -0,0 +1,322 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_usb.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "arm_internal.h" +#include "chip.h" +#include "stm32_gpio.h" +#include "stm32_otg.h" +#include "nucleo-h753zi.h" + +#ifdef CONFIG_STM32H7_OTGFS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if defined(CONFIG_USBDEV) || defined(CONFIG_USBHOST) +# define HAVE_USB 1 +#else +# warning "CONFIG_STM32_OTGFS is enabled but neither CONFIG_USBDEV nor CONFIG_USBHOST" +# undef HAVE_USB +#endif + +#ifndef CONFIG_NUCLEOH753ZI_USBHOST_PRIO +# define CONFIG_NUCLEOH753ZI_USBHOST_PRIO 100 +#endif + +#ifndef CONFIG_NUCLEOH753ZI_USBHOST_STACKSIZE +# define CONFIG_NUCLEOH753ZI_USBHOST_STACKSIZE 2048 +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_USBHOST +static struct usbhost_connection_s *g_usbconn; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: usbhost_waiter + * + * Description: + * Wait for USB devices to be connected. + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST +static int usbhost_waiter(int argc, char *argv[]) +{ + struct usbhost_hubport_s *hport; + + uinfo("Running\n"); + for (; ; ) + { + /* Wait for the device to change state */ + + DEBUGVERIFY(CONN_WAIT(g_usbconn, &hport)); + uinfo("%s\n", hport->connected ? "connected" : "disconnected"); + + /* Did we just become connected? */ + + if (hport->connected) + { + /* Yes.. enumerate the newly connected device */ + + CONN_ENUMERATE(g_usbconn, hport); + } + } + + /* Keep the compiler from complaining */ + + return 0; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_usbinitialize + * + * Description: + * Called from stm32_usbinitialize very early in initialization to setup + * USB-related GPIO pins for the nucleo-144 board. + * + ****************************************************************************/ + +void stm32_usbinitialize(void) +{ + /* The OTG FS has an internal soft pull-up. + * No GPIO configuration is required + */ + + /* Configure the OTG FS VBUS sensing GPIO, + * Power On, and Overcurrent GPIOs + */ + +#ifdef CONFIG_STM32H7_OTGFS + stm32_configgpio(GPIO_OTGFS_VBUS); + stm32_configgpio(GPIO_OTGFS_PWRON); + stm32_configgpio(GPIO_OTGFS_OVER); +#endif +} + +/**************************************************************************** + * Name: stm32_usbhost_initialize + * + * Description: + * Called at application startup time to initialize the USB host + * functionality. + * This function will start a thread that will monitor for device + * connection/disconnection events. + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST +int stm32_usbhost_initialize(void) +{ + int ret; + + /* First, register all of the class drivers needed to support the drivers + * that we care about: + */ + + uinfo("Register class drivers\n"); + +#ifdef CONFIG_USBHOST_HUB + /* Initialize USB hub class support */ + + ret = usbhost_hub_initialize(); + if (ret < 0) + { + uerr("ERROR: usbhost_hub_initialize failed: %d\n", ret); + } +#endif + +#ifdef CONFIG_USBHOST_MSC + /* Register the USB mass storage class class */ + + ret = usbhost_msc_initialize(); + if (ret != OK) + { + uerr("ERROR: Failed to register the mass storage class: %d\n", ret); + } +#endif + +#ifdef CONFIG_USBHOST_CDCACM + /* Register the CDC/ACM serial class */ + + ret = usbhost_cdcacm_initialize(); + if (ret != OK) + { + uerr("ERROR: Failed to register the CDC/ACM serial class: %d\n", ret); + } +#endif + +#ifdef CONFIG_USBHOST_HIDKBD + /* Initialize the HID keyboard class */ + + ret = usbhost_kbdinit(); + if (ret != OK) + { + uerr("ERROR: Failed to register the HID keyboard class\n"); + } +#endif + +#ifdef CONFIG_USBHOST_HIDMOUSE + /* Initialize the HID mouse class */ + + ret = usbhost_mouse_init(); + if (ret != OK) + { + uerr("ERROR: Failed to register the HID mouse class\n"); + } +#endif + + /* Then get an instance of the USB host interface */ + + uinfo("Initialize USB host\n"); + g_usbconn = stm32_otgfshost_initialize(0); + if (g_usbconn) + { + /* Start a thread to handle device connection. */ + + uinfo("Start usbhost_waiter\n"); + + ret = kthread_create("usbhost", CONFIG_NUCLEOH753ZI_USBHOST_PRIO, + CONFIG_NUCLEOH753ZI_USBHOST_STACKSIZE, + usbhost_waiter, NULL); + return ret < 0 ? -ENOEXEC : OK; + } + + return -ENODEV; +} +#endif + +/**************************************************************************** + * Name: stm32_usbhost_vbusdrive + * + * Description: + * Enable/disable driving of VBUS 5V output. This function must be + * provided be each platform that implements the STM32 OTG FS host + * interface + * + * "On-chip 5 V VBUS generation is not supported. For this reason, a + * charge pump or, if 5 V are available on the application board, a + * basic power switch, must be added externally to drive the 5 V VBUS + * line. The external charge pump can be driven by any GPIO output. + * When the application decides to power on VBUS using the chosen GPIO, + * it must also set the port power bit in the host port control and status + * register (PPWR bit in OTG_FS_HPRT). + * + * "The application uses this field to control power to this port, and + * the core clears this bit on an overcurrent condition." + * + * Input Parameters: + * iface - For future growth to handle multiple USB host interface. + * Should be zero. + * enable - true: enable VBUS power; false: disable VBUS power + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST +void stm32_usbhost_vbusdrive(int iface, bool enable) +{ + DEBUGASSERT(iface == 0); + + /* Set the Power Switch by driving the active high enable pin */ + + stm32_gpiowrite(GPIO_OTGFS_PWRON, enable); +} +#endif + +/**************************************************************************** + * Name: stm32_setup_overcurrent + * + * Description: + * Setup to receive an interrupt-level callback if an overcurrent + * condition is detected. + * + * Input Parameters: + * handler - New overcurrent interrupt handler + * arg - The argument provided for the interrupt handler + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise, a negated errno value + * is returned to indicate the nature of the failure. + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST +int stm32_setup_overcurrent(xcpt_t handler, void *arg) +{ + return stm32_gpiosetevent(GPIO_OTGFS_OVER, true, true, true, handler, arg); +} +#endif + +/**************************************************************************** + * Name: stm32_usbsuspend + * + * Description: + * Board logic must provide the stm32_usbsuspend logic if the USBDEV + * driver is used. This function is called whenever the USB enters or + * leaves suspend mode. This is an opportunity for the board logic to + * shutdown clocks, power, etc. while the USB is suspended. + * + ****************************************************************************/ + +#ifdef CONFIG_USBDEV +void stm32_usbsuspend(struct usbdev_s *dev, bool resume) +{ + uinfo("resume: %d\n", resume); +} +#endif + +#endif /* CONFIG_STM32_OTGFS */ diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_usbmsc.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_usbmsc.c new file mode 100644 index 0000000000000..22c06c5488360 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_usbmsc.c @@ -0,0 +1,61 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_usbmsc.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_usbmsc_initialize + * + * Description: + * Perform architecture specific initialization as needed to establish + * the mass storage device that will be exported by the USB MSC device. + * + ****************************************************************************/ + +int board_usbmsc_initialize(int port) +{ + /* If system/usbmsc is built as an NSH command, then SD slot should + * already have been initialized in board_app_initialize() + * (see stm32_appinit.c). + * In this case, there is nothing further to be done here. + */ + +#ifndef CONFIG_NSH_BUILTIN_APPS + stm32_mmcsd_initialize(0); +#else + return OK; +#endif +} diff --git a/boards/arm/stm32h7/nucleo-h753zi/src/stm32_userleds.c b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_userleds.c new file mode 100644 index 0000000000000..222ccb5c2f286 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h753zi/src/stm32_userleds.c @@ -0,0 +1,129 @@ +/**************************************************************************** + * boards/arm/stm32h7/nucleo-h753zi/src/stm32_userleds.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include +#include + +#include "stm32_gpio.h" +#include "nucleo-h753zi.h" + +#ifndef CONFIG_ARCH_LEDS + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This array maps an LED number to GPIO pin configuration and is indexed by + * BOARD_LED_ + */ + +static const uint32_t g_ledcfg[BOARD_NLEDS] = +{ + GPIO_LED_GREEN, + GPIO_LED_ORANGE, + GPIO_LED_RED, +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_userled_initialize + * + * Description: + * If CONFIG_ARCH_LEDS is defined, then NuttX will control the on-board + * LEDs. If CONFIG_ARCH_LEDS is not defined, then the + * board_userled_initialize() is available to initialize the LED from user + * application logic. + * + ****************************************************************************/ + +uint32_t board_userled_initialize(void) +{ + int i; + + /* Configure LED1-3 GPIOs for output */ + + for (i = 0; i < nitems(g_ledcfg); i++) + { + stm32_configgpio(g_ledcfg[i]); + } + + return BOARD_NLEDS; +} + +/**************************************************************************** + * Name: board_userled + * + * Description: + * If CONFIG_ARCH_LEDS is defined, then NuttX will control the on-board + * LEDs. If CONFIG_ARCH_LEDS is not defined, then the board_userled() is + * available to control the LED from user application logic. + * + ****************************************************************************/ + +void board_userled(int led, bool ledon) +{ + if ((unsigned)led < nitems(g_ledcfg)) + { + stm32_gpiowrite(g_ledcfg[led], ledon); + } +} + +/**************************************************************************** + * Name: board_userled_all + * + * Description: + * If CONFIG_ARCH_LEDS is defined, then NuttX will control the on-board + * LEDs. If CONFIG_ARCH_LEDS is not defined, then board_userled_all() + * is available to control all LEDs from user application logic. + * This function allows controlling multiple LEDs simultaneously using + * a bitmask, which is more efficient than calling board_userled() + * individually for each LED. + * + ****************************************************************************/ + +void board_userled_all(uint32_t ledset) +{ + int i; + + /* Configure LED1-3 GPIOs for output */ + + for (i = 0; i < nitems(g_ledcfg); i++) + { + stm32_gpiowrite(g_ledcfg[i], (ledset & (1 << i)) != 0); + } +} + +#endif /* !CONFIG_ARCH_LEDS */