From e5598c2848ccea041656db9611b9ddbb6cf85072 Mon Sep 17 00:00:00 2001 From: David Sidrane Date: Tue, 14 Mar 2023 06:54:09 -0700 Subject: [PATCH] nxp:imxrt 1060/1170 bifurcation and restructuring --- .../imxrt/include/px4_arch/hw_description.h | 761 ----------- .../px4_arch/io_timer_hw_description.h | 1186 ----------------- .../include/px4_arch/spi_hw_description.h | 140 -- .../src/px4/nxp/imxrt/io_pins/imxrt_pinirq.c | 14 +- .../rt106x/include/px4_arch/hw_description.h | 377 +++++- .../nxp/rt106x/include/px4_arch/io_timer.h | 143 +- .../px4_arch/io_timer_hw_description.h | 591 +++++++- .../include/px4_arch/spi_hw_description.h | 118 +- .../nuttx/src/px4/nxp/rt117x/CMakeLists.txt | 4 +- .../src/px4/nxp/rt117x/adc/CMakeLists.txt | 36 + .../nuttx/src/px4/nxp/rt117x/adc/adc.cpp | 209 +++ .../rt117x/include/px4_arch/hw_description.h | 455 ++++++- .../px4_arch/io_timer_hw_description.h | 1168 +++++++++++++++- .../include/px4_arch/spi_hw_description.h | 112 +- .../src/px4/nxp/rt117x/io_pins/CMakeLists.txt | 44 + .../src/px4/nxp/rt117x/io_pins/imxrt_pinirq.c | 161 +++ .../px4/nxp/rt117x/io_pins/input_capture.c | 325 +++++ .../src/px4/nxp/rt117x/io_pins/io_timer.c | 775 +++++++++++ .../src/px4/nxp/rt117x/io_pins/pwm_servo.c | 165 +++ .../src/px4/nxp/rt117x/io_pins/pwm_trigger.c | 115 ++ 20 files changed, 4752 insertions(+), 2147 deletions(-) delete mode 100644 platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/hw_description.h delete mode 100644 platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/io_timer_hw_description.h delete mode 100644 platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/spi_hw_description.h create mode 100644 platforms/nuttx/src/px4/nxp/rt117x/adc/CMakeLists.txt create mode 100644 platforms/nuttx/src/px4/nxp/rt117x/adc/adc.cpp create mode 100644 platforms/nuttx/src/px4/nxp/rt117x/io_pins/CMakeLists.txt create mode 100644 platforms/nuttx/src/px4/nxp/rt117x/io_pins/imxrt_pinirq.c create mode 100644 platforms/nuttx/src/px4/nxp/rt117x/io_pins/input_capture.c create mode 100644 platforms/nuttx/src/px4/nxp/rt117x/io_pins/io_timer.c create mode 100644 platforms/nuttx/src/px4/nxp/rt117x/io_pins/pwm_servo.c create mode 100644 platforms/nuttx/src/px4/nxp/rt117x/io_pins/pwm_trigger.c diff --git a/platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/hw_description.h b/platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/hw_description.h deleted file mode 100644 index 504b7b6011..0000000000 --- a/platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/hw_description.h +++ /dev/null @@ -1,761 +0,0 @@ -/**************************************************************************** - * - * Copyright (C) 2019 PX4 Development Team. All rights reserved. - * - * 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 PX4 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. - * - ****************************************************************************/ - -#pragma once - - -#include - -#include "hardware/imxrt_flexpwm.h" - -#include - -#include -#if !defined(CONFIG_ARCH_CHIP_MIMXRT1062DVL6A) && !defined(CONFIG_ARCH_CHIP_MIMXRT1176DVMAA) -# error "This code has only been validated with IMXRT1062/IMXRT1176. Make sure it is correct before using it on another board." -#endif - -/* - * PWM - */ - -namespace PWM -{ -enum FlexPWM { - FlexPWM1 = 0, - FlexPWM2, - FlexPWM3, - FlexPWM4, -}; - -enum FlexPWMModule { - PWM1_PWM_A = 0, - PWM1_PWM_B, - PWM1_PWM_X, - - PWM2_PWM_A, - PWM2_PWM_B, - PWM2_PWM_X, - - PWM3_PWM_A, - PWM3_PWM_B, - PWM3_PWM_X, - - PWM4_PWM_A, - PWM4_PWM_B, - PWM4_PWM_X, -}; - -enum FlexPWMSubmodule { - Submodule0 = 0, - Submodule1, - Submodule2, - Submodule3, -}; - -struct FlexPWMConfig { - FlexPWMModule module; - FlexPWMSubmodule submodule; -}; -} - -static inline constexpr uint32_t getFlexPWMBaseRegister(PWM::FlexPWM pwm) -{ - switch (pwm) { - case PWM::FlexPWM1: return IMXRT_FLEXPWM1_BASE; - - case PWM::FlexPWM2: return IMXRT_FLEXPWM2_BASE; - - case PWM::FlexPWM3: return IMXRT_FLEXPWM3_BASE; - - case PWM::FlexPWM4: return IMXRT_FLEXPWM4_BASE; - } - - return 0; -} - - -#ifdef CONFIG_ARCH_FAMILY_IMXRT117x - - -namespace IOMUX -{ -enum class Pad { - GPIO_EMC_B1_00 = 0, - GPIO_EMC_B1_01 = 1, - GPIO_EMC_B1_02 = 2, - GPIO_EMC_B1_03 = 3, - GPIO_EMC_B1_04 = 4, - GPIO_EMC_B1_05 = 5, - GPIO_EMC_B1_06 = 6, - GPIO_EMC_B1_07 = 7, - GPIO_EMC_B1_08 = 8, - GPIO_EMC_B1_09 = 9, - GPIO_EMC_B1_10 = 10, - GPIO_EMC_B1_11 = 11, - GPIO_EMC_B1_12 = 12, - GPIO_EMC_B1_13 = 13, - GPIO_EMC_B1_14 = 14, - GPIO_EMC_B1_15 = 15, - GPIO_EMC_B1_16 = 16, - GPIO_EMC_B1_17 = 17, - GPIO_EMC_B1_18 = 18, - GPIO_EMC_B1_19 = 19, - GPIO_EMC_B1_20 = 20, - GPIO_EMC_B1_21 = 21, - GPIO_EMC_B1_22 = 22, - GPIO_EMC_B1_23 = 23, - GPIO_EMC_B1_24 = 24, - GPIO_EMC_B1_25 = 25, - GPIO_EMC_B1_26 = 26, - GPIO_EMC_B1_27 = 27, - GPIO_EMC_B1_28 = 28, - GPIO_EMC_B1_29 = 29, - GPIO_EMC_B1_30 = 30, - GPIO_EMC_B1_31 = 31, - GPIO_EMC_B1_32 = 32, - GPIO_EMC_B1_33 = 33, - GPIO_EMC_B1_34 = 34, - GPIO_EMC_B1_35 = 35, - GPIO_EMC_B1_36 = 36, - GPIO_EMC_B1_37 = 37, - GPIO_EMC_B1_38 = 38, - GPIO_EMC_B1_39 = 39, - GPIO_EMC_B1_40 = 40, - GPIO_EMC_B1_41 = 41, - GPIO_EMC_B2_00 = 42, - GPIO_EMC_B2_01 = 43, - GPIO_EMC_B2_02 = 44, - GPIO_EMC_B2_03 = 45, - GPIO_EMC_B2_04 = 46, - GPIO_EMC_B2_05 = 47, - GPIO_EMC_B2_06 = 48, - GPIO_EMC_B2_07 = 49, - GPIO_EMC_B2_08 = 50, - GPIO_EMC_B2_09 = 51, - GPIO_EMC_B2_10 = 52, - GPIO_EMC_B2_11 = 53, - GPIO_EMC_B2_12 = 54, - GPIO_EMC_B2_13 = 55, - GPIO_EMC_B2_14 = 56, - GPIO_EMC_B2_15 = 57, - GPIO_EMC_B2_16 = 58, - GPIO_EMC_B2_17 = 59, - GPIO_EMC_B2_18 = 60, - GPIO_EMC_B2_19 = 61, - GPIO_EMC_B2_20 = 62, - GPIO_AD_00 = 63, - GPIO_AD_01 = 64, - GPIO_AD_02 = 65, - GPIO_AD_03 = 66, - GPIO_AD_04 = 67, - GPIO_AD_05 = 68, - GPIO_AD_06 = 69, - GPIO_AD_07 = 70, - GPIO_AD_08 = 71, - GPIO_AD_09 = 72, - GPIO_AD_10 = 73, - GPIO_AD_11 = 74, - GPIO_AD_12 = 75, - GPIO_AD_13 = 76, - GPIO_AD_14 = 77, - GPIO_AD_15 = 78, - GPIO_AD_16 = 79, - GPIO_AD_17 = 80, - GPIO_AD_18 = 81, - GPIO_AD_19 = 82, - GPIO_AD_20 = 83, - GPIO_AD_21 = 84, - GPIO_AD_22 = 85, - GPIO_AD_23 = 86, - GPIO_AD_24 = 87, - GPIO_AD_25 = 88, - GPIO_AD_26 = 89, - GPIO_AD_27 = 90, - GPIO_AD_28 = 91, - GPIO_AD_29 = 92, - GPIO_AD_30 = 93, - GPIO_AD_31 = 94, - GPIO_AD_32 = 95, - GPIO_AD_33 = 96, - GPIO_AD_34 = 97, - GPIO_AD_35 = 98, - GPIO_SD_B1_00 = 99, - GPIO_SD_B1_01 = 100, - GPIO_SD_B1_02 = 101, - GPIO_SD_B1_03 = 102, - GPIO_SD_B1_04 = 103, - GPIO_SD_B1_05 = 104, - GPIO_SD_B2_00 = 105, - GPIO_SD_B2_01 = 106, - GPIO_SD_B2_02 = 107, - GPIO_SD_B2_03 = 108, - GPIO_SD_B2_04 = 109, - GPIO_SD_B2_05 = 110, - GPIO_SD_B2_06 = 111, - GPIO_SD_B2_07 = 112, - GPIO_SD_B2_08 = 113, - GPIO_SD_B2_09 = 114, - GPIO_SD_B2_10 = 115, - GPIO_SD_B2_11 = 116, - GPIO_DISP_B1_00 = 117, - GPIO_DISP_B1_01 = 118, - GPIO_DISP_B1_02 = 119, - GPIO_DISP_B1_03 = 120, - GPIO_DISP_B1_04 = 121, - GPIO_DISP_B1_05 = 122, - GPIO_DISP_B1_06 = 123, - GPIO_DISP_B1_07 = 124, - GPIO_DISP_B1_08 = 125, - GPIO_DISP_B1_09 = 126, - GPIO_DISP_B1_10 = 127, - GPIO_DISP_B1_11 = 128, - GPIO_DISP_B2_00 = 129, - GPIO_DISP_B2_01 = 130, - GPIO_DISP_B2_02 = 131, - GPIO_DISP_B2_03 = 132, - GPIO_DISP_B2_04 = 133, - GPIO_DISP_B2_05 = 134, - GPIO_DISP_B2_06 = 135, - GPIO_DISP_B2_07 = 136, - GPIO_DISP_B2_08 = 137, - GPIO_DISP_B2_09 = 138, - GPIO_DISP_B2_10 = 139, - GPIO_DISP_B2_11 = 140, - GPIO_DISP_B2_12 = 141, - GPIO_DISP_B2_13 = 142, - GPIO_DISP_B2_14 = 143, - GPIO_DISP_B2_15 = 144, - WAKEUP = 145, - PMIC_ON_REQ = 146, - PMIC_STBY_REQ = 147, - GPIO_SNVS_00 = 148, - GPIO_SNVS_01 = 149, - GPIO_SNVS_02 = 150, - GPIO_SNVS_03 = 151, - GPIO_SNVS_04 = 152, - GPIO_SNVS_05 = 153, - GPIO_SNVS_06 = 154, - GPIO_SNVS_07 = 155, - GPIO_SNVS_08 = 156, - GPIO_SNVS_09 = 157, - GPIO_LPSR_00 = 158, - GPIO_LPSR_01 = 159, - GPIO_LPSR_02 = 160, - GPIO_LPSR_03 = 161, - GPIO_LPSR_04 = 162, - GPIO_LPSR_05 = 163, - GPIO_LPSR_06 = 164, - GPIO_LPSR_07 = 165, - GPIO_LPSR_08 = 166, - GPIO_LPSR_09 = 167, - GPIO_LPSR_10 = 168, - GPIO_LPSR_11 = 169, - GPIO_LPSR_12 = 170, - GPIO_LPSR_13 = 171, - GPIO_LPSR_14 = 172, - GPIO_LPSR_15 = 173 -}; - -} - -/* - * GPIO - */ - -namespace GPIO -{ -enum Port { - PortInvalid = 0, - Port1, - Port2, - Port3, - Port4, - Port5, - Port6, - Port7, - Port8, - Port9, - Port10, - Port11, - Port12, - Port13, -}; -enum Pin { - Pin0 = 0, - Pin1, - Pin2, - Pin3, - Pin4, - Pin5, - Pin6, - Pin7, - Pin8, - Pin9, - Pin10, - Pin11, - Pin12, - Pin13, - Pin14, - Pin15, - Pin16, - Pin17, - Pin18, - Pin19, - Pin20, - Pin21, - Pin22, - Pin23, - Pin24, - Pin25, - Pin26, - Pin27, - Pin28, - Pin29, - Pin30, - Pin31, -}; -struct GPIOPin { - Port port; - Pin pin; -}; -} - -static inline constexpr uint32_t getGPIOPort(GPIO::Port port) -{ - switch (port) { - case GPIO::Port1: return GPIO_PORT1; - - case GPIO::Port2: return GPIO_PORT2; - - case GPIO::Port3: return GPIO_PORT3; - - case GPIO::Port4: return GPIO_PORT4; - - case GPIO::Port5: return GPIO_PORT5; - - case GPIO::Port6: return GPIO_PORT6; - - case GPIO::Port7: return GPIO_PORT7; - - case GPIO::Port8: return GPIO_PORT8; - - case GPIO::Port9: return GPIO_PORT9; - - case GPIO::Port10: return GPIO_PORT10; - - case GPIO::Port11: return GPIO_PORT11; - - case GPIO::Port12: return GPIO_PORT12; - - case GPIO::Port13: return GPIO_PORT13; - - default: break; - } - - return 0; -} - -static inline constexpr uint32_t getGPIOPin(GPIO::Pin pin) -{ - switch (pin) { - case GPIO::Pin0: return GPIO_PIN0; - - case GPIO::Pin1: return GPIO_PIN1; - - case GPIO::Pin2: return GPIO_PIN2; - - case GPIO::Pin3: return GPIO_PIN3; - - case GPIO::Pin4: return GPIO_PIN4; - - case GPIO::Pin5: return GPIO_PIN5; - - case GPIO::Pin6: return GPIO_PIN6; - - case GPIO::Pin7: return GPIO_PIN7; - - case GPIO::Pin8: return GPIO_PIN8; - - case GPIO::Pin9: return GPIO_PIN9; - - case GPIO::Pin10: return GPIO_PIN10; - - case GPIO::Pin11: return GPIO_PIN11; - - case GPIO::Pin12: return GPIO_PIN12; - - case GPIO::Pin13: return GPIO_PIN13; - - case GPIO::Pin14: return GPIO_PIN14; - - case GPIO::Pin15: return GPIO_PIN15; - - case GPIO::Pin16: return GPIO_PIN16; - - case GPIO::Pin17: return GPIO_PIN17; - - case GPIO::Pin18: return GPIO_PIN18; - - case GPIO::Pin19: return GPIO_PIN19; - - case GPIO::Pin20: return GPIO_PIN20; - - case GPIO::Pin21: return GPIO_PIN21; - - case GPIO::Pin22: return GPIO_PIN22; - - case GPIO::Pin23: return GPIO_PIN23; - - case GPIO::Pin24: return GPIO_PIN24; - - case GPIO::Pin25: return GPIO_PIN25; - - case GPIO::Pin26: return GPIO_PIN26; - - case GPIO::Pin27: return GPIO_PIN27; - - case GPIO::Pin28: return GPIO_PIN28; - - case GPIO::Pin29: return GPIO_PIN29; - - case GPIO::Pin30: return GPIO_PIN30; - - case GPIO::Pin31: return GPIO_PIN31; - } - - return 0; -} - -#else - -namespace IOMUX -{ -enum class Pad { - GPIO_EMC_00 = 0, - GPIO_EMC_01 = 1, - GPIO_EMC_02 = 2, - GPIO_EMC_03 = 3, - GPIO_EMC_04 = 4, - GPIO_EMC_05 = 5, - GPIO_EMC_06 = 6, - GPIO_EMC_07 = 7, - GPIO_EMC_08 = 8, - GPIO_EMC_09 = 9, - GPIO_EMC_10 = 10, - GPIO_EMC_11 = 11, - GPIO_EMC_12 = 12, - GPIO_EMC_13 = 13, - GPIO_EMC_14 = 14, - GPIO_EMC_15 = 15, - GPIO_EMC_16 = 16, - GPIO_EMC_17 = 17, - GPIO_EMC_18 = 18, - GPIO_EMC_19 = 19, - GPIO_EMC_20 = 20, - GPIO_EMC_21 = 21, - GPIO_EMC_22 = 22, - GPIO_EMC_23 = 23, - GPIO_EMC_24 = 24, - GPIO_EMC_25 = 25, - GPIO_EMC_26 = 26, - GPIO_EMC_27 = 27, - GPIO_EMC_28 = 28, - GPIO_EMC_29 = 29, - GPIO_EMC_30 = 30, - GPIO_EMC_31 = 31, - GPIO_EMC_32 = 32, - GPIO_EMC_33 = 33, - GPIO_EMC_34 = 34, - GPIO_EMC_35 = 35, - GPIO_EMC_36 = 36, - GPIO_EMC_37 = 37, - GPIO_EMC_38 = 38, - GPIO_EMC_39 = 39, - GPIO_EMC_40 = 40, - GPIO_EMC_41 = 41, - GPIO_AD_B0_00 = 42, - GPIO_AD_B0_01 = 43, - GPIO_AD_B0_02 = 44, - GPIO_AD_B0_03 = 45, - GPIO_AD_B0_04 = 46, - GPIO_AD_B0_05 = 47, - GPIO_AD_B0_06 = 48, - GPIO_AD_B0_07 = 49, - GPIO_AD_B0_08 = 50, - GPIO_AD_B0_09 = 51, - GPIO_AD_B0_10 = 52, - GPIO_AD_B0_11 = 53, - GPIO_AD_B0_12 = 54, - GPIO_AD_B0_13 = 55, - GPIO_AD_B0_14 = 56, - GPIO_AD_B0_15 = 57, - GPIO_AD_B1_00 = 58, - GPIO_AD_B1_01 = 59, - GPIO_AD_B1_02 = 60, - GPIO_AD_B1_03 = 61, - GPIO_AD_B1_04 = 62, - GPIO_AD_B1_05 = 63, - GPIO_AD_B1_06 = 64, - GPIO_AD_B1_07 = 65, - GPIO_AD_B1_08 = 66, - GPIO_AD_B1_09 = 67, - GPIO_AD_B1_10 = 68, - GPIO_AD_B1_11 = 69, - GPIO_AD_B1_12 = 70, - GPIO_AD_B1_13 = 71, - GPIO_AD_B1_14 = 72, - GPIO_AD_B1_15 = 73, - GPIO_B0_00 = 74, - GPIO_B0_01 = 75, - GPIO_B0_02 = 76, - GPIO_B0_03 = 77, - GPIO_B0_04 = 78, - GPIO_B0_05 = 79, - GPIO_B0_06 = 80, - GPIO_B0_07 = 81, - GPIO_B0_08 = 82, - GPIO_B0_09 = 83, - GPIO_B0_10 = 84, - GPIO_B0_11 = 85, - GPIO_B0_12 = 86, - GPIO_B0_13 = 87, - GPIO_B0_14 = 88, - GPIO_B0_15 = 89, - GPIO_B1_00 = 90, - GPIO_B1_01 = 91, - GPIO_B1_02 = 92, - GPIO_B1_03 = 93, - GPIO_B1_04 = 94, - GPIO_B1_05 = 95, - GPIO_B1_06 = 96, - GPIO_B1_07 = 97, - GPIO_B1_08 = 98, - GPIO_B1_09 = 99, - GPIO_B1_10 = 100, - GPIO_B1_11 = 101, - GPIO_B1_12 = 102, - GPIO_B1_13 = 103, - GPIO_B1_14 = 104, - GPIO_B1_15 = 105, - GPIO_SD_B0_00 = 106, - GPIO_SD_B0_01 = 107, - GPIO_SD_B0_02 = 108, - GPIO_SD_B0_03 = 109, - GPIO_SD_B0_04 = 110, - GPIO_SD_B0_05 = 111, - GPIO_SD_B1_00 = 112, - GPIO_SD_B1_01 = 113, - GPIO_SD_B1_02 = 114, - GPIO_SD_B1_03 = 115, - GPIO_SD_B1_04 = 116, - GPIO_SD_B1_05 = 117, - GPIO_SD_B1_06 = 118, - GPIO_SD_B1_07 = 119, - GPIO_SD_B1_08 = 120, - GPIO_SD_B1_09 = 121, - GPIO_SD_B1_10 = 122, - GPIO_SD_B1_11 = 123, -}; - -} - -/* - * GPIO - */ - -namespace GPIO -{ -enum Port { - PortInvalid = 0, - Port1, - Port2, - Port3, - Port4, - Port5, -}; -enum Pin { - Pin0 = 0, - Pin1, - Pin2, - Pin3, - Pin4, - Pin5, - Pin6, - Pin7, - Pin8, - Pin9, - Pin10, - Pin11, - Pin12, - Pin13, - Pin14, - Pin15, - Pin16, - Pin17, - Pin18, - Pin19, - Pin20, - Pin21, - Pin22, - Pin23, - Pin24, - Pin25, - Pin26, - Pin27, - Pin28, - Pin29, - Pin30, - Pin31, -}; -struct GPIOPin { - Port port; - Pin pin; -}; -} - -static inline constexpr uint32_t getGPIOPort(GPIO::Port port) -{ - switch (port) { - case GPIO::Port1: return GPIO_PORT1; - - case GPIO::Port2: return GPIO_PORT2; - - case GPIO::Port3: return GPIO_PORT3; - - case GPIO::Port4: return GPIO_PORT4; - - case GPIO::Port5: return GPIO_PORT5; - - default: break; - } - - return 0; -} - -static inline constexpr uint32_t getGPIOPin(GPIO::Pin pin) -{ - switch (pin) { - case GPIO::Pin0: return GPIO_PIN0; - - case GPIO::Pin1: return GPIO_PIN1; - - case GPIO::Pin2: return GPIO_PIN2; - - case GPIO::Pin3: return GPIO_PIN3; - - case GPIO::Pin4: return GPIO_PIN4; - - case GPIO::Pin5: return GPIO_PIN5; - - case GPIO::Pin6: return GPIO_PIN6; - - case GPIO::Pin7: return GPIO_PIN7; - - case GPIO::Pin8: return GPIO_PIN8; - - case GPIO::Pin9: return GPIO_PIN9; - - case GPIO::Pin10: return GPIO_PIN10; - - case GPIO::Pin11: return GPIO_PIN11; - - case GPIO::Pin12: return GPIO_PIN12; - - case GPIO::Pin13: return GPIO_PIN13; - - case GPIO::Pin14: return GPIO_PIN14; - - case GPIO::Pin15: return GPIO_PIN15; - - case GPIO::Pin16: return GPIO_PIN16; - - case GPIO::Pin17: return GPIO_PIN17; - - case GPIO::Pin18: return GPIO_PIN18; - - case GPIO::Pin19: return GPIO_PIN19; - - case GPIO::Pin20: return GPIO_PIN20; - - case GPIO::Pin21: return GPIO_PIN21; - - case GPIO::Pin22: return GPIO_PIN22; - - case GPIO::Pin23: return GPIO_PIN23; - - case GPIO::Pin24: return GPIO_PIN24; - - case GPIO::Pin25: return GPIO_PIN25; - - case GPIO::Pin26: return GPIO_PIN26; - - case GPIO::Pin27: return GPIO_PIN27; - - case GPIO::Pin28: return GPIO_PIN28; - - case GPIO::Pin29: return GPIO_PIN29; - - case GPIO::Pin30: return GPIO_PIN30; - - case GPIO::Pin31: return GPIO_PIN31; - } - - return 0; -} - -#endif - -namespace SPI -{ - -enum class Bus { - LPSPI1 = 1, - LPSPI2, - LPSPI3, - LPSPI4, -#ifdef CONFIG_ARCH_FAMILY_IMXRT117x - LPSPI5, - LPSPI6, -#endif -}; - -using CS = GPIO::GPIOPin; ///< chip-select pin -using DRDY = GPIO::GPIOPin; ///< data ready pin - -struct bus_device_external_cfg_t { - CS cs_gpio; - DRDY drdy_gpio; -}; - -} // namespace SPI diff --git a/platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/io_timer_hw_description.h b/platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/io_timer_hw_description.h deleted file mode 100644 index 545c7587bf..0000000000 --- a/platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/io_timer_hw_description.h +++ /dev/null @@ -1,1186 +0,0 @@ -/**************************************************************************** - * - * Copyright (C) 2019 PX4 Development Team. All rights reserved. - * - * 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 PX4 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. - * - ****************************************************************************/ - -#pragma once - - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#if !defined(CONFIG_ARCH_CHIP_MIMXRT1062DVL6A) && !defined(CONFIG_ARCH_CHIP_MIMXRT1176DVMAA) -# error "This code has only been validated with IMXRT1062/IMXRT1176. Make sure it is correct before using it on another board." -#endif - - -static inline constexpr timer_io_channels_t initIOTimerChannel(const io_timers_t io_timers_conf[MAX_IO_TIMERS], - PWM::FlexPWMConfig pwm_config, IOMUX::Pad pad) -{ - timer_io_channels_t ret{}; - PWM::FlexPWM pwm{}; - - // FlexPWM IMXRT1176 Muxing Options -#ifdef CONFIG_ARCH_FAMILY_IMXRT117x - - switch (pwm_config.module) { - case PWM::PWM1_PWM_A: - pwm = PWM::FlexPWM1; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_EMC_B1_23) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_23_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN23; - - } else if (pad == IOMUX::Pad::GPIO_AD_00) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_00_INDEX); - ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN31; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_EMC_B1_25) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_25_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN25; - - } else if (pad == IOMUX::Pad::GPIO_AD_02) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_02_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN1; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_EMC_B1_27) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_27_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN27; - - } else if (pad == IOMUX::Pad::GPIO_AD_04) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_04_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN3; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_EMC_B1_38) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_38_INDEX); - ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN6; - - } - - break; - } - - break; - - case PWM::PWM1_PWM_B: - pwm = PWM::FlexPWM1; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_EMC_B1_24) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_24_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN24; - - } else if (pad == IOMUX::Pad::GPIO_AD_01) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_01_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN0; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_EMC_B1_26) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_26_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN26; - - } else if (pad == IOMUX::Pad::GPIO_AD_03) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_03_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN2; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_EMC_B1_28) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_28_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN28; - - } else if (pad == IOMUX::Pad::GPIO_AD_05) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_05_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN4; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_EMC_B1_39) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_39_INDEX); - ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN7; - - } - - break; - } - - break; - - case PWM::PWM1_PWM_X: - pwm = PWM::FlexPWM1; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_AD_06) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_06_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN5; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_AD_07) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_07_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN6; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_AD_08) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_08_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN7; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_AD_09) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_09_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN8; - } - - break; - } - - break; - - - case PWM::PWM2_PWM_A: - pwm = PWM::FlexPWM2; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_EMC_B1_06) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_06_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN6; - - } else if (pad == IOMUX::Pad::GPIO_AD_24) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_24_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN23; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_EMC_B1_08) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_08_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN8; - - } else if (pad == IOMUX::Pad::GPIO_AD_26) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_26_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN25; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_EMC_B1_10) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_10_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN10; - - } else if (pad == IOMUX::Pad::GPIO_AD_28) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_28_INDEX); - ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN27; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_EMC_B1_19) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_19_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN19; - - } - - break; - } - - break; - - case PWM::PWM2_PWM_B: - pwm = PWM::FlexPWM2; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_EMC_B1_07) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_07_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN7; - - } else if (pad == IOMUX::Pad::GPIO_AD_25) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_25_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN24; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_EMC_B1_09) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_09_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN9; - - } else if (pad == IOMUX::Pad::GPIO_AD_27) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_27_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN26; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_EMC_B1_11) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_11_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN11; - - } else if (pad == IOMUX::Pad::GPIO_AD_29) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_29_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN28; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_EMC_B1_20) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_20_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN20; - - } - - break; - } - - break; - - case PWM::PWM2_PWM_X: - pwm = PWM::FlexPWM2; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_AD_10) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_10_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN9; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_AD_11) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_11_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN10; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_AD_12) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_12_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN11; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_AD_13) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_13_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN12; - } - - break; - } - - break; - - - case PWM::PWM3_PWM_A: - pwm = PWM::FlexPWM3; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_EMC_B1_29) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_29_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN29; - - } else if (pad == IOMUX::Pad::GPIO_EMC_B2_00) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_00_INDEX); - ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN10; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_EMC_B1_31) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_31_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN31; - - } else if (pad == IOMUX::Pad::GPIO_EMC_B2_02) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_02_INDEX); - ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN12; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_EMC_B1_33) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_33_INDEX); - ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN1; - - } else if (pad == IOMUX::Pad::GPIO_EMC_B2_04) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_04_INDEX); - ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN14; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_EMC_B1_21) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_21_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN21; - - } else if (pad == IOMUX::Pad::GPIO_EMC_B2_06) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_06_INDEX); - ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN16; - } - - break; - } - - break; - - case PWM::PWM3_PWM_B: - pwm = PWM::FlexPWM3; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_EMC_B1_30) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_30_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN30; - - } else if (pad == IOMUX::Pad::GPIO_EMC_B2_01) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_01_INDEX); - ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN11; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_EMC_B1_32) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_32_INDEX); - ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN0; - - } else if (pad == IOMUX::Pad::GPIO_EMC_B2_03) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_03_INDEX); - ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN13; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_EMC_B1_34) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_34_INDEX); - ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN2; - - } else if (pad == IOMUX::Pad::GPIO_EMC_B2_05) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_05_INDEX); - ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN15; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_EMC_B1_22) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_22_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN22; - - } else if (pad == IOMUX::Pad::GPIO_EMC_B2_07) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_07_INDEX); - ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN17; - } - - break; - } - - break; - - - case PWM::PWM3_PWM_X: - pwm = PWM::FlexPWM3; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_AD_14) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_14_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN13; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_AD_15) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_15_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN14; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_AD_16) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_16_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN15; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_AD_17) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_17_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN16; - } - - break; - } - - break; - - case PWM::PWM4_PWM_A: - pwm = PWM::FlexPWM4; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_EMC_B1_00) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_00_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN0; - - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_EMC_B1_02) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_02_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN2; - - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_EMC_B1_04) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_04_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN4; - - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_EMC_B1_17) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_17_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN17; - - } - - break; - } - - break; - - case PWM::PWM4_PWM_B: - pwm = PWM::FlexPWM4; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_EMC_B1_01) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_01_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN1; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_EMC_B1_03) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_03_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN3; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_EMC_B1_05) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_05_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN5; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_EMC_B1_18) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_18_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN18; - } - - break; - } - - break; - - - case PWM::PWM4_PWM_X: - pwm = PWM::FlexPWM4; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_AD_18) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_18_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN17; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_AD_19) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_19_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN18; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_AD_20) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_20_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN19; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_AD_21) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_21_INDEX); - ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN20; - } - - break; - } - - break; - } - - constexpr_assert(ret.gpio_out != 0, "Invalid PWM/Pad config"); - ret.gpio_out |= IOMUX_CMOS_OUTPUT | IOMUX_PULL_NONE | IOMUX_DRIVE_HIGHSTRENGTH | IOMUX_SLEW_FAST; -#else - - switch (pwm_config.module) { - case PWM::PWM1_PWM_A: - pwm = PWM::FlexPWM1; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_EMC_23) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_23_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN23; - - } else if (pad == IOMUX::Pad::GPIO_SD_B0_00) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_00_INDEX); - ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN12; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_EMC_25) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_25_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN25; - - } else if (pad == IOMUX::Pad::GPIO_SD_B0_02) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_02_INDEX); - ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN14; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_EMC_27) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_27_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN27; - - } else if (pad == IOMUX::Pad::GPIO_SD_B0_04) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_04_INDEX); - ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN16; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_EMC_38) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_38_INDEX); - ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN24; - - } else if (pad == IOMUX::Pad::GPIO_SD_B1_00) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B1_00_INDEX); - ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN0; - - } else if (pad == IOMUX::Pad::GPIO_AD_B0_10) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_10_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN10; - - } else if (pad == IOMUX::Pad::GPIO_EMC_12) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_12_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN12; - - } else if (pad == IOMUX::Pad::GPIO_B1_00) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT6 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_00_INDEX); - ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN16; - } - - break; - } - - break; - - case PWM::PWM1_PWM_B: - pwm = PWM::FlexPWM1; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_EMC_24) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_24_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN24; - - } else if (pad == IOMUX::Pad::GPIO_SD_B0_01) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_01_INDEX); - ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN13; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_EMC_26) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_26_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN26; - - } else if (pad == IOMUX::Pad::GPIO_SD_B0_03) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_03_INDEX); - ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN15; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_EMC_28) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_28_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN28; - - } else if (pad == IOMUX::Pad::GPIO_SD_B0_05) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_05_INDEX); - ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN17; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_EMC_39) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_39_INDEX); - ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN25; - - } else if (pad == IOMUX::Pad::GPIO_SD_B1_01) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B1_01_INDEX); - ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN1; - - } else if (pad == IOMUX::Pad::GPIO_AD_B0_11) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_11_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN11; - - } else if (pad == IOMUX::Pad::GPIO_EMC_13) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_13_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN13; - - } else if (pad == IOMUX::Pad::GPIO_B1_01) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT6 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_01_INDEX); - ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN17; - } - - break; - } - - break; - - case PWM::PWM1_PWM_X: - pwm = PWM::FlexPWM1; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_AD_B0_02) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_02_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN2; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_AD_B0_03) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_03_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN3; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_AD_B0_12) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_12_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN12; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_AD_B0_13) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_13_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN13; - } - - break; - } - - break; - - - case PWM::PWM2_PWM_A: - pwm = PWM::FlexPWM2; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_B0_06) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_06_INDEX); - ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN6; - - } else if (pad == IOMUX::Pad::GPIO_EMC_06) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_06_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN6; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_EMC_08) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_08_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN8; - - } else if (pad == IOMUX::Pad::GPIO_B0_08) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_08_INDEX); - ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN8; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_EMC_10) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_10_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN10; - - } else if (pad == IOMUX::Pad::GPIO_B0_10) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_10_INDEX); - ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN10; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_AD_B0_09) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_09_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN9; - - } else if (pad == IOMUX::Pad::GPIO_SD_B1_02) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B1_02_INDEX); - ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN2; - - } else if (pad == IOMUX::Pad::GPIO_EMC_19) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_19_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN19; - - } else if (pad == IOMUX::Pad::GPIO_B1_02) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT6 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_02_INDEX); - ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN18; - - } else if (pad == IOMUX::Pad::GPIO_AD_B0_00) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT0 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_00_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN0; - } - - break; - } - - break; - - case PWM::PWM2_PWM_B: - pwm = PWM::FlexPWM2; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_B0_07) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_07_INDEX); - ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN6; - - } else if (pad == IOMUX::Pad::GPIO_EMC_07) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_07_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN6; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_EMC_09) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_09_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN8; - - } else if (pad == IOMUX::Pad::GPIO_B0_09) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_09_INDEX); - ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN8; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_EMC_11) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_11_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN10; - - } else if (pad == IOMUX::Pad::GPIO_B0_11) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_11_INDEX); - ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN10; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_AD_B0_01) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT0 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_01_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN1; - - } else if (pad == IOMUX::Pad::GPIO_SD_B1_03) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B1_03_INDEX); - ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN3; - - } else if (pad == IOMUX::Pad::GPIO_EMC_20) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_20_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN20; - - } else if (pad == IOMUX::Pad::GPIO_B1_03) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT6 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_03_INDEX); - ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN19; - } - - break; - } - - break; - - - case PWM::PWM3_PWM_A: - pwm = PWM::FlexPWM3; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_EMC_29) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_29_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN29; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_EMC_31) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_31_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN31; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_EMC_33) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_33_INDEX); - ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN19; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_EMC_21) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_21_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN21; - } - - break; - } - - break; - - case PWM::PWM3_PWM_B: - pwm = PWM::FlexPWM3; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_EMC_30) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_30_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN30; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_EMC_32) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_32_INDEX); - ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN18; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_EMC_34) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_34_INDEX); - ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN20; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_EMC_22) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_22_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN22; - } - - break; - } - - break; - - - case PWM::PWM4_PWM_A: - pwm = PWM::FlexPWM4; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_AD_B1_08) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_08_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN24; - - } else if (pad == IOMUX::Pad::GPIO_EMC_00) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_00_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN0; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_EMC_02) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_02_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN2; - - } else if (pad == IOMUX::Pad::GPIO_AD_B1_09) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_09_INDEX); - ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN25; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_EMC_04) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_04_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN4; - - } else if (pad == IOMUX::Pad::GPIO_B1_14) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_14_INDEX); - ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN30; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_EMC_17) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_17_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN17; - - } else if (pad == IOMUX::Pad::GPIO_B1_15) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_15_INDEX); - ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN31; - } - - break; - } - - break; - - case PWM::PWM4_PWM_B: - pwm = PWM::FlexPWM4; - - switch (pwm_config.submodule) { - case PWM::Submodule0: - if (pad == IOMUX::Pad::GPIO_EMC_01) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_01_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN1; - } - - break; - - case PWM::Submodule1: - if (pad == IOMUX::Pad::GPIO_EMC_03) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_03_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN3; - } - - break; - - case PWM::Submodule2: - if (pad == IOMUX::Pad::GPIO_EMC_05) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_05_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN5; - } - - break; - - case PWM::Submodule3: - if (pad == IOMUX::Pad::GPIO_EMC_18) { - ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_18_INDEX); - ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN18; - } - - break; - } - - break; - } - - constexpr_assert(ret.gpio_out != 0, "Invalid PWM/Pad config"); - ret.gpio_out |= IOMUX_CMOS_OUTPUT | IOMUX_PULL_NONE | IOMUX_DRIVE_50OHM | IOMUX_SPEED_MEDIUM | IOMUX_SLEW_FAST; -#endif - - switch (pwm_config.module) { - case PWM::PWM1_PWM_A: - case PWM::PWM2_PWM_A: - case PWM::PWM3_PWM_A: - case PWM::PWM4_PWM_A: - ret.val_offset = PWMA_VAL; - break; - - case PWM::PWM1_PWM_B: - case PWM::PWM2_PWM_B: - case PWM::PWM3_PWM_B: - case PWM::PWM4_PWM_B: - ret.val_offset = PWMB_VAL; - break; - - case PWM::PWM1_PWM_X: - case PWM::PWM2_PWM_X: - case PWM::PWM3_PWM_X: - case PWM::PWM4_PWM_X: - ret.val_offset = PWMX_VAL; - break; - - default: - constexpr_assert(false, "not implemented"); - } - - switch (pwm_config.submodule) { - case PWM::Submodule0: - ret.sub_module = SM0; - ret.sub_module_bits = MCTRL_LDOK(1 << SM0); - break; - - case PWM::Submodule1: - ret.sub_module = SM1; - ret.sub_module_bits = MCTRL_LDOK(1 << SM1); - break; - - case PWM::Submodule2: - ret.sub_module = SM2; - ret.sub_module_bits = MCTRL_LDOK(1 << SM2); - break; - - case PWM::Submodule3: - ret.sub_module = SM3; - ret.sub_module_bits = MCTRL_LDOK(1 << SM3); - break; - } - - ret.gpio_in = 0; // TODO (not used yet) - - // find timer index - ret.timer_index = 0xff; - const uint32_t timer_base = getFlexPWMBaseRegister(pwm); - - for (int i = 0; i < MAX_IO_TIMERS; ++i) { - if (io_timers_conf[i].base == timer_base && io_timers_conf[i].submodle == ret.sub_module) { - ret.timer_index = i; - break; - } - } - - constexpr_assert(ret.timer_index != 0xff, "Timer not found"); - return ret; -} - -static inline constexpr io_timers_t initIOPWM(PWM::FlexPWM pwm, PWM::FlexPWMSubmodule sub) -{ - io_timers_t ret{}; - - ret.base = getFlexPWMBaseRegister(pwm); - ret.submodle = sub; - return ret; -} diff --git a/platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/spi_hw_description.h b/platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/spi_hw_description.h deleted file mode 100644 index 0dda27e8b9..0000000000 --- a/platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/spi_hw_description.h +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************** - * - * Copyright (C) 2020 PX4 Development Team. All rights reserved. - * - * 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 PX4 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. - * - ****************************************************************************/ - -#pragma once - -#include -#include - -#if defined(CONFIG_SPI) - -#include - -//#define CS_IOMUX (IOMUX_CMOS_OUTPUT | IOMUX_PULL_UP_100K | IOMUX_DRIVE_33OHM | IOMUX_SPEED_LOW | IOMUX_SLEW_FAST) - -#define DRDY_IOMUX (IOMUX_PULL_UP | IOMUX_DRIVE_HIGHSTRENGTH) - -//#define GENERAL_OUTPUT_IOMUX (IOMUX_CMOS_OUTPUT | IOMUX_PULL_KEEP | IOMUX_DRIVE_33OHM | IOMUX_SPEED_MEDIUM | IOMUX_SLEW_FAST) - -static inline constexpr px4_spi_bus_device_t initSPIDevice(uint32_t devid, SPI::CS cs_gpio, SPI::DRDY drdy_gpio = {}) -{ - px4_spi_bus_device_t ret{}; - ret.cs_gpio = getGPIOPort(cs_gpio.port) | getGPIOPin(cs_gpio.pin) | (GPIO_OUTPUT | GPIO_OUTPUT_ONE | CS_IOMUX); - - if (drdy_gpio.port != GPIO::PortInvalid) { - ret.drdy_gpio = getGPIOPort(drdy_gpio.port) | getGPIOPin(drdy_gpio.pin) | (GPIO_INPUT | DRDY_IOMUX); - } - - if (PX4_SPIDEVID_TYPE(devid) == 0) { // it's a PX4 device (internal or external) - ret.devid = PX4_SPIDEV_ID(PX4_SPI_DEVICE_ID, devid); - - } else { // it's a NuttX device (e.g. SPIDEV_FLASH(0)) - ret.devid = devid; - } - - ret.devtype_driver = PX4_SPI_DEV_ID(devid); - return ret; -} - -static inline constexpr px4_spi_bus_t initSPIBus(SPI::Bus bus, const px4_spi_bus_devices_t &devices, - GPIO::GPIOPin power_enable = {}) -{ - px4_spi_bus_t ret{}; - ret.requires_locking = false; - - for (int i = 0; i < SPI_BUS_MAX_DEVICES; ++i) { - ret.devices[i] = devices.devices[i]; - - - if (ret.devices[i].cs_gpio != 0) { - if (PX4_SPI_DEVICE_ID == PX4_SPIDEVID_TYPE(ret.devices[i].devid)) { - int same_devices_count = 0; - - for (int j = 0; j < i; ++j) { - if (ret.devices[j].cs_gpio != 0) { - same_devices_count += (ret.devices[i].devid & 0xff) == (ret.devices[j].devid & 0xff); - } - } - - // increment the 2. LSB byte to allow multiple devices of the same type - ret.devices[i].devid |= same_devices_count << 8; - - } else { - // A bus potentially requires locking if it is accessed by non-PX4 devices (i.e. NuttX drivers) - ret.requires_locking = true; - } - } - } - - ret.bus = (int)bus; - ret.is_external = false; - - if (power_enable.port != GPIO::PortInvalid) { - ret.power_enable_gpio = getGPIOPort(power_enable.port) | getGPIOPin(power_enable.pin) | - (GPIO_OUTPUT | GPIO_OUTPUT_ZERO | GENERAL_OUTPUT_IOMUX); - } - - return ret; -} - -// just a wrapper since we cannot pass brace-enclosed initialized arrays directly as arguments -struct bus_device_external_cfg_array_t { - SPI::bus_device_external_cfg_t devices[SPI_BUS_MAX_DEVICES]; -}; - -static inline constexpr px4_spi_bus_t initSPIBusExternal(SPI::Bus bus, const bus_device_external_cfg_array_t &devices) -{ - px4_spi_bus_t ret{}; - - for (int i = 0; i < SPI_BUS_MAX_DEVICES; ++i) { - if (devices.devices[i].cs_gpio.port == GPIO::PortInvalid) { - break; - } - - ret.devices[i] = initSPIDevice(i, devices.devices[i].cs_gpio, devices.devices[i].drdy_gpio); - } - - ret.bus = (int)bus; - ret.is_external = true; - ret.requires_locking = false; // external buses are never accessed by NuttX drivers - return ret; -} - -static inline constexpr SPI::bus_device_external_cfg_t initSPIConfigExternal(SPI::CS cs_gpio, SPI::DRDY drdy_gpio = {}) -{ - SPI::bus_device_external_cfg_t ret{}; - ret.cs_gpio = cs_gpio; - ret.drdy_gpio = drdy_gpio; - return ret; -} -#endif // CONFIG_SPI diff --git a/platforms/nuttx/src/px4/nxp/imxrt/io_pins/imxrt_pinirq.c b/platforms/nuttx/src/px4/nxp/imxrt/io_pins/imxrt_pinirq.c index a993460f6f..8d89c6d452 100644 --- a/platforms/nuttx/src/px4/nxp/imxrt/io_pins/imxrt_pinirq.c +++ b/platforms/nuttx/src/px4/nxp/imxrt/io_pins/imxrt_pinirq.c @@ -47,14 +47,12 @@ typedef struct { int hi; } lh_t; -const lh_t port_to_irq[8] = { - {_IMXRT_GPIO1_0_15_BASE, _IMXRT_GPIO1_16_31_BASE}, - {_IMXRT_GPIO2_0_15_BASE, _IMXRT_GPIO2_16_31_BASE}, - {_IMXRT_GPIO3_0_15_BASE, _IMXRT_GPIO3_16_31_BASE}, - {_IMXRT_GPIO4_0_15_BASE, _IMXRT_GPIO4_16_31_BASE}, - {_IMXRT_GPIO5_0_15_BASE, _IMXRT_GPIO5_16_31_BASE}, - {_IMXRT_GPIO6_0_15_BASE, _IMXRT_GPIO6_16_31_BASE}, - {_IMXRT_GPIO13_BASE, _IMXRT_GPIO13_BASE}, //FIXME +const lh_t port_to_irq[9] = { + {_IMXRT_GPIO1_0_15_BASE, _IMXRT_GPIO1_16_31_BASE}, {_IMXRT_GPIO2_0_15_BASE, _IMXRT_GPIO2_16_31_BASE}, + {_IMXRT_GPIO3_0_15_BASE, _IMXRT_GPIO3_16_31_BASE}, {_IMXRT_GPIO4_0_15_BASE, _IMXRT_GPIO4_16_31_BASE}, + {_IMXRT_GPIO5_0_15_BASE, _IMXRT_GPIO5_16_31_BASE}, {_IMXRT_GPIO6_0_15_BASE, _IMXRT_GPIO6_16_31_BASE}, + {_IMXRT_GPIO7_0_15_BASE, _IMXRT_GPIO7_16_31_BASE}, {_IMXRT_GPIO8_0_15_BASE, _IMXRT_GPIO8_16_31_BASE}, + {_IMXRT_GPIO9_0_15_BASE, _IMXRT_GPIO9_16_31_BASE}, }; /**************************************************************************** diff --git a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/hw_description.h b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/hw_description.h index e7676690b9..d4aada2ffe 100644 --- a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/hw_description.h +++ b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/hw_description.h @@ -1,20 +1,20 @@ /**************************************************************************** * - * Copyright (c) 2019 PX4 Development Team. All rights reserved. + * Copyright (C) 2019 PX4 Development Team. All rights reserved. * * 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. + * 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. + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. * 3. Neither the name PX4 nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. + * 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 @@ -30,7 +30,368 @@ * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ + #pragma once -#include "../../../imxrt/include/px4_arch/hw_description.h" +#include + +#include "hardware/imxrt_flexpwm.h" + +#include + +#include +#ifndef CONFIG_ARCH_CHIP_MIMXRT1062DVL6A +# error "This code has only been validated with IMXRT1062. Make sure it is correct before using it on another board." +#endif + +/* + * PWM + */ + +namespace PWM +{ +enum FlexPWM { + FlexPWM1 = 0, + FlexPWM2, + FlexPWM3, + FlexPWM4, +}; + +enum FlexPWMModule { + PWM1_PWM_A = 0, + PWM1_PWM_B, + PWM1_PWM_X, + + PWM2_PWM_A, + PWM2_PWM_B, + + PWM3_PWM_A, + PWM3_PWM_B, + + PWM4_PWM_A, + PWM4_PWM_B, +}; + +enum FlexPWMSubmodule { + Submodule0 = 0, + Submodule1, + Submodule2, + Submodule3, +}; + +struct FlexPWMConfig { + FlexPWMModule module; + FlexPWMSubmodule submodule; +}; +} + +static inline constexpr uint32_t getFlexPWMBaseRegister(PWM::FlexPWM pwm) +{ + switch (pwm) { + case PWM::FlexPWM1: return IMXRT_FLEXPWM1_BASE; + + case PWM::FlexPWM2: return IMXRT_FLEXPWM2_BASE; + + case PWM::FlexPWM3: return IMXRT_FLEXPWM3_BASE; + + case PWM::FlexPWM4: return IMXRT_FLEXPWM4_BASE; + } + + return 0; +} + +namespace IOMUX +{ +enum class Pad { + GPIO_EMC_00 = 0, + GPIO_EMC_01 = 1, + GPIO_EMC_02 = 2, + GPIO_EMC_03 = 3, + GPIO_EMC_04 = 4, + GPIO_EMC_05 = 5, + GPIO_EMC_06 = 6, + GPIO_EMC_07 = 7, + GPIO_EMC_08 = 8, + GPIO_EMC_09 = 9, + GPIO_EMC_10 = 10, + GPIO_EMC_11 = 11, + GPIO_EMC_12 = 12, + GPIO_EMC_13 = 13, + GPIO_EMC_14 = 14, + GPIO_EMC_15 = 15, + GPIO_EMC_16 = 16, + GPIO_EMC_17 = 17, + GPIO_EMC_18 = 18, + GPIO_EMC_19 = 19, + GPIO_EMC_20 = 20, + GPIO_EMC_21 = 21, + GPIO_EMC_22 = 22, + GPIO_EMC_23 = 23, + GPIO_EMC_24 = 24, + GPIO_EMC_25 = 25, + GPIO_EMC_26 = 26, + GPIO_EMC_27 = 27, + GPIO_EMC_28 = 28, + GPIO_EMC_29 = 29, + GPIO_EMC_30 = 30, + GPIO_EMC_31 = 31, + GPIO_EMC_32 = 32, + GPIO_EMC_33 = 33, + GPIO_EMC_34 = 34, + GPIO_EMC_35 = 35, + GPIO_EMC_36 = 36, + GPIO_EMC_37 = 37, + GPIO_EMC_38 = 38, + GPIO_EMC_39 = 39, + GPIO_EMC_40 = 40, + GPIO_EMC_41 = 41, + GPIO_AD_B0_00 = 42, + GPIO_AD_B0_01 = 43, + GPIO_AD_B0_02 = 44, + GPIO_AD_B0_03 = 45, + GPIO_AD_B0_04 = 46, + GPIO_AD_B0_05 = 47, + GPIO_AD_B0_06 = 48, + GPIO_AD_B0_07 = 49, + GPIO_AD_B0_08 = 50, + GPIO_AD_B0_09 = 51, + GPIO_AD_B0_10 = 52, + GPIO_AD_B0_11 = 53, + GPIO_AD_B0_12 = 54, + GPIO_AD_B0_13 = 55, + GPIO_AD_B0_14 = 56, + GPIO_AD_B0_15 = 57, + GPIO_AD_B1_00 = 58, + GPIO_AD_B1_01 = 59, + GPIO_AD_B1_02 = 60, + GPIO_AD_B1_03 = 61, + GPIO_AD_B1_04 = 62, + GPIO_AD_B1_05 = 63, + GPIO_AD_B1_06 = 64, + GPIO_AD_B1_07 = 65, + GPIO_AD_B1_08 = 66, + GPIO_AD_B1_09 = 67, + GPIO_AD_B1_10 = 68, + GPIO_AD_B1_11 = 69, + GPIO_AD_B1_12 = 70, + GPIO_AD_B1_13 = 71, + GPIO_AD_B1_14 = 72, + GPIO_AD_B1_15 = 73, + GPIO_B0_00 = 74, + GPIO_B0_01 = 75, + GPIO_B0_02 = 76, + GPIO_B0_03 = 77, + GPIO_B0_04 = 78, + GPIO_B0_05 = 79, + GPIO_B0_06 = 80, + GPIO_B0_07 = 81, + GPIO_B0_08 = 82, + GPIO_B0_09 = 83, + GPIO_B0_10 = 84, + GPIO_B0_11 = 85, + GPIO_B0_12 = 86, + GPIO_B0_13 = 87, + GPIO_B0_14 = 88, + GPIO_B0_15 = 89, + GPIO_B1_00 = 90, + GPIO_B1_01 = 91, + GPIO_B1_02 = 92, + GPIO_B1_03 = 93, + GPIO_B1_04 = 94, + GPIO_B1_05 = 95, + GPIO_B1_06 = 96, + GPIO_B1_07 = 97, + GPIO_B1_08 = 98, + GPIO_B1_09 = 99, + GPIO_B1_10 = 100, + GPIO_B1_11 = 101, + GPIO_B1_12 = 102, + GPIO_B1_13 = 103, + GPIO_B1_14 = 104, + GPIO_B1_15 = 105, + GPIO_SD_B0_00 = 106, + GPIO_SD_B0_01 = 107, + GPIO_SD_B0_02 = 108, + GPIO_SD_B0_03 = 109, + GPIO_SD_B0_04 = 110, + GPIO_SD_B0_05 = 111, + GPIO_SD_B1_00 = 112, + GPIO_SD_B1_01 = 113, + GPIO_SD_B1_02 = 114, + GPIO_SD_B1_03 = 115, + GPIO_SD_B1_04 = 116, + GPIO_SD_B1_05 = 117, + GPIO_SD_B1_06 = 118, + GPIO_SD_B1_07 = 119, + GPIO_SD_B1_08 = 120, + GPIO_SD_B1_09 = 121, + GPIO_SD_B1_10 = 122, + GPIO_SD_B1_11 = 123, +}; + +} + +/* + * GPIO + */ + +namespace GPIO +{ +enum Port { + PortInvalid = 0, + Port1, + Port2, + Port3, + Port4, + Port5, +}; +enum Pin { + Pin0 = 0, + Pin1, + Pin2, + Pin3, + Pin4, + Pin5, + Pin6, + Pin7, + Pin8, + Pin9, + Pin10, + Pin11, + Pin12, + Pin13, + Pin14, + Pin15, + Pin16, + Pin17, + Pin18, + Pin19, + Pin20, + Pin21, + Pin22, + Pin23, + Pin24, + Pin25, + Pin26, + Pin27, + Pin28, + Pin29, + Pin30, + Pin31, +}; +struct GPIOPin { + Port port; + Pin pin; +}; +} + +static inline constexpr uint32_t getGPIOPort(GPIO::Port port) +{ + switch (port) { + case GPIO::Port1: return GPIO_PORT1; + + case GPIO::Port2: return GPIO_PORT2; + + case GPIO::Port3: return GPIO_PORT3; + + case GPIO::Port4: return GPIO_PORT4; + + case GPIO::Port5: return GPIO_PORT5; + + default: break; + } + + return 0; +} + +static inline constexpr uint32_t getGPIOPin(GPIO::Pin pin) +{ + switch (pin) { + case GPIO::Pin0: return GPIO_PIN0; + + case GPIO::Pin1: return GPIO_PIN1; + + case GPIO::Pin2: return GPIO_PIN2; + + case GPIO::Pin3: return GPIO_PIN3; + + case GPIO::Pin4: return GPIO_PIN4; + + case GPIO::Pin5: return GPIO_PIN5; + + case GPIO::Pin6: return GPIO_PIN6; + + case GPIO::Pin7: return GPIO_PIN7; + + case GPIO::Pin8: return GPIO_PIN8; + + case GPIO::Pin9: return GPIO_PIN9; + + case GPIO::Pin10: return GPIO_PIN10; + + case GPIO::Pin11: return GPIO_PIN11; + + case GPIO::Pin12: return GPIO_PIN12; + + case GPIO::Pin13: return GPIO_PIN13; + + case GPIO::Pin14: return GPIO_PIN14; + + case GPIO::Pin15: return GPIO_PIN15; + + case GPIO::Pin16: return GPIO_PIN16; + + case GPIO::Pin17: return GPIO_PIN17; + + case GPIO::Pin18: return GPIO_PIN18; + + case GPIO::Pin19: return GPIO_PIN19; + + case GPIO::Pin20: return GPIO_PIN20; + + case GPIO::Pin21: return GPIO_PIN21; + + case GPIO::Pin22: return GPIO_PIN22; + + case GPIO::Pin23: return GPIO_PIN23; + + case GPIO::Pin24: return GPIO_PIN24; + + case GPIO::Pin25: return GPIO_PIN25; + + case GPIO::Pin26: return GPIO_PIN26; + + case GPIO::Pin27: return GPIO_PIN27; + + case GPIO::Pin28: return GPIO_PIN28; + + case GPIO::Pin29: return GPIO_PIN29; + + case GPIO::Pin30: return GPIO_PIN30; + + case GPIO::Pin31: return GPIO_PIN31; + } + + return 0; +} + +namespace SPI +{ + +enum class Bus { + LPSPI1 = 1, + LPSPI2, + LPSPI3, + LPSPI4, +}; + +using CS = GPIO::GPIOPin; ///< chip-select pin +using DRDY = GPIO::GPIOPin; ///< data ready pin + +struct bus_device_external_cfg_t { + CS cs_gpio; + DRDY drdy_gpio; +}; + +} // namespace SPI diff --git a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/io_timer.h b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/io_timer.h index 328ac3eddf..613ac1b197 100644 --- a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/io_timer.h +++ b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/io_timer.h @@ -1,6 +1,6 @@ /**************************************************************************** * - * Copyright (c) 2019 PX4 Development Team. All rights reserved. + * Copyright (C) 2018 PX4 Development Team. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,7 +30,146 @@ * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ + +/** + * @file drv_io_timer.h + * + * imxrt-specific PWM output data. + */ +#include +#include +#include + +#include + #pragma once +__BEGIN_DECLS +/* configuration limits */ +#ifdef BOARD_NUM_IO_TIMERS +#define MAX_IO_TIMERS BOARD_NUM_IO_TIMERS +#else +#define MAX_IO_TIMERS 4 +#endif +#define MAX_TIMER_IO_CHANNELS 16 + +#define MAX_LED_TIMERS 2 +#define MAX_TIMER_LED_CHANNELS 6 + +#define IO_TIMER_ALL_MODES_CHANNELS 0 + +typedef enum io_timer_channel_mode_t { + IOTimerChanMode_NotUsed = 0, + IOTimerChanMode_PWMOut = 1, + IOTimerChanMode_PWMIn = 2, + IOTimerChanMode_Capture = 3, + IOTimerChanMode_OneShot = 4, + IOTimerChanMode_Trigger = 5, + IOTimerChanMode_Dshot = 6, + IOTimerChanMode_LED = 7, + IOTimerChanMode_PPS = 8, + IOTimerChanMode_Other = 9, + IOTimerChanModeSize +} io_timer_channel_mode_t; + +typedef uint16_t io_timer_channel_allocation_t; /* big enough to hold MAX_TIMER_IO_CHANNELS */ + +/* array of timers dedicated to PWM in and out and TBD capture use + *** Timers are driven from QTIMER3_OUT0 + *** In PWM mode the timer's prescaler is set to achieve a counter frequency of 1MHz + *** In OneShot mode the timer's prescaler is set to achieve a counter frequency of 8MHz + *** Other prescaler rates can be achieved by fore instance by setting the clock_freq = 1Mhz + *** the resulting PSC will be one and the timer will count at it's clock frequency. + */ +typedef struct io_timers_t { + uint32_t base; /* Base address of the timer */ + uint32_t submodle; /* Which Submodule */ + uint32_t clock_register; /* SIM_SCGCn */ + uint32_t clock_bit; /* SIM_SCGCn bit pos */ + uint32_t vectorno; /* IRQ number */ +} io_timers_t; + +typedef struct io_timers_channel_mapping_element_t { + uint32_t first_channel_index; + uint32_t channel_count; + uint32_t lowest_timer_channel; + uint32_t channel_count_including_gaps; +} io_timers_channel_mapping_element_t; + +/* mapping for each io_timers to timer_io_channels */ +typedef struct io_timers_channel_mapping_t { + io_timers_channel_mapping_element_t element[MAX_IO_TIMERS]; +} io_timers_channel_mapping_t; + +/* array of channels in logical order */ +typedef struct timer_io_channels_t { + uint32_t gpio_out; /* The timer valn_offset GPIO for PWM (this is the IOMUX Pad, e.g. PWM_IOMUX | GPIO_FLEXPWM2_PWMA00_2) */ + uint32_t gpio_in; /* The timer valn_offset GPIO for Capture */ + uint32_t gpio_portpin; /* The GPIO Port + Pin (e.g. GPIO_PORT2 | GPIO_PIN6) */ + uint8_t timer_index; /* 0 based index in the io_timers_t table */ + uint8_t val_offset; /* IMXRT_FLEXPWM_SM0VAL3_OFFSET or IMXRT_FLEXPWM_SM0VAL5_OFFSET */ + uint8_t sub_module; /* 0 based sub module offset */ + uint8_t sub_module_bits; /* LDOK and CLDOK bits */ + uint8_t timer_channel; /* Unused */ +} timer_io_channels_t; + +#define SM0 0 +#define SM1 1 +#define SM2 2 +#define SM3 3 + +#define PWMA_VAL IMXRT_FLEXPWM_SM0VAL3_OFFSET +#define PWMB_VAL IMXRT_FLEXPWM_SM0VAL5_OFFSET -#include "../../../imxrt/include/px4_arch/io_timer.h" +typedef void (*channel_handler_t)(void *context, const io_timers_t *timer, uint32_t chan_index, + const timer_io_channels_t *chan, + hrt_abstime isrs_time, uint16_t isrs_rcnt, + uint16_t capture); + + +/* supplied by board-specific code */ +__EXPORT extern const io_timers_t io_timers[MAX_IO_TIMERS]; +__EXPORT extern const io_timers_channel_mapping_t io_timers_channel_mapping; +__EXPORT extern const timer_io_channels_t timer_io_channels[MAX_TIMER_IO_CHANNELS]; + +__EXPORT extern const io_timers_t led_pwm_timers[MAX_LED_TIMERS]; +__EXPORT extern const timer_io_channels_t led_pwm_channels[MAX_TIMER_LED_CHANNELS]; + +__EXPORT int io_timer_channel_init(unsigned channel, io_timer_channel_mode_t mode, + channel_handler_t channel_handler, void *context); + +__EXPORT int io_timer_init_timer(unsigned timer, io_timer_channel_mode_t mode); + +__EXPORT int io_timer_set_pwm_rate(unsigned timer, unsigned rate); +__EXPORT int io_timer_set_enable(bool state, io_timer_channel_mode_t mode, + io_timer_channel_allocation_t masks); +__EXPORT uint16_t io_channel_get_ccr(unsigned channel); +__EXPORT int io_timer_set_ccr(unsigned channel, uint16_t value); +__EXPORT uint32_t io_timer_get_group(unsigned timer); +__EXPORT int io_timer_validate_channel_index(unsigned channel); +__EXPORT int io_timer_allocate_channel(unsigned channel, io_timer_channel_mode_t mode); +__EXPORT int io_timer_unallocate_channel(unsigned channel); +__EXPORT int io_timer_get_channel_mode(unsigned channel); +__EXPORT int io_timer_get_mode_channels(io_timer_channel_mode_t mode); +__EXPORT extern void io_timer_trigger(unsigned channel_mask); + +/** + * Reserve a timer + * @return 0 on success (if not used yet, or already set to the mode) + */ +__EXPORT int io_timer_allocate_timer(unsigned timer, io_timer_channel_mode_t mode); + +__EXPORT int io_timer_unallocate_timer(unsigned timer); + +/** + * Returns the pin configuration for a specific channel, to be used as GPIO output. + * 0 is returned if the channel is not valid. + */ +__EXPORT uint32_t io_timer_channel_get_gpio_output(unsigned channel); +/** + * Returns the pin configuration for a specific channel, to be used as PWM input. + * 0 is returned if the channel is not valid. + */ +__EXPORT uint32_t io_timer_channel_get_as_pwm_input(unsigned channel); + +__END_DECLS diff --git a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/io_timer_hw_description.h b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/io_timer_hw_description.h index 3d4b6417df..e371b6de83 100644 --- a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/io_timer_hw_description.h +++ b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/io_timer_hw_description.h @@ -1,20 +1,20 @@ /**************************************************************************** * - * Copyright (c) 2019 PX4 Development Team. All rights reserved. + * Copyright (C) 2019 PX4 Development Team. All rights reserved. * * 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. + * 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. + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. * 3. Neither the name PX4 nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. + * 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 @@ -30,7 +30,582 @@ * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ + #pragma once -#include "../../../imxrt/include/px4_arch/io_timer_hw_description.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#ifndef CONFIG_ARCH_CHIP_MIMXRT1062DVL6A +# error "This code has only been validated with IMXRT1062. Make sure it is correct before using it on another board." +#endif + + +static inline constexpr timer_io_channels_t initIOTimerChannel(const io_timers_t io_timers_conf[MAX_IO_TIMERS], + PWM::FlexPWMConfig pwm_config, IOMUX::Pad pad) +{ + timer_io_channels_t ret{}; + PWM::FlexPWM pwm{}; + + // FlexPWM Muxing Options + switch (pwm_config.module) { + case PWM::PWM1_PWM_A: + pwm = PWM::FlexPWM1; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_23) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_23_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN23; + + } else if (pad == IOMUX::Pad::GPIO_SD_B0_00) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_00_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN12; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_25) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_25_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN25; + + } else if (pad == IOMUX::Pad::GPIO_SD_B0_02) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_02_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN14; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_27) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_27_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN27; + + } else if (pad == IOMUX::Pad::GPIO_SD_B0_04) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_04_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN16; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_38) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_38_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN24; + + } else if (pad == IOMUX::Pad::GPIO_SD_B1_00) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B1_00_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN0; + + } else if (pad == IOMUX::Pad::GPIO_AD_B0_10) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_10_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN10; + + } else if (pad == IOMUX::Pad::GPIO_EMC_12) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_12_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN12; + + } else if (pad == IOMUX::Pad::GPIO_B1_00) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT6 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_00_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN16; + } + + break; + } + + break; + + case PWM::PWM1_PWM_B: + pwm = PWM::FlexPWM1; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_24) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_24_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN24; + + } else if (pad == IOMUX::Pad::GPIO_SD_B0_01) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_01_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN13; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_26) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_26_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN26; + + } else if (pad == IOMUX::Pad::GPIO_SD_B0_03) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_03_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN15; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_28) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_28_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN28; + + } else if (pad == IOMUX::Pad::GPIO_SD_B0_05) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_05_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN17; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_39) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_39_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN25; + + } else if (pad == IOMUX::Pad::GPIO_SD_B1_01) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B1_01_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN1; + + } else if (pad == IOMUX::Pad::GPIO_AD_B0_11) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_11_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN11; + + } else if (pad == IOMUX::Pad::GPIO_EMC_13) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_13_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN13; + + } else if (pad == IOMUX::Pad::GPIO_B1_01) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT6 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_01_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN17; + } + + break; + } + + break; + + case PWM::PWM1_PWM_X: + pwm = PWM::FlexPWM1; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_AD_B0_02) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_02_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN2; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_AD_B0_03) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_03_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN3; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_AD_B0_12) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_12_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN12; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_AD_B0_13) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_13_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN13; + } + + break; + } + + break; + + + case PWM::PWM2_PWM_A: + pwm = PWM::FlexPWM2; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_B0_06) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_06_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN6; + + } else if (pad == IOMUX::Pad::GPIO_EMC_06) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_06_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN6; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_08) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_08_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN8; + + } else if (pad == IOMUX::Pad::GPIO_B0_08) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_08_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN8; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_10) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_10_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN10; + + } else if (pad == IOMUX::Pad::GPIO_B0_10) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_10_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN10; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_AD_B0_09) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_09_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN9; + + } else if (pad == IOMUX::Pad::GPIO_SD_B1_02) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B1_02_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN2; + + } else if (pad == IOMUX::Pad::GPIO_EMC_19) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_19_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN19; + + } else if (pad == IOMUX::Pad::GPIO_B1_02) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT6 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_02_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN18; + + } else if (pad == IOMUX::Pad::GPIO_AD_B0_00) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT0 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_00_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN0; + } + + break; + } + + break; + + case PWM::PWM2_PWM_B: + pwm = PWM::FlexPWM2; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_B0_07) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_07_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN6; + + } else if (pad == IOMUX::Pad::GPIO_EMC_07) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_07_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN6; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_09) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_09_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN8; + + } else if (pad == IOMUX::Pad::GPIO_B0_09) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_09_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN8; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_11) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_11_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN10; + + } else if (pad == IOMUX::Pad::GPIO_B0_11) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_11_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN10; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_AD_B0_01) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT0 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_01_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN1; + + } else if (pad == IOMUX::Pad::GPIO_SD_B1_03) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B1_03_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN3; + + } else if (pad == IOMUX::Pad::GPIO_EMC_20) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_20_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN20; + + } else if (pad == IOMUX::Pad::GPIO_B1_03) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT6 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_03_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN19; + } + + break; + } + + break; + + + case PWM::PWM3_PWM_A: + pwm = PWM::FlexPWM3; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_29) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_29_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN29; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_31) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_31_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN31; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_33) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_33_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN19; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_21) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_21_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN21; + } + + break; + } + + break; + + case PWM::PWM3_PWM_B: + pwm = PWM::FlexPWM3; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_30) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_30_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN30; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_32) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_32_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN18; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_34) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_34_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN20; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_22) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_22_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN22; + } + + break; + } + + break; + + + case PWM::PWM4_PWM_A: + pwm = PWM::FlexPWM4; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_AD_B1_08) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_08_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN24; + + } else if (pad == IOMUX::Pad::GPIO_EMC_00) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_00_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN0; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_02) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_02_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN2; + + } else if (pad == IOMUX::Pad::GPIO_AD_B1_09) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_09_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN25; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_04) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_04_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN4; + + } else if (pad == IOMUX::Pad::GPIO_B1_14) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_14_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN30; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_17) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_17_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN17; + + } else if (pad == IOMUX::Pad::GPIO_B1_15) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_15_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN31; + } + + break; + } + + break; + + case PWM::PWM4_PWM_B: + pwm = PWM::FlexPWM4; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_01) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_01_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN1; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_03) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_03_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN3; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_05) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_05_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN5; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_18) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_18_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN18; + } + + break; + } + + break; + } + + constexpr_assert(ret.gpio_out != 0, "Invalid PWM/Pad config"); + ret.gpio_out |= IOMUX_CMOS_OUTPUT | IOMUX_PULL_NONE | IOMUX_DRIVE_50OHM | IOMUX_SPEED_MEDIUM | IOMUX_SLEW_FAST; + + switch (pwm_config.module) { + case PWM::PWM1_PWM_A: + case PWM::PWM2_PWM_A: + case PWM::PWM3_PWM_A: + case PWM::PWM4_PWM_A: + ret.val_offset = PWMA_VAL; + break; + + case PWM::PWM1_PWM_B: + case PWM::PWM2_PWM_B: + case PWM::PWM3_PWM_B: + case PWM::PWM4_PWM_B: + ret.val_offset = PWMB_VAL; + break; + + default: + constexpr_assert(false, "not implemented"); + } + + switch (pwm_config.submodule) { + case PWM::Submodule0: + ret.sub_module = SM0; + ret.sub_module_bits = MCTRL_LDOK(1 << SM0); + break; + + case PWM::Submodule1: + ret.sub_module = SM1; + ret.sub_module_bits = MCTRL_LDOK(1 << SM1); + break; + + case PWM::Submodule2: + ret.sub_module = SM2; + ret.sub_module_bits = MCTRL_LDOK(1 << SM2); + break; + + case PWM::Submodule3: + ret.sub_module = SM3; + ret.sub_module_bits = MCTRL_LDOK(1 << SM3); + break; + } + + ret.gpio_in = 0; // TODO (not used yet) + + // find timer index + ret.timer_index = 0xff; + const uint32_t timer_base = getFlexPWMBaseRegister(pwm); + + for (int i = 0; i < MAX_IO_TIMERS; ++i) { + if (io_timers_conf[i].base == timer_base && io_timers_conf[i].submodle == ret.sub_module) { + ret.timer_index = i; + break; + } + } + + constexpr_assert(ret.timer_index != 0xff, "Timer not found"); + + return ret; +} + +static inline constexpr io_timers_t initIOPWM(PWM::FlexPWM pwm, PWM::FlexPWMSubmodule sub) +{ + io_timers_t ret{}; + + ret.base = getFlexPWMBaseRegister(pwm); + ret.submodle = sub; + return ret; +} diff --git a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/spi_hw_description.h b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/spi_hw_description.h index b736695d85..de0c30247d 100644 --- a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/spi_hw_description.h +++ b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/spi_hw_description.h @@ -1,20 +1,20 @@ /**************************************************************************** * - * Copyright (c) 2020 PX4 Development Team. All rights reserved. + * Copyright (C) 2020 PX4 Development Team. All rights reserved. * * 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. + * 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. + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. * 3. Neither the name PX4 nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. + * 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 @@ -30,11 +30,113 @@ * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ + #pragma once +#include +#include + #if defined(CONFIG_SPI) -#include "../../../imxrt/include/px4_arch/spi_hw_description.h" +#include + +#define CS_IOMUX (IOMUX_CMOS_OUTPUT | IOMUX_PULL_UP_100K | IOMUX_DRIVE_33OHM | IOMUX_SPEED_LOW | IOMUX_SLEW_FAST) + +#define DRDY_IOMUX (IOMUX_SCHMITT_TRIGGER | IOMUX_PULL_UP_47K | IOMUX_DRIVE_HIZ) + +#define GENERAL_OUTPUT_IOMUX (IOMUX_CMOS_OUTPUT | IOMUX_PULL_KEEP | IOMUX_DRIVE_33OHM | IOMUX_SPEED_MEDIUM | IOMUX_SLEW_FAST) + +static inline constexpr px4_spi_bus_device_t initSPIDevice(uint32_t devid, SPI::CS cs_gpio, SPI::DRDY drdy_gpio = {}) +{ + px4_spi_bus_device_t ret{}; + ret.cs_gpio = getGPIOPort(cs_gpio.port) | getGPIOPin(cs_gpio.pin) | (GPIO_OUTPUT | GPIO_OUTPUT_ONE | CS_IOMUX); + + if (drdy_gpio.port != GPIO::PortInvalid) { + ret.drdy_gpio = getGPIOPort(drdy_gpio.port) | getGPIOPin(drdy_gpio.pin) | (GPIO_INPUT | DRDY_IOMUX); + } + + if (PX4_SPIDEVID_TYPE(devid) == 0) { // it's a PX4 device (internal or external) + ret.devid = PX4_SPIDEV_ID(PX4_SPI_DEVICE_ID, devid); + + } else { // it's a NuttX device (e.g. SPIDEV_FLASH(0)) + ret.devid = devid; + } + + ret.devtype_driver = PX4_SPI_DEV_ID(devid); + return ret; +} + +static inline constexpr px4_spi_bus_t initSPIBus(SPI::Bus bus, const px4_spi_bus_devices_t &devices, + GPIO::GPIOPin power_enable = {}) +{ + px4_spi_bus_t ret{}; + ret.requires_locking = false; + + for (int i = 0; i < SPI_BUS_MAX_DEVICES; ++i) { + ret.devices[i] = devices.devices[i]; + + + if (ret.devices[i].cs_gpio != 0) { + if (PX4_SPI_DEVICE_ID == PX4_SPIDEVID_TYPE(ret.devices[i].devid)) { + int same_devices_count = 0; + + for (int j = 0; j < i; ++j) { + if (ret.devices[j].cs_gpio != 0) { + same_devices_count += (ret.devices[i].devid & 0xff) == (ret.devices[j].devid & 0xff); + } + } + + // increment the 2. LSB byte to allow multiple devices of the same type + ret.devices[i].devid |= same_devices_count << 8; + + } else { + // A bus potentially requires locking if it is accessed by non-PX4 devices (i.e. NuttX drivers) + ret.requires_locking = true; + } + } + } + + ret.bus = (int)bus; + ret.is_external = false; + + if (power_enable.port != GPIO::PortInvalid) { + ret.power_enable_gpio = getGPIOPort(power_enable.port) | getGPIOPin(power_enable.pin) | + (GPIO_OUTPUT | GPIO_OUTPUT_ZERO | GENERAL_OUTPUT_IOMUX); + } + + return ret; +} + +// just a wrapper since we cannot pass brace-enclosed initialized arrays directly as arguments +struct bus_device_external_cfg_array_t { + SPI::bus_device_external_cfg_t devices[SPI_BUS_MAX_DEVICES]; +}; + +static inline constexpr px4_spi_bus_t initSPIBusExternal(SPI::Bus bus, const bus_device_external_cfg_array_t &devices) +{ + px4_spi_bus_t ret{}; + + for (int i = 0; i < SPI_BUS_MAX_DEVICES; ++i) { + if (devices.devices[i].cs_gpio.port == GPIO::PortInvalid) { + break; + } + + ret.devices[i] = initSPIDevice(i, devices.devices[i].cs_gpio, devices.devices[i].drdy_gpio); + } + + ret.bus = (int)bus; + ret.is_external = true; + ret.requires_locking = false; // external buses are never accessed by NuttX drivers + return ret; +} + +static inline constexpr SPI::bus_device_external_cfg_t initSPIConfigExternal(SPI::CS cs_gpio, SPI::DRDY drdy_gpio = {}) +{ + SPI::bus_device_external_cfg_t ret{}; + ret.cs_gpio = cs_gpio; + ret.drdy_gpio = drdy_gpio; + return ret; +} constexpr bool validateSPIConfig(const px4_spi_bus_t spi_busses_conf[SPI_BUS_MAX_BUS_ITEMS]) { diff --git a/platforms/nuttx/src/px4/nxp/rt117x/CMakeLists.txt b/platforms/nuttx/src/px4/nxp/rt117x/CMakeLists.txt index 8f14a4cde5..91224642dc 100644 --- a/platforms/nuttx/src/px4/nxp/rt117x/CMakeLists.txt +++ b/platforms/nuttx/src/px4/nxp/rt117x/CMakeLists.txt @@ -32,13 +32,13 @@ ############################################################################ -#add_subdirectory(../imxrt/adc adc) +add_subdirectory(adc) add_subdirectory(../imxrt/board_critmon board_critmon) add_subdirectory(../imxrt/board_hw_info board_hw_info) add_subdirectory(../imxrt/board_reset board_reset) #add_subdirectory(../imxrt/dshot dshot) add_subdirectory(../imxrt/hrt hrt) add_subdirectory(../imxrt/led_pwm led_pwm) -add_subdirectory(../imxrt/io_pins io_pins) +add_subdirectory(io_pins) #add_subdirectory(../imxrt/tone_alarm tone_alarm) add_subdirectory(../imxrt/version version) diff --git a/platforms/nuttx/src/px4/nxp/rt117x/adc/CMakeLists.txt b/platforms/nuttx/src/px4/nxp/rt117x/adc/CMakeLists.txt new file mode 100644 index 0000000000..9f0d432ba0 --- /dev/null +++ b/platforms/nuttx/src/px4/nxp/rt117x/adc/CMakeLists.txt @@ -0,0 +1,36 @@ +############################################################################ +# +# Copyright (c) 2023 PX4 Development Team. All rights reserved. +# +# 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 PX4 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. +# +############################################################################ + +px4_add_library(arch_adc + adc.cpp +) diff --git a/platforms/nuttx/src/px4/nxp/rt117x/adc/adc.cpp b/platforms/nuttx/src/px4/nxp/rt117x/adc/adc.cpp new file mode 100644 index 0000000000..413e1d8e5f --- /dev/null +++ b/platforms/nuttx/src/px4/nxp/rt117x/adc/adc.cpp @@ -0,0 +1,209 @@ +/**************************************************************************** + * + * Copyright (C) 2023 PX4 Development Team. All rights reserved. + * + * 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 PX4 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. + * + ****************************************************************************/ + +/** + * @file adc.cpp + * + * Driver for the imxrt ADC. + * + * This is a low-rate driver, designed for sampling things like voltages + * and so forth. It avoids the gross complexity of the NuttX ADC driver. + */ + +#include +#include +#include +#include +#include + +#include +#include + +typedef uint32_t adc_chan_t; +#define ADC_TOTAL_CHANNELS 16 + +#define _REG(_addr) (*(volatile uint32_t *)(_addr)) + +/* ADC register accessors */ + +#define REG(base_address, _reg) _REG((base_address) + (_reg)) + +#define rHC0(base_address) REG(base_address, IMXRT_ADC_HC0_OFFSET) /* Control register for hardware triggers */ +#define rHC1(base_address) REG(base_address, IMXRT_ADC_HC1_OFFSET) /* Control register for hardware triggers */ +#define rHC2(base_address) REG(base_address, IMXRT_ADC_HC2_OFFSET) /* Control register for hardware triggers */ +#define rHC3(base_address) REG(base_address, IMXRT_ADC_HC3_OFFSET) /* Control register for hardware triggers */ +#define rHC4(base_address) REG(base_address, IMXRT_ADC_HC4_OFFSET) /* Control register for hardware triggers */ +#define rHC5(base_address) REG(base_address, IMXRT_ADC_HC5_OFFSET) /* Control register for hardware triggers */ +#define rHC6(base_address) REG(base_address, IMXRT_ADC_HC6_OFFSET) /* Control register for hardware triggers */ +#define rHC7(base_address) REG(base_address, IMXRT_ADC_HC7_OFFSET) /* Control register for hardware triggers */ +#define rHS(base_address) REG(base_address, IMXRT_ADC_HS_OFFSET) /* Status register for HW triggers */ +#define rR0(base_address) REG(base_address, IMXRT_ADC_R0_OFFSET) /* Data result register for HW triggers */ +#define rR1(base_address) REG(base_address, IMXRT_ADC_R1_OFFSET) /* Data result register for HW triggers */ +#define rR2(base_address) REG(base_address, IMXRT_ADC_R2_OFFSET) /* Data result register for HW triggers */ +#define rR3(base_address) REG(base_address, IMXRT_ADC_R3_OFFSET) /* Data result register for HW triggers */ +#define rR4(base_address) REG(base_address, IMXRT_ADC_R4_OFFSET) /* Data result register for HW triggers */ +#define rR5(base_address) REG(base_address, IMXRT_ADC_R5_OFFSET) /* Data result register for HW triggers */ +#define rR6(base_address) REG(base_address, IMXRT_ADC_R6_OFFSET) /* Data result register for HW triggers */ +#define rR7(base_address) REG(base_address, IMXRT_ADC_R7_OFFSET) /* Data result register for HW triggers */ +#define rCFG(base_address) REG(base_address, IMXRT_ADC_CFG_OFFSET) /* Configuration register */ +#define rGC(base_address) REG(base_address, IMXRT_ADC_GC_OFFSET) /* General control register */ +#define rGS(base_address) REG(base_address, IMXRT_ADC_GS_OFFSET) /* General status register */ +#define rCV(base_address) REG(base_address, IMXRT_ADC_CV_OFFSET) /* Compare value register */ +#define rOFS(base_address) REG(base_address, IMXRT_ADC_OFS_OFFSET) /* Offset correction value register */ +#define rCAL(base_address) REG(base_address, IMXRT_ADC_CAL_OFFSET) /* Calibration value register */ + + +int px4_arch_adc_init(uint32_t base_address) +{ + static bool once = false; + + if (!once) { + + once = true; + + /* Input is Buss Clock 144 Mhz We will use /4 for 36 Mhz */ + + irqstate_t flags = px4_enter_critical_section(); + +// imxrt_clockall_adc1(); + + rCFG(base_address) = ADC_CFG_ADICLK_IPG | ADC_CFG_MODE_12BIT | \ + ADC_CFG_ADIV_DIV4 | ADC_CFG_ADLSMP | ADC_CFG_ADSTS_7_21 | \ + ADC_CFG_AVGS_4SMPL | ADC_CFG_OVWREN; + px4_leave_critical_section(flags); + + /* Clear the CALF and begin the calibration */ + + rGS(base_address) = ADC_GS_CALF; + rGC(base_address) = ADC_GC_CAL; + uint32_t guard = 100; + + while (guard != 0 && (rGS(base_address) & ADC_GC_CAL) == 0) { + guard--; + usleep(1); + } + + while ((rGS(base_address) & ADC_GC_CAL) == ADC_GC_CAL) { + + usleep(100); + + if (rGS(base_address) & ADC_GS_CALF) { + return -1; + } + } + + if ((rHS(base_address) & ADC_HS_COCO0) == 0) { + return -2; + } + + if (rGS(base_address) & ADC_GS_CALF) { + return -3; + } + + /* dummy read to clear COCO of calibration */ + + int32_t r = rR0(base_address); + UNUSED(r); + + /* kick off a sample and wait for it to complete */ + hrt_abstime now = hrt_absolute_time(); + rGC(base_address) = ADC_GC_AVGE; + rHC0(base_address) = 0xd; // VREFSH = internal channel, for ADC self-test, hard connected to VRH internally + + while (!(rHS(base_address) & ADC_HS_COCO0)) { + + /* don't wait for more than 500us, since that means something broke - + * should reset here if we see this + */ + + if ((hrt_absolute_time() - now) > 500) { + return -4; + } + } + + r = rR0(base_address); + } // once + + return 0; +} + +void px4_arch_adc_uninit(uint32_t base_address) +{ + //imxrt_clockoff_adc1(); +} + +uint32_t px4_arch_adc_sample(uint32_t base_address, unsigned channel) +{ + + irqstate_t flags = px4_enter_critical_section(); + + /* clear any previous COCO0 */ + + uint16_t result = rR0(base_address); + + rHC0(base_address) = channel; + + /* wait for the conversion to complete */ + hrt_abstime now = hrt_absolute_time(); + + while (!(rHS(base_address) & ADC_HS_COCO0)) { + /* don't wait for more than 10us, since that means something broke + * should reset here if we see this + */ + if ((hrt_absolute_time() - now) > 30) { + px4_leave_critical_section(flags); + return UINT32_MAX; + } + } + + /* read the result and clear COCO0 */ + result = rR0(base_address); + px4_leave_critical_section(flags); + + return result; +} + +float px4_arch_adc_reference_v() +{ + return BOARD_ADC_POS_REF_V; // TODO: provide true vref +} + +uint32_t px4_arch_adc_temp_sensor_mask() +{ + return 0; +} + +uint32_t px4_arch_adc_dn_fullcount(void) +{ + return 1 << 12; // 12 bit ADC +} diff --git a/platforms/nuttx/src/px4/nxp/rt117x/include/px4_arch/hw_description.h b/platforms/nuttx/src/px4/nxp/rt117x/include/px4_arch/hw_description.h index e7676690b9..71a492b161 100644 --- a/platforms/nuttx/src/px4/nxp/rt117x/include/px4_arch/hw_description.h +++ b/platforms/nuttx/src/px4/nxp/rt117x/include/px4_arch/hw_description.h @@ -1,20 +1,20 @@ /**************************************************************************** * - * Copyright (c) 2019 PX4 Development Team. All rights reserved. + * Copyright (C) 2023 PX4 Development Team. All rights reserved. * * 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. + * 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. + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. * 3. Neither the name PX4 nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. + * 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 @@ -30,7 +30,446 @@ * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ + #pragma once -#include "../../../imxrt/include/px4_arch/hw_description.h" +#include + +#include "hardware/imxrt_flexpwm.h" + +#include + +#include +#if !defined(CONFIG_ARCH_CHIP_MIMXRT1176DVMAA) +# error "This code has only been validated with IMXRT1176. Make sure it is correct before using it on another board." +#endif + +/* + * PWM + */ + +namespace PWM +{ +enum FlexPWM { + FlexPWM1 = 0, + FlexPWM2, + FlexPWM3, + FlexPWM4, +}; + +enum FlexPWMModule { + PWM1_PWM_A = 0, + PWM1_PWM_B, + PWM1_PWM_X, + + PWM2_PWM_A, + PWM2_PWM_B, + PWM2_PWM_X, + + PWM3_PWM_A, + PWM3_PWM_B, + PWM3_PWM_X, + + PWM4_PWM_A, + PWM4_PWM_B, + PWM4_PWM_X, +}; + +enum FlexPWMSubmodule { + Submodule0 = 0, + Submodule1, + Submodule2, + Submodule3, +}; + +struct FlexPWMConfig { + FlexPWMModule module; + FlexPWMSubmodule submodule; +}; +} + +static inline constexpr uint32_t getFlexPWMBaseRegister(PWM::FlexPWM pwm) +{ + switch (pwm) { + case PWM::FlexPWM1: return IMXRT_FLEXPWM1_BASE; + + case PWM::FlexPWM2: return IMXRT_FLEXPWM2_BASE; + + case PWM::FlexPWM3: return IMXRT_FLEXPWM3_BASE; + + case PWM::FlexPWM4: return IMXRT_FLEXPWM4_BASE; + } + + return 0; +} +namespace IOMUX +{ +enum class Pad { + GPIO_EMC_B1_00 = 0, + GPIO_EMC_B1_01 = 1, + GPIO_EMC_B1_02 = 2, + GPIO_EMC_B1_03 = 3, + GPIO_EMC_B1_04 = 4, + GPIO_EMC_B1_05 = 5, + GPIO_EMC_B1_06 = 6, + GPIO_EMC_B1_07 = 7, + GPIO_EMC_B1_08 = 8, + GPIO_EMC_B1_09 = 9, + GPIO_EMC_B1_10 = 10, + GPIO_EMC_B1_11 = 11, + GPIO_EMC_B1_12 = 12, + GPIO_EMC_B1_13 = 13, + GPIO_EMC_B1_14 = 14, + GPIO_EMC_B1_15 = 15, + GPIO_EMC_B1_16 = 16, + GPIO_EMC_B1_17 = 17, + GPIO_EMC_B1_18 = 18, + GPIO_EMC_B1_19 = 19, + GPIO_EMC_B1_20 = 20, + GPIO_EMC_B1_21 = 21, + GPIO_EMC_B1_22 = 22, + GPIO_EMC_B1_23 = 23, + GPIO_EMC_B1_24 = 24, + GPIO_EMC_B1_25 = 25, + GPIO_EMC_B1_26 = 26, + GPIO_EMC_B1_27 = 27, + GPIO_EMC_B1_28 = 28, + GPIO_EMC_B1_29 = 29, + GPIO_EMC_B1_30 = 30, + GPIO_EMC_B1_31 = 31, + GPIO_EMC_B1_32 = 32, + GPIO_EMC_B1_33 = 33, + GPIO_EMC_B1_34 = 34, + GPIO_EMC_B1_35 = 35, + GPIO_EMC_B1_36 = 36, + GPIO_EMC_B1_37 = 37, + GPIO_EMC_B1_38 = 38, + GPIO_EMC_B1_39 = 39, + GPIO_EMC_B1_40 = 40, + GPIO_EMC_B1_41 = 41, + GPIO_EMC_B2_00 = 42, + GPIO_EMC_B2_01 = 43, + GPIO_EMC_B2_02 = 44, + GPIO_EMC_B2_03 = 45, + GPIO_EMC_B2_04 = 46, + GPIO_EMC_B2_05 = 47, + GPIO_EMC_B2_06 = 48, + GPIO_EMC_B2_07 = 49, + GPIO_EMC_B2_08 = 50, + GPIO_EMC_B2_09 = 51, + GPIO_EMC_B2_10 = 52, + GPIO_EMC_B2_11 = 53, + GPIO_EMC_B2_12 = 54, + GPIO_EMC_B2_13 = 55, + GPIO_EMC_B2_14 = 56, + GPIO_EMC_B2_15 = 57, + GPIO_EMC_B2_16 = 58, + GPIO_EMC_B2_17 = 59, + GPIO_EMC_B2_18 = 60, + GPIO_EMC_B2_19 = 61, + GPIO_EMC_B2_20 = 62, + GPIO_AD_00 = 63, + GPIO_AD_01 = 64, + GPIO_AD_02 = 65, + GPIO_AD_03 = 66, + GPIO_AD_04 = 67, + GPIO_AD_05 = 68, + GPIO_AD_06 = 69, + GPIO_AD_07 = 70, + GPIO_AD_08 = 71, + GPIO_AD_09 = 72, + GPIO_AD_10 = 73, + GPIO_AD_11 = 74, + GPIO_AD_12 = 75, + GPIO_AD_13 = 76, + GPIO_AD_14 = 77, + GPIO_AD_15 = 78, + GPIO_AD_16 = 79, + GPIO_AD_17 = 80, + GPIO_AD_18 = 81, + GPIO_AD_19 = 82, + GPIO_AD_20 = 83, + GPIO_AD_21 = 84, + GPIO_AD_22 = 85, + GPIO_AD_23 = 86, + GPIO_AD_24 = 87, + GPIO_AD_25 = 88, + GPIO_AD_26 = 89, + GPIO_AD_27 = 90, + GPIO_AD_28 = 91, + GPIO_AD_29 = 92, + GPIO_AD_30 = 93, + GPIO_AD_31 = 94, + GPIO_AD_32 = 95, + GPIO_AD_33 = 96, + GPIO_AD_34 = 97, + GPIO_AD_35 = 98, + GPIO_SD_B1_00 = 99, + GPIO_SD_B1_01 = 100, + GPIO_SD_B1_02 = 101, + GPIO_SD_B1_03 = 102, + GPIO_SD_B1_04 = 103, + GPIO_SD_B1_05 = 104, + GPIO_SD_B2_00 = 105, + GPIO_SD_B2_01 = 106, + GPIO_SD_B2_02 = 107, + GPIO_SD_B2_03 = 108, + GPIO_SD_B2_04 = 109, + GPIO_SD_B2_05 = 110, + GPIO_SD_B2_06 = 111, + GPIO_SD_B2_07 = 112, + GPIO_SD_B2_08 = 113, + GPIO_SD_B2_09 = 114, + GPIO_SD_B2_10 = 115, + GPIO_SD_B2_11 = 116, + GPIO_DISP_B1_00 = 117, + GPIO_DISP_B1_01 = 118, + GPIO_DISP_B1_02 = 119, + GPIO_DISP_B1_03 = 120, + GPIO_DISP_B1_04 = 121, + GPIO_DISP_B1_05 = 122, + GPIO_DISP_B1_06 = 123, + GPIO_DISP_B1_07 = 124, + GPIO_DISP_B1_08 = 125, + GPIO_DISP_B1_09 = 126, + GPIO_DISP_B1_10 = 127, + GPIO_DISP_B1_11 = 128, + GPIO_DISP_B2_00 = 129, + GPIO_DISP_B2_01 = 130, + GPIO_DISP_B2_02 = 131, + GPIO_DISP_B2_03 = 132, + GPIO_DISP_B2_04 = 133, + GPIO_DISP_B2_05 = 134, + GPIO_DISP_B2_06 = 135, + GPIO_DISP_B2_07 = 136, + GPIO_DISP_B2_08 = 137, + GPIO_DISP_B2_09 = 138, + GPIO_DISP_B2_10 = 139, + GPIO_DISP_B2_11 = 140, + GPIO_DISP_B2_12 = 141, + GPIO_DISP_B2_13 = 142, + GPIO_DISP_B2_14 = 143, + GPIO_DISP_B2_15 = 144, + WAKEUP = 145, + PMIC_ON_REQ = 146, + PMIC_STBY_REQ = 147, + GPIO_SNVS_00 = 148, + GPIO_SNVS_01 = 149, + GPIO_SNVS_02 = 150, + GPIO_SNVS_03 = 151, + GPIO_SNVS_04 = 152, + GPIO_SNVS_05 = 153, + GPIO_SNVS_06 = 154, + GPIO_SNVS_07 = 155, + GPIO_SNVS_08 = 156, + GPIO_SNVS_09 = 157, + GPIO_LPSR_00 = 158, + GPIO_LPSR_01 = 159, + GPIO_LPSR_02 = 160, + GPIO_LPSR_03 = 161, + GPIO_LPSR_04 = 162, + GPIO_LPSR_05 = 163, + GPIO_LPSR_06 = 164, + GPIO_LPSR_07 = 165, + GPIO_LPSR_08 = 166, + GPIO_LPSR_09 = 167, + GPIO_LPSR_10 = 168, + GPIO_LPSR_11 = 169, + GPIO_LPSR_12 = 170, + GPIO_LPSR_13 = 171, + GPIO_LPSR_14 = 172, + GPIO_LPSR_15 = 173 +}; + +} + +/* + * GPIO + */ + +namespace GPIO +{ +enum Port { + PortInvalid = 0, + Port1, + Port2, + Port3, + Port4, + Port5, + Port6, + Port7, + Port8, + Port9, + Port10, + Port11, + Port12, + Port13, +}; +enum Pin { + Pin0 = 0, + Pin1, + Pin2, + Pin3, + Pin4, + Pin5, + Pin6, + Pin7, + Pin8, + Pin9, + Pin10, + Pin11, + Pin12, + Pin13, + Pin14, + Pin15, + Pin16, + Pin17, + Pin18, + Pin19, + Pin20, + Pin21, + Pin22, + Pin23, + Pin24, + Pin25, + Pin26, + Pin27, + Pin28, + Pin29, + Pin30, + Pin31, +}; +struct GPIOPin { + Port port; + Pin pin; +}; +} + +static inline constexpr uint32_t getGPIOPort(GPIO::Port port) +{ + switch (port) { + case GPIO::Port1: return GPIO_PORT1; + + case GPIO::Port2: return GPIO_PORT2; + + case GPIO::Port3: return GPIO_PORT3; + + case GPIO::Port4: return GPIO_PORT4; + + case GPIO::Port5: return GPIO_PORT5; + + case GPIO::Port6: return GPIO_PORT6; + + case GPIO::Port7: return GPIO_PORT7; + + case GPIO::Port8: return GPIO_PORT8; + + case GPIO::Port9: return GPIO_PORT9; + + case GPIO::Port10: return GPIO_PORT10; + + case GPIO::Port11: return GPIO_PORT11; + + case GPIO::Port12: return GPIO_PORT12; + + case GPIO::Port13: return GPIO_PORT13; + + default: break; + } + + return 0; +} + +static inline constexpr uint32_t getGPIOPin(GPIO::Pin pin) +{ + switch (pin) { + case GPIO::Pin0: return GPIO_PIN0; + + case GPIO::Pin1: return GPIO_PIN1; + + case GPIO::Pin2: return GPIO_PIN2; + + case GPIO::Pin3: return GPIO_PIN3; + + case GPIO::Pin4: return GPIO_PIN4; + + case GPIO::Pin5: return GPIO_PIN5; + + case GPIO::Pin6: return GPIO_PIN6; + + case GPIO::Pin7: return GPIO_PIN7; + + case GPIO::Pin8: return GPIO_PIN8; + + case GPIO::Pin9: return GPIO_PIN9; + + case GPIO::Pin10: return GPIO_PIN10; + + case GPIO::Pin11: return GPIO_PIN11; + + case GPIO::Pin12: return GPIO_PIN12; + + case GPIO::Pin13: return GPIO_PIN13; + + case GPIO::Pin14: return GPIO_PIN14; + + case GPIO::Pin15: return GPIO_PIN15; + + case GPIO::Pin16: return GPIO_PIN16; + + case GPIO::Pin17: return GPIO_PIN17; + + case GPIO::Pin18: return GPIO_PIN18; + + case GPIO::Pin19: return GPIO_PIN19; + + case GPIO::Pin20: return GPIO_PIN20; + + case GPIO::Pin21: return GPIO_PIN21; + + case GPIO::Pin22: return GPIO_PIN22; + + case GPIO::Pin23: return GPIO_PIN23; + + case GPIO::Pin24: return GPIO_PIN24; + + case GPIO::Pin25: return GPIO_PIN25; + + case GPIO::Pin26: return GPIO_PIN26; + + case GPIO::Pin27: return GPIO_PIN27; + + case GPIO::Pin28: return GPIO_PIN28; + + case GPIO::Pin29: return GPIO_PIN29; + + case GPIO::Pin30: return GPIO_PIN30; + + case GPIO::Pin31: return GPIO_PIN31; + } + + return 0; +} + +namespace SPI +{ + +enum class Bus { + LPSPI1 = 1, + LPSPI2, + LPSPI3, + LPSPI4, + LPSPI5, + LPSPI6, +}; + +using CS = GPIO::GPIOPin; ///< chip-select pin +using DRDY = GPIO::GPIOPin; ///< data ready pin + +struct bus_device_external_cfg_t { + CS cs_gpio; + DRDY drdy_gpio; +}; + +} // namespace SPI diff --git a/platforms/nuttx/src/px4/nxp/rt117x/include/px4_arch/io_timer_hw_description.h b/platforms/nuttx/src/px4/nxp/rt117x/include/px4_arch/io_timer_hw_description.h index 3d4b6417df..36aafe3ebb 100644 --- a/platforms/nuttx/src/px4/nxp/rt117x/include/px4_arch/io_timer_hw_description.h +++ b/platforms/nuttx/src/px4/nxp/rt117x/include/px4_arch/io_timer_hw_description.h @@ -1,20 +1,20 @@ /**************************************************************************** * - * Copyright (c) 2019 PX4 Development Team. All rights reserved. + * Copyright (C) 2019 PX4 Development Team. All rights reserved. * * 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. + * 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. + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. * 3. Neither the name PX4 nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. + * 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 @@ -30,7 +30,1159 @@ * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ + #pragma once -#include "../../../imxrt/include/px4_arch/io_timer_hw_description.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#if !defined(CONFIG_ARCH_CHIP_MIMXRT1176DVMAA) +# error "This code has only been validated with IMXRT1176. Make sure it is correct before using it on another board." +#endif + + +static inline constexpr timer_io_channels_t initIOTimerChannel(const io_timers_t io_timers_conf[MAX_IO_TIMERS], + PWM::FlexPWMConfig pwm_config, IOMUX::Pad pad) +{ + timer_io_channels_t ret{}; + + PWM::FlexPWM pwm {}; + + // FlexPWM IMXRT1176 Muxing Options +#ifdef CONFIG_ARCH_FAMILY_IMXRT117x + + switch (pwm_config.module) { + case PWM::PWM1_PWM_A: + pwm = PWM::FlexPWM1; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_B1_23) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_23_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN23; + + } else if (pad == IOMUX::Pad::GPIO_AD_00) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_00_INDEX); + ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN31; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_B1_25) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_25_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN25; + + } else if (pad == IOMUX::Pad::GPIO_AD_02) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_02_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN1; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_B1_27) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_27_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN27; + + } else if (pad == IOMUX::Pad::GPIO_AD_04) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_04_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN3; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_B1_38) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_38_INDEX); + ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN6; + + } + + break; + } + + break; + + case PWM::PWM1_PWM_B: + pwm = PWM::FlexPWM1; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_B1_24) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_24_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN24; + + } else if (pad == IOMUX::Pad::GPIO_AD_01) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_01_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN0; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_B1_26) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_26_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN26; + + } else if (pad == IOMUX::Pad::GPIO_AD_03) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_03_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN2; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_B1_28) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_28_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN28; + + } else if (pad == IOMUX::Pad::GPIO_AD_05) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_05_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN4; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_B1_39) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_39_INDEX); + ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN7; + + } + + break; + } + + break; + + case PWM::PWM1_PWM_X: + pwm = PWM::FlexPWM1; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_AD_06) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_06_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN5; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_AD_07) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_07_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN6; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_AD_08) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_08_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN7; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_AD_09) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_09_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN8; + } + + break; + } + + break; + + + case PWM::PWM2_PWM_A: + pwm = PWM::FlexPWM2; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_B1_06) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_06_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN6; + + } else if (pad == IOMUX::Pad::GPIO_AD_24) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_24_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN23; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_B1_08) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_08_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN8; + + } else if (pad == IOMUX::Pad::GPIO_AD_26) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_26_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN25; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_B1_10) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_10_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN10; + + } else if (pad == IOMUX::Pad::GPIO_AD_28) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_28_INDEX); + ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN27; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_B1_19) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_19_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN19; + + } + + break; + } + + break; + + case PWM::PWM2_PWM_B: + pwm = PWM::FlexPWM2; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_B1_07) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_07_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN7; + + } else if (pad == IOMUX::Pad::GPIO_AD_25) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_25_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN24; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_B1_09) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_09_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN9; + + } else if (pad == IOMUX::Pad::GPIO_AD_27) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_27_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN26; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_B1_11) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_11_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN11; + + } else if (pad == IOMUX::Pad::GPIO_AD_29) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_29_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN28; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_B1_20) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_20_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN20; + + } + + break; + } + + break; + + case PWM::PWM2_PWM_X: + pwm = PWM::FlexPWM2; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_AD_10) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_10_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN9; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_AD_11) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_11_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN10; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_AD_12) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_12_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN11; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_AD_13) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_13_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN12; + } + + break; + } + + break; + + + case PWM::PWM3_PWM_A: + pwm = PWM::FlexPWM3; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_B1_29) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_29_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN29; + + } else if (pad == IOMUX::Pad::GPIO_EMC_B2_00) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_00_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN10; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_B1_31) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_31_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN31; + + } else if (pad == IOMUX::Pad::GPIO_EMC_B2_02) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_02_INDEX); + ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN12; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_B1_33) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_33_INDEX); + ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN1; + + } else if (pad == IOMUX::Pad::GPIO_EMC_B2_04) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_04_INDEX); + ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN14; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_B1_21) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_21_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN21; + + } else if (pad == IOMUX::Pad::GPIO_EMC_B2_06) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_06_INDEX); + ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN16; + } + + break; + } + + break; + + case PWM::PWM3_PWM_B: + pwm = PWM::FlexPWM3; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_B1_30) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_30_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN30; + + } else if (pad == IOMUX::Pad::GPIO_EMC_B2_01) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_01_INDEX); + ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN11; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_B1_32) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_32_INDEX); + ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN0; + + } else if (pad == IOMUX::Pad::GPIO_EMC_B2_03) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_03_INDEX); + ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN13; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_B1_34) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_34_INDEX); + ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN2; + + } else if (pad == IOMUX::Pad::GPIO_EMC_B2_05) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_05_INDEX); + ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN15; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_B1_22) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_22_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN22; + + } else if (pad == IOMUX::Pad::GPIO_EMC_B2_07) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_07_INDEX); + ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN17; + } + + break; + } + + break; + + + case PWM::PWM3_PWM_X: + pwm = PWM::FlexPWM3; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_AD_14) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_14_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN13; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_AD_15) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_15_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN14; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_AD_16) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_16_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN15; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_AD_17) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_17_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN16; + } + + break; + } + + break; + + case PWM::PWM4_PWM_A: + pwm = PWM::FlexPWM4; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_B1_00) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_00_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN0; + + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_B1_02) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_02_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN2; + + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_B1_04) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_04_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN4; + + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_B1_17) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_17_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN17; + + } + + break; + } + + break; + + case PWM::PWM4_PWM_B: + pwm = PWM::FlexPWM4; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_B1_01) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_01_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN1; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_B1_03) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_03_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN3; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_B1_05) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_05_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN5; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_B1_18) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_18_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN18; + } + + break; + } + + break; + + + case PWM::PWM4_PWM_X: + pwm = PWM::FlexPWM4; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_AD_18) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_18_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN17; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_AD_19) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_19_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN18; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_AD_20) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_20_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN19; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_AD_21) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_21_INDEX); + ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN20; + } + + break; + } + + break; + } + + constexpr_assert(ret.gpio_out != 0, "Invalid PWM/Pad config"); + ret.gpio_out |= IOMUX_CMOS_OUTPUT | IOMUX_PULL_NONE | IOMUX_DRIVE_HIGHSTRENGTH | IOMUX_SLEW_FAST; +#else + + switch (pwm_config.module) { + case PWM::PWM1_PWM_A: + pwm = PWM::FlexPWM1; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_23) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_23_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN23; + + } else if (pad == IOMUX::Pad::GPIO_SD_B0_00) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_00_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN12; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_25) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_25_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN25; + + } else if (pad == IOMUX::Pad::GPIO_SD_B0_02) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_02_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN14; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_27) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_27_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN27; + + } else if (pad == IOMUX::Pad::GPIO_SD_B0_04) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_04_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN16; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_38) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_38_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN24; + + } else if (pad == IOMUX::Pad::GPIO_SD_B1_00) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B1_00_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN0; + + } else if (pad == IOMUX::Pad::GPIO_AD_B0_10) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_10_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN10; + + } else if (pad == IOMUX::Pad::GPIO_EMC_12) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_12_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN12; + + } else if (pad == IOMUX::Pad::GPIO_B1_00) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT6 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_00_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN16; + } + + break; + } + + break; + + case PWM::PWM1_PWM_B: + pwm = PWM::FlexPWM1; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_24) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_24_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN24; + + } else if (pad == IOMUX::Pad::GPIO_SD_B0_01) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_01_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN13; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_26) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_26_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN26; + + } else if (pad == IOMUX::Pad::GPIO_SD_B0_03) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_03_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN15; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_28) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_28_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN28; + + } else if (pad == IOMUX::Pad::GPIO_SD_B0_05) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B0_05_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN17; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_39) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_39_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN25; + + } else if (pad == IOMUX::Pad::GPIO_SD_B1_01) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B1_01_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN1; + + } else if (pad == IOMUX::Pad::GPIO_AD_B0_11) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_11_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN11; + + } else if (pad == IOMUX::Pad::GPIO_EMC_13) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_13_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN13; + + } else if (pad == IOMUX::Pad::GPIO_B1_01) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT6 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_01_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN17; + } + + break; + } + + break; + + case PWM::PWM1_PWM_X: + pwm = PWM::FlexPWM1; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_AD_B0_02) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_02_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN2; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_AD_B0_03) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_03_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN3; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_AD_B0_12) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_12_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN12; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_AD_B0_13) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_13_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN13; + } + + break; + } + + break; + + + case PWM::PWM2_PWM_A: + pwm = PWM::FlexPWM2; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_B0_06) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_06_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN6; + + } else if (pad == IOMUX::Pad::GPIO_EMC_06) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_06_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN6; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_08) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_08_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN8; + + } else if (pad == IOMUX::Pad::GPIO_B0_08) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_08_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN8; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_10) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_10_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN10; + + } else if (pad == IOMUX::Pad::GPIO_B0_10) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_10_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN10; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_AD_B0_09) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_09_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN9; + + } else if (pad == IOMUX::Pad::GPIO_SD_B1_02) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B1_02_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN2; + + } else if (pad == IOMUX::Pad::GPIO_EMC_19) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_19_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN19; + + } else if (pad == IOMUX::Pad::GPIO_B1_02) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT6 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_02_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN18; + + } else if (pad == IOMUX::Pad::GPIO_AD_B0_00) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT0 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_00_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN0; + } + + break; + } + + break; + + case PWM::PWM2_PWM_B: + pwm = PWM::FlexPWM2; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_B0_07) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_07_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN6; + + } else if (pad == IOMUX::Pad::GPIO_EMC_07) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_07_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN6; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_09) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_09_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN8; + + } else if (pad == IOMUX::Pad::GPIO_B0_09) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_09_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN8; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_11) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_11_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN10; + + } else if (pad == IOMUX::Pad::GPIO_B0_11) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B0_11_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN10; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_AD_B0_01) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT0 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_01_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN1; + + } else if (pad == IOMUX::Pad::GPIO_SD_B1_03) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT2 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_SD_B1_03_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN3; + + } else if (pad == IOMUX::Pad::GPIO_EMC_20) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_20_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN20; + + } else if (pad == IOMUX::Pad::GPIO_B1_03) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT6 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_03_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN19; + } + + break; + } + + break; + + + case PWM::PWM3_PWM_A: + pwm = PWM::FlexPWM3; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_29) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_29_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN29; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_31) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_31_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN31; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_33) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_33_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN19; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_21) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_21_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN21; + } + + break; + } + + break; + + case PWM::PWM3_PWM_B: + pwm = PWM::FlexPWM3; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_30) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_30_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN30; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_32) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_32_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN18; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_34) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_34_INDEX); + ret.gpio_portpin = GPIO_PORT3 | GPIO_PIN20; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_22) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_22_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN22; + } + + break; + } + + break; + + + case PWM::PWM4_PWM_A: + pwm = PWM::FlexPWM4; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_AD_B1_08) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_08_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN24; + + } else if (pad == IOMUX::Pad::GPIO_EMC_00) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_00_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN0; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_02) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_02_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN2; + + } else if (pad == IOMUX::Pad::GPIO_AD_B1_09) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_09_INDEX); + ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN25; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_04) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_04_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN4; + + } else if (pad == IOMUX::Pad::GPIO_B1_14) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_14_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN30; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_17) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_17_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN17; + + } else if (pad == IOMUX::Pad::GPIO_B1_15) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_15_INDEX); + ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN31; + } + + break; + } + + break; + + case PWM::PWM4_PWM_B: + pwm = PWM::FlexPWM4; + + switch (pwm_config.submodule) { + case PWM::Submodule0: + if (pad == IOMUX::Pad::GPIO_EMC_01) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_01_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN1; + } + + break; + + case PWM::Submodule1: + if (pad == IOMUX::Pad::GPIO_EMC_03) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_03_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN3; + } + + break; + + case PWM::Submodule2: + if (pad == IOMUX::Pad::GPIO_EMC_05) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_05_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN5; + } + + break; + + case PWM::Submodule3: + if (pad == IOMUX::Pad::GPIO_EMC_18) { + ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_18_INDEX); + ret.gpio_portpin = GPIO_PORT4 | GPIO_PIN18; + } + + break; + } + + break; + } + + constexpr_assert(ret.gpio_out != 0, "Invalid PWM/Pad config"); + ret.gpio_out |= IOMUX_CMOS_OUTPUT | IOMUX_PULL_NONE | IOMUX_DRIVE_50OHM | IOMUX_SPEED_MEDIUM | IOMUX_SLEW_FAST; +#endif + + switch (pwm_config.module) { + case PWM::PWM1_PWM_A: + case PWM::PWM2_PWM_A: + case PWM::PWM3_PWM_A: + case PWM::PWM4_PWM_A: + ret.val_offset = PWMA_VAL; + break; + + case PWM::PWM1_PWM_B: + case PWM::PWM2_PWM_B: + case PWM::PWM3_PWM_B: + case PWM::PWM4_PWM_B: + ret.val_offset = PWMB_VAL; + break; + + case PWM::PWM1_PWM_X: + case PWM::PWM2_PWM_X: + case PWM::PWM3_PWM_X: + case PWM::PWM4_PWM_X: + ret.val_offset = PWMX_VAL; + break; + + default: + constexpr_assert(false, "not implemented"); + } + + switch (pwm_config.submodule) { + case PWM::Submodule0: + ret.sub_module = SM0; + ret.sub_module_bits = MCTRL_LDOK(1 << SM0); + break; + + case PWM::Submodule1: + ret.sub_module = SM1; + ret.sub_module_bits = MCTRL_LDOK(1 << SM1); + break; + + case PWM::Submodule2: + ret.sub_module = SM2; + ret.sub_module_bits = MCTRL_LDOK(1 << SM2); + break; + + case PWM::Submodule3: + ret.sub_module = SM3; + ret.sub_module_bits = MCTRL_LDOK(1 << SM3); + break; + } + + ret.gpio_in = 0; // TODO (not used yet) + + // find timer index + ret.timer_index = 0xff; + const uint32_t timer_base = getFlexPWMBaseRegister(pwm); + + for (int i = 0; i < MAX_IO_TIMERS; ++i) { + if (io_timers_conf[i].base == timer_base) { + ret.timer_index = i; + break; + } + } + + constexpr_assert(ret.timer_index != 0xff, "Timer not found"); + + return ret; +} + +static inline constexpr io_timers_t initIOPWM(PWM::FlexPWM pwm) +{ + io_timers_t ret{}; + + ret.base = getFlexPWMBaseRegister(pwm); + + return ret; +} diff --git a/platforms/nuttx/src/px4/nxp/rt117x/include/px4_arch/spi_hw_description.h b/platforms/nuttx/src/px4/nxp/rt117x/include/px4_arch/spi_hw_description.h index b736695d85..f8573c32f5 100644 --- a/platforms/nuttx/src/px4/nxp/rt117x/include/px4_arch/spi_hw_description.h +++ b/platforms/nuttx/src/px4/nxp/rt117x/include/px4_arch/spi_hw_description.h @@ -1,20 +1,20 @@ /**************************************************************************** * - * Copyright (c) 2020 PX4 Development Team. All rights reserved. + * Copyright (C) 2020 PX4 Development Team. All rights reserved. * * 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. + * 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. + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. * 3. Neither the name PX4 nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. + * 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 @@ -30,11 +30,107 @@ * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ + #pragma once +#include +#include + #if defined(CONFIG_SPI) -#include "../../../imxrt/include/px4_arch/spi_hw_description.h" +#include + +static inline constexpr px4_spi_bus_device_t initSPIDevice(uint32_t devid, SPI::CS cs_gpio, SPI::DRDY drdy_gpio = {}) +{ + px4_spi_bus_device_t ret{}; + ret.cs_gpio = getGPIOPort(cs_gpio.port) | getGPIOPin(cs_gpio.pin) | (GPIO_OUTPUT | GPIO_OUTPUT_ONE | CS_IOMUX); + + if (drdy_gpio.port != GPIO::PortInvalid) { + ret.drdy_gpio = getGPIOPort(drdy_gpio.port) | getGPIOPin(drdy_gpio.pin) | (GPIO_INPUT | DRDY_IOMUX); + } + + if (PX4_SPIDEVID_TYPE(devid) == 0) { // it's a PX4 device (internal or external) + ret.devid = PX4_SPIDEV_ID(PX4_SPI_DEVICE_ID, devid); + + } else { // it's a NuttX device (e.g. SPIDEV_FLASH(0)) + ret.devid = devid; + } + + ret.devtype_driver = PX4_SPI_DEV_ID(devid); + return ret; +} + +static inline constexpr px4_spi_bus_t initSPIBus(SPI::Bus bus, const px4_spi_bus_devices_t &devices, + GPIO::GPIOPin power_enable = {}) +{ + px4_spi_bus_t ret{}; + ret.requires_locking = false; + + for (int i = 0; i < SPI_BUS_MAX_DEVICES; ++i) { + ret.devices[i] = devices.devices[i]; + + + if (ret.devices[i].cs_gpio != 0) { + if (PX4_SPI_DEVICE_ID == PX4_SPIDEVID_TYPE(ret.devices[i].devid)) { + int same_devices_count = 0; + + for (int j = 0; j < i; ++j) { + if (ret.devices[j].cs_gpio != 0) { + same_devices_count += (ret.devices[i].devid & 0xff) == (ret.devices[j].devid & 0xff); + } + } + + // increment the 2. LSB byte to allow multiple devices of the same type + ret.devices[i].devid |= same_devices_count << 8; + + } else { + // A bus potentially requires locking if it is accessed by non-PX4 devices (i.e. NuttX drivers) + ret.requires_locking = true; + } + } + } + + ret.bus = (int)bus; + ret.is_external = false; + + if (power_enable.port != GPIO::PortInvalid) { + ret.power_enable_gpio = getGPIOPort(power_enable.port) | getGPIOPin(power_enable.pin) | + (GPIO_OUTPUT | GPIO_OUTPUT_ZERO | GENERAL_OUTPUT_IOMUX); + } + + return ret; +} + +// just a wrapper since we cannot pass brace-enclosed initialized arrays directly as arguments +struct bus_device_external_cfg_array_t { + SPI::bus_device_external_cfg_t devices[SPI_BUS_MAX_DEVICES]; +}; + +static inline constexpr px4_spi_bus_t initSPIBusExternal(SPI::Bus bus, const bus_device_external_cfg_array_t &devices) +{ + px4_spi_bus_t ret{}; + + for (int i = 0; i < SPI_BUS_MAX_DEVICES; ++i) { + if (devices.devices[i].cs_gpio.port == GPIO::PortInvalid) { + break; + } + + ret.devices[i] = initSPIDevice(i, devices.devices[i].cs_gpio, devices.devices[i].drdy_gpio); + } + + ret.bus = (int)bus; + ret.is_external = true; + ret.requires_locking = false; // external buses are never accessed by NuttX drivers + return ret; +} + +static inline constexpr SPI::bus_device_external_cfg_t initSPIConfigExternal(SPI::CS cs_gpio, SPI::DRDY drdy_gpio = {}) +{ + SPI::bus_device_external_cfg_t ret{}; + ret.cs_gpio = cs_gpio; + ret.drdy_gpio = drdy_gpio; + return ret; +} constexpr bool validateSPIConfig(const px4_spi_bus_t spi_busses_conf[SPI_BUS_MAX_BUS_ITEMS]) { diff --git a/platforms/nuttx/src/px4/nxp/rt117x/io_pins/CMakeLists.txt b/platforms/nuttx/src/px4/nxp/rt117x/io_pins/CMakeLists.txt new file mode 100644 index 0000000000..5720786e14 --- /dev/null +++ b/platforms/nuttx/src/px4/nxp/rt117x/io_pins/CMakeLists.txt @@ -0,0 +1,44 @@ +############################################################################ +# +# Copyright (c) 2015-2019 PX4 Development Team. All rights reserved. +# +# 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 PX4 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. +# +############################################################################ + +add_compile_options( + -Wno-unused-function + ) # TODO: remove once io_timer_handlerX are used + +px4_add_library(arch_io_pins + io_timer.c + pwm_servo.c + pwm_trigger.c + input_capture.c + imxrt_pinirq.c +) diff --git a/platforms/nuttx/src/px4/nxp/rt117x/io_pins/imxrt_pinirq.c b/platforms/nuttx/src/px4/nxp/rt117x/io_pins/imxrt_pinirq.c new file mode 100644 index 0000000000..e1bf45040b --- /dev/null +++ b/platforms/nuttx/src/px4/nxp/rt117x/io_pins/imxrt_pinirq.c @@ -0,0 +1,161 @@ +/**************************************************************************** + * + * Copyright (C) 2020 PX4 Development Team. All rights reserved. + * + * 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 PX4 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. + * + ****************************************************************************/ + +#include +#include + +#include + +#include + +#include "chip.h" +#include "imxrt_irq.h" +#include "hardware/imxrt_gpio.h" + +typedef struct { + int low; + int hi; +} lh_t; + + +const lh_t port_to_irq[13] = { + {_IMXRT_GPIO1_0_15_BASE, _IMXRT_GPIO1_16_31_BASE}, + {_IMXRT_GPIO2_0_15_BASE, _IMXRT_GPIO2_16_31_BASE}, + {_IMXRT_GPIO3_0_15_BASE, _IMXRT_GPIO3_16_31_BASE}, + {_IMXRT_GPIO4_0_15_BASE, _IMXRT_GPIO4_16_31_BASE}, + {_IMXRT_GPIO5_0_15_BASE, _IMXRT_GPIO5_16_31_BASE}, + {_IMXRT_GPIO6_0_15_BASE, _IMXRT_GPIO6_16_31_BASE}, + {0, 0}, // GPIO7 Not on CM7 + {0, 0}, // GPIO8 Not on CM7 + {0, 0}, // GPIO9 Not on CM7 + {0, 0}, // GPIO10 Not on CM7 + {0, 0}, // GPIO11 Not on CM7 + {0, 0}, // GPIO12 Not on CM7 + {_IMXRT_GPIO13_BASE, _IMXRT_GPIO13_BASE}, +}; + +static bool imxrt_pin_irq_valid(gpio_pinset_t pinset) +{ + int port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + lh_t irqlh = port_to_irq[port]; + return (irqlh.low != 0 && irqlh.hi != 0); +} +/**************************************************************************** + * Name: imxrt_pin_irqattach + * + * Description: + * Sets/clears GPIO based event and interrupt triggers. + * + * Input Parameters: + * - pinset: gpio pin configuration + * - rising/falling edge: enables + * - func: when non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure indicating the + * nature of the failure. + * + ****************************************************************************/ + +static int imxrt_pin_irqattach(gpio_pinset_t pinset, xcpt_t func, void *arg) +{ + int rv = -EINVAL; + volatile int port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + volatile int pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + volatile int irq; + lh_t irqlh = port_to_irq[port]; + + if (irqlh.low != 0 && irqlh.hi != 0) { + rv = OK; + irq = (pin < 16) ? irqlh.low : irqlh.hi; + irq += pin % 16; + irq_attach(irq, func, arg); + up_enable_irq(irq); + } + + return rv; +} + +/**************************************************************************** + * Name: imxrt_gpiosetevent + * + * Description: + * Sets/clears GPIO based event and interrupt triggers. + * + * Input Parameters: + * - pinset: gpio pin configuration + * - rising/falling edge: enables + * - event: generate event when set + * - func: when non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure indicating the + * nature of the failure. + * + ****************************************************************************/ +#if defined(CONFIG_IMXRT_GPIO_IRQ) +int imxrt_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, + bool event, xcpt_t func, void *arg) +{ + int ret = -ENOSYS; + + if (imxrt_pin_irq_valid(pinset)) { + if (func == NULL) { + imxrt_gpioirq_disable(pinset); + pinset &= ~GPIO_INTCFG_MASK; + ret = imxrt_config_gpio(pinset); + + } else { + + pinset &= ~GPIO_INTCFG_MASK; + + if (risingedge & fallingedge) { + pinset |= GPIO_INTBOTH_EDGES; + + } else if (risingedge) { + pinset |= GPIO_INT_RISINGEDGE; + + } else if (fallingedge) { + pinset |= GPIO_INT_FALLINGEDGE; + } + + imxrt_gpioirq_configure(pinset); + ret = imxrt_pin_irqattach(pinset, func, arg); + } + } + + return ret; +} +#endif /* CONFIG_IMXRT_GPIO_IRQ */ diff --git a/platforms/nuttx/src/px4/nxp/rt117x/io_pins/input_capture.c b/platforms/nuttx/src/px4/nxp/rt117x/io_pins/input_capture.c new file mode 100644 index 0000000000..6fb285c583 --- /dev/null +++ b/platforms/nuttx/src/px4/nxp/rt117x/io_pins/input_capture.c @@ -0,0 +1,325 @@ +/**************************************************************************** + * + * Copyright (C) 2018 PX4 Development Team. All rights reserved. + * + * 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 PX4 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. + * + ****************************************************************************/ + +/* + * @file drv_input_capture.c + * + * Servo driver supporting input capture connected to imxrt timer blocks. + * + * Works with any FLEXPWN that have input pins. + * + * Require an interrupt. + * + * + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include "hardware/imxrt_flexpwm.h" + +#define MAX_CHANNELS_PER_TIMER 2 + +#define SM_SPACING (IMXRT_FLEXPWM_SM1CNT_OFFSET-IMXRT_FLEXPWM_SM0CNT_OFFSET) + +#define _REG(_addr) (*(volatile uint16_t *)(_addr)) +#define _REG16(_base, _reg) (*(volatile uint16_t *)(_base + _reg)) +#define REG(_tmr, _sm, _reg) _REG16(io_timers[(_tmr)].base + ((_sm) * SM_SPACING), (_reg)) + +static input_capture_stats_t channel_stats[MAX_TIMER_IO_CHANNELS]; + +static struct channel_handler_entry { + capture_callback_t callback; + void *context; +} channel_handlers[MAX_TIMER_IO_CHANNELS]; + +static void input_capture_chan_handler(void *context, const io_timers_t *timer, uint32_t chan_index, + const timer_io_channels_t *chan, + hrt_abstime isrs_time, uint16_t isrs_rcnt, + uint16_t capture) +{ + channel_stats[chan_index].last_edge = px4_arch_gpioread(chan->gpio_in); + + if ((isrs_rcnt - capture) > channel_stats[chan_index].latency) { + channel_stats[chan_index].latency = (isrs_rcnt - capture); + } + + channel_stats[chan_index].edges++; + channel_stats[chan_index].last_time = isrs_time - (isrs_rcnt - capture); + uint32_t overflow = 0;//_REG32(timer, KINETIS_FTM_CSC_OFFSET(chan->timer_channel - 1)) & FTM_CSC_CHF; + + if (overflow) { + + /* Error we has a second edge before we cleared CCxR */ + + channel_stats[chan_index].overflows++; + } + + if (channel_handlers[chan_index].callback) { + channel_handlers[chan_index].callback(channel_handlers[chan_index].context, chan_index, + channel_stats[chan_index].last_time, + channel_stats[chan_index].last_edge, overflow); + } +} + +static void input_capture_bind(unsigned channel, capture_callback_t callback, void *context) +{ + irqstate_t flags = px4_enter_critical_section(); + channel_handlers[channel].callback = callback; + channel_handlers[channel].context = context; + px4_leave_critical_section(flags); +} + +static void input_capture_unbind(unsigned channel) +{ + input_capture_bind(channel, NULL, NULL); +} + +int up_input_capture_set(unsigned channel, input_capture_edge edge, capture_filter_t filter, + capture_callback_t callback, void *context) +{ + if (edge > Both) { + return -EINVAL; + } + + int rv = io_timer_validate_channel_index(channel); + + if (rv == 0) { + if (edge == Disabled) { + + io_timer_set_enable(false, IOTimerChanMode_Capture, 1 << channel); + input_capture_unbind(channel); + + } else { + + input_capture_bind(channel, callback, context); + + rv = io_timer_channel_init(channel, IOTimerChanMode_Capture, input_capture_chan_handler, context); + + if (rv != 0) { + return rv; + } + + rv = up_input_capture_set_filter(channel, filter); + + if (rv == 0) { + rv = up_input_capture_set_trigger(channel, edge); + + if (rv == 0) { + rv = io_timer_set_enable(true, IOTimerChanMode_Capture, 1 << channel); + } + } + } + } + + return rv; +} + +int up_input_capture_get_filter(unsigned channel, capture_filter_t *filter) +{ + return 0; +} +int up_input_capture_set_filter(unsigned channel, capture_filter_t filter) +{ + return 0; +} + +int up_input_capture_get_trigger(unsigned channel, input_capture_edge *edge) +{ + int rv = io_timer_validate_channel_index(channel); + + if (rv == 0) { + + rv = -ENXIO; + + /* Any pins in capture mode */ + + if (io_timer_get_channel_mode(channel) == IOTimerChanMode_Capture) { + + rv = OK; + + uint32_t timer = timer_io_channels[channel].timer_index; + uint32_t offset = timer_io_channels[channel].val_offset == PWMA_VAL ? IMXRT_FLEXPWM_SM0CAPTCTRLA_OFFSET : + IMXRT_FLEXPWM_SM0CAPTCTRLB_OFFSET; + uint32_t rvalue = REG(timer, timer_io_channels[channel].sub_module, offset); + rvalue &= SMC_EDGA0_BOTH; + + switch (rvalue) { + + case (SMC_EDGA0_RISING): + *edge = Rising; + break; + + case (SMC_EDGA0_FALLING): + *edge = Falling; + break; + + case (SMC_EDGA0_BOTH): + *edge = Both; + break; + + default: + rv = -EIO; + } + } + } + + return rv; +} +int up_input_capture_set_trigger(unsigned channel, input_capture_edge edge) +{ + int rv = io_timer_validate_channel_index(channel); + + if (rv == 0) { + + rv = -ENXIO; + + /* Any pins in capture mode */ + + if (io_timer_get_channel_mode(channel) == IOTimerChanMode_Capture) { + + uint16_t edge_bits = 0; + + switch (edge) { + case Disabled: + break; + + case Rising: + edge_bits = SMC_EDGA0_RISING; + break; + + case Falling: + edge_bits = SMC_EDGA0_FALLING; + break; + + case Both: + edge_bits = SMC_EDGA0_BOTH; + break; + + default: + return -EINVAL;; + } + + uint32_t timer = timer_io_channels[channel].timer_index; + uint32_t offset = timer_io_channels[channel].val_offset == PWMA_VAL ? IMXRT_FLEXPWM_SM0CAPTCTRLA_OFFSET : + IMXRT_FLEXPWM_SM0CAPTCTRLB_OFFSET; + irqstate_t flags = px4_enter_critical_section(); + uint32_t rvalue = REG(timer, timer_io_channels[channel].sub_module, offset); + rvalue &= ~SMC_EDGA0_BOTH; + rvalue |= edge_bits; + REG(timer, timer_io_channels[channel].sub_module, offset) = rvalue; + px4_leave_critical_section(flags); + rv = OK; + } + } + + return rv; +} + +int up_input_capture_get_callback(unsigned channel, capture_callback_t *callback, void **context) +{ + int rv = io_timer_validate_channel_index(channel); + + if (rv == 0) { + + rv = -ENXIO; + + /* Any pins in capture mode */ + + if (io_timer_get_channel_mode(channel) == IOTimerChanMode_Capture) { + + irqstate_t flags = px4_enter_critical_section(); + *callback = channel_handlers[channel].callback; + *context = channel_handlers[channel].context; + px4_leave_critical_section(flags); + rv = OK; + } + } + + return rv; + +} + +int up_input_capture_set_callback(unsigned channel, capture_callback_t callback, void *context) +{ + int rv = io_timer_validate_channel_index(channel); + + if (rv == 0) { + + rv = -ENXIO; + + /* Any pins in capture mode */ + + if (io_timer_get_channel_mode(channel) == IOTimerChanMode_Capture) { + input_capture_bind(channel, callback, context); + rv = 0; + } + } + + return rv; +} + +int up_input_capture_get_stats(unsigned channel, input_capture_stats_t *stats, bool clear) +{ + int rv = io_timer_validate_channel_index(channel); + + if (rv == 0) { + irqstate_t flags = px4_enter_critical_section(); + *stats = channel_stats[channel]; + + if (clear) { + memset(&channel_stats[channel], 0, sizeof(*stats)); + } + + px4_leave_critical_section(flags); + } + + return rv; +} diff --git a/platforms/nuttx/src/px4/nxp/rt117x/io_pins/io_timer.c b/platforms/nuttx/src/px4/nxp/rt117x/io_pins/io_timer.c new file mode 100644 index 0000000000..14bbca63e4 --- /dev/null +++ b/platforms/nuttx/src/px4/nxp/rt117x/io_pins/io_timer.c @@ -0,0 +1,775 @@ +/**************************************************************************** + * + * Copyright (C) 2018 PX4 Development Team. All rights reserved. + * + * 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 PX4 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. + * + ****************************************************************************/ + +/** + * @file io_timer.c + * + * Servo driver supporting PWM servos connected to imxrt FLEXPWM blocks. + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include "hardware/imxrt_flexpwm.h" +#include "imxrt_periphclks.h" + +static int io_timer_handler0(int irq, void *context, void *arg); +static int io_timer_handler1(int irq, void *context, void *arg); +static int io_timer_handler2(int irq, void *context, void *arg); +static int io_timer_handler3(int irq, void *context, void *arg); +static int io_timer_handler4(int irq, void *context, void *arg); +static int io_timer_handler5(int irq, void *context, void *arg); +static int io_timer_handler6(int irq, void *context, void *arg); +static int io_timer_handler7(int irq, void *context, void *arg); + +#if !defined(BOARD_PWM_FREQ) +#define BOARD_PWM_FREQ 1000000 +#endif + +#if !defined(BOARD_ONESHOT_FREQ) +#define BOARD_ONESHOT_FREQ 8000000 +#endif + +#define FLEXPWM_SRC_CLOCK_FREQ 16000000 + +#define MAX_CHANNELS_PER_TIMER 2 + +#define SM_SPACING (IMXRT_FLEXPWM_SM1CNT_OFFSET-IMXRT_FLEXPWM_SM0CNT_OFFSET) + +#define _REG(_addr) (*(volatile uint16_t *)(_addr)) +#define _REG16(_base, _reg) (*(volatile uint16_t *)(_base + _reg)) +#define REG(_tmr, _sm, _reg) _REG16(io_timers[(_tmr)].base + ((_sm) * SM_SPACING), (_reg)) + + +/* Timer register accessors */ + +#define rCNT(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CNT_OFFSET) /* Counter Register */ +#define rINIT(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0INIT_OFFSET) /* Initial Count Register */ +#define rCTRL2(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CTRL2_OFFSET) /* Control 2 Register */ +#define rCTRL(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CTRL_OFFSET) /* Control Register */ +#define rVAL0(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0VAL0_OFFSET) /* Value Register 0 */ +#define rFRACVAL1(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0FRACVAL1_OFFSET) /* Fractional Value Register 1 */ +#define rVAL1(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0VAL1_OFFSET) /* Value Register 1 */ +#define rFRACVAL2(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0FRACVAL2_OFFSET) /* Fractional Value Register 2 */ +#define rVAL2(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0VAL2_OFFSET) /* Value Register 2 */ +#define rFRACVAL3(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0FRACVAL3_OFFSET) /* Fractional Value Register 3 */ +#define rVAL3(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0VAL3_OFFSET) /* Value Register 3 */ +#define rFRACVAL4(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0FRACVAL4_OFFSET) /* Fractional Value Register 4 */ +#define rVAL4(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0VAL4_OFFSET) /* Value Register 4 */ +#define rFRACVAL5(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0FRACVAL5_OFFSET) /* Fractional Value Register 5 */ +#define rVAL5(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0VAL5_OFFSET) /* Value Register 5 */ +#define rFRCTRL(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0FRCTRL_OFFSET) /* Fractional Control Register */ +#define rOCTRL(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0OCTRL_OFFSET) /* Output Control Register */ +#define rSTS(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0STS_OFFSET) /* Status Register */ +#define rINTEN(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0INTEN_OFFSET) /* Interrupt Enable Register */ +#define rDMAEN(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0DMAEN_OFFSET) /* DMA Enable Register */ +#define rTCTRL(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0TCTRL_OFFSET) /* Output Trigger Control Register */ +#define rDISMAP0(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0DISMAP0_OFFSET) /* Fault Disable Mapping Register 0 */ +#define rDISMAP1(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0DISMAP1_OFFSET) /* Fault Disable Mapping Register 1 */ +#define rDTCNT0(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0DTCNT0_OFFSET) /* Deadtime Count Register 0 */ +#define rDTCNT1(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0DTCNT1_OFFSET) /* Deadtime Count Register 1 */ +#define rCAPTCTRLA(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CAPTCTRLA_OFFSET) /* Capture Control A Register */ +#define rCAPTCOMPA(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CAPTCOMPA_OFFSET) /* Capture Compare A Register */ +#define rCAPTCTRLB(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CAPTCTRLB_OFFSET) /* Capture Control B Register */ +#define rCAPTCOMPB(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CAPTCOMPB_OFFSET) /* Capture Compare B Register */ +#define rCAPTCTRLX(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CAPTCTRLX_OFFSET) /* Capture Control X Register */ +#define rCAPTCOMPX(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CAPTCOMPX_OFFSET) /* Capture Compare X Register */ +#define rCVAL0(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CVAL0_OFFSET) /* Capture Value 0 Register */ +#define rCVAL0CYC(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CVAL0CYC_OFFSET) /* Capture Value 0 Cycle Register */ +#define rCVAL1(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CVAL1_OFFSET) /* Capture Value 1 Register */ +#define rCVAL1CYC(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CVAL1CYC_OFFSET) /* Capture Value 1 Cycle Register */ +#define rCVAL2(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CVAL2_OFFSET) /* Capture Value 2 Register */ +#define rCVAL2CYC(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CVAL2CYC_OFFSET) /* Capture Value 2 Cycle Register */ +#define rCVAL3(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CVAL3_OFFSET) /* Capture Value 3 Register */ +#define rCVAL3CYC(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CVAL3CYC_OFFSET) /* Capture Value 3 Cycle Register */ +#define rCVAL4(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CVAL4_OFFSET) /* Capture Value 4 Register */ +#define rCVAL4CYC(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CVAL4CYC_OFFSET) /* Capture Value 4 Cycle Register */ +#define rCVAL5(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CVAL5_OFFSET) /* Capture Value 5 Register */ +#define rCVAL5CYC(_tim, _sm) REG(_tim, _sm,IMXRT_FLEXPWM_SM0CVAL5CYC_OFFSET) /* Capture Value 5 Cycle Register */ + +#define rOUTEN(_tim) REG(_tim, 0, IMXRT_FLEXPWM_OUTEN_OFFSET) /* Output Enable Register */ +#define rMASK(_tim) REG(_tim, 0, IMXRT_FLEXPWM_MASK_OFFSET) /* Mask Register */ +#define rSWCOUT(_tim) REG(_tim, 0, IMXRT_FLEXPWM_SWCOUT_OFFSET) /* Software Controlled Output Register */ +#define rDTSRCSEL(_tim) REG(_tim, 0, IMXRT_FLEXPWM_DTSRCSEL_OFFSET) /* PWM Source Select Register */ +#define rMCTRL(_tim) REG(_tim, 0, IMXRT_FLEXPWM_MCTRL_OFFSET) /* Master Control Register */ +#define rMCTRL2(_tim) REG(_tim, 0, IMXRT_FLEXPWM_MCTRL2_OFFSET) /* Master Control 2 Register */ +#define rFCTRL0(_tim) REG(_tim, 0, IMXRT_FLEXPWM_FCTRL0_OFFSET) /* Fault Control Register */ +#define rFSTS0(_tim) REG(_tim, 0, IMXRT_FLEXPWM_FSTS0_OFFSET) /* Fault Status Register */ +#define rFFILT0(_tim) REG(_tim, 0, IMXRT_FLEXPWM_FFILT0_OFFSET) /* Fault Filter Register */ +#define rFTST0(_tim) REG(_tim, 0, IMXRT_FLEXPWM_FTST0_OFFSET) /* Fault Test Register */ +#define rFCTRL20(_tim) REG(_tim, 0, IMXRT_FLEXPWM_FCTRL20_OFFSET) /* Fault Control 2 Register */ + + +// NotUsed PWMOut PWMIn Capture OneShot Trigger Dshot LED PPS Other +io_timer_channel_allocation_t channel_allocations[IOTimerChanModeSize] = { UINT16_MAX, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +typedef uint8_t io_timer_allocation_t; /* big enough to hold MAX_IO_TIMERS */ + +io_timer_channel_allocation_t timer_allocations[MAX_IO_TIMERS] = { }; + +/* Stats and handlers are only useful for Capture */ + +typedef struct channel_stat_t { + uint32_t isr_cout; + uint32_t overflows; +} channel_stat_t; + +static channel_stat_t io_timer_channel_stats[MAX_TIMER_IO_CHANNELS]; + +static struct channel_handler_entry { + channel_handler_t callback; + void *context; +} channel_handlers[MAX_TIMER_IO_CHANNELS]; + + +static int io_timer_handler(uint16_t timer_index) +{ + // Not implemented yet + UNUSED(io_timer_channel_stats); + return 0; +} + +int io_timer_handler0(int irq, void *context, void *arg) +{ + return io_timer_handler(0); +} + +int io_timer_handler1(int irq, void *context, void *arg) +{ + return io_timer_handler(1); +} + +int io_timer_handler2(int irq, void *context, void *arg) +{ + return io_timer_handler(2); +} + +int io_timer_handler3(int irq, void *context, void *arg) +{ + return io_timer_handler(3); +} + +int io_timer_handler4(int irq, void *context, void *arg) +{ + return io_timer_handler(4); +} +int io_timer_handler5(int irq, void *context, void *arg) +{ + return io_timer_handler(5); +} +int io_timer_handler6(int irq, void *context, void *arg) +{ + return io_timer_handler(6); +} +int io_timer_handler7(int irq, void *context, void *arg) +{ + return io_timer_handler(7); +} + +static inline int validate_timer_index(unsigned timer) +{ + return (timer < MAX_IO_TIMERS && io_timers[timer].base != 0) ? 0 : -EINVAL; +} + +int io_timer_allocate_timer(unsigned timer, io_timer_channel_mode_t mode) +{ + int ret = -EINVAL; + + if (validate_timer_index(timer) == 0) { + // check if timer is unused or already set to the mode we want + if (timer_allocations[timer] == IOTimerChanMode_NotUsed || timer_allocations[timer] == mode) { + timer_allocations[timer] = mode; + ret = 0; + + } else { + ret = -EBUSY; + } + } + + return ret; +} + +int io_timer_unallocate_timer(unsigned timer) +{ + int ret = -EINVAL; + + if (validate_timer_index(timer) == 0) { + timer_allocations[timer] = IOTimerChanMode_NotUsed; + ret = 0; + } + + return ret; +} + +static inline int channels_timer(unsigned channel) +{ + return timer_io_channels[channel].timer_index; +} + +static uint32_t get_channel_mask(unsigned channel) +{ + return io_timer_validate_channel_index(channel) == 0 ? 1 << channel : 0; +} + +int io_timer_validate_channel_index(unsigned channel) +{ + int rv = -EINVAL; + + if (channel < MAX_TIMER_IO_CHANNELS && timer_io_channels[channel].val_offset != 0) { + + /* test timer for validity */ + + if (io_timers[channels_timer(channel)].base != 0) { + rv = 0; + } + } + + return rv; +} + +uint32_t io_timer_channel_get_gpio_output(unsigned channel) +{ + if (io_timer_validate_channel_index(channel) != 0) { + return 0; + } + + return timer_io_channels[channel].gpio_portpin | (GPIO_OUTPUT | GPIO_OUTPUT_ZERO | IOMUX_CMOS_OUTPUT | IOMUX_PULL_KEEP + | IOMUX_SLEW_FAST); + return 0; +} + +uint32_t io_timer_channel_get_as_pwm_input(unsigned channel) +{ + if (io_timer_validate_channel_index(channel) != 0) { + return 0; + } + + return timer_io_channels[channel].gpio_in; +} + +int io_timer_get_mode_channels(io_timer_channel_mode_t mode) +{ + if (mode < IOTimerChanModeSize) { + return channel_allocations[mode]; + } + + return 0; +} + +int io_timer_get_channel_mode(unsigned channel) +{ + io_timer_channel_allocation_t bit = 1 << channel; + + for (int mode = IOTimerChanMode_NotUsed; mode < IOTimerChanModeSize; mode++) { + if (bit & channel_allocations[mode]) { + return mode; + } + } + + return -1; +} + +static int reallocate_channel_resources(uint32_t channels, io_timer_channel_mode_t mode, + io_timer_channel_mode_t new_mode) +{ + /* If caller mode is not based on current setting adjust it */ + + if ((channels & channel_allocations[IOTimerChanMode_NotUsed]) == channels) { + mode = IOTimerChanMode_NotUsed; + } + + /* Remove old set of channels from original */ + + channel_allocations[mode] &= ~channels; + + /* Will this change ?*/ + + uint32_t before = channel_allocations[new_mode] & channels; + + /* add in the new set */ + + channel_allocations[new_mode] |= channels; + + /* Indicate a mode change */ + + return before ^ channels; +} + +__EXPORT int io_timer_allocate_channel(unsigned channel, io_timer_channel_mode_t mode) +{ + irqstate_t flags = px4_enter_critical_section(); + int existing_mode = io_timer_get_channel_mode(channel); + int ret = -EBUSY; + + if (existing_mode <= IOTimerChanMode_NotUsed || existing_mode == mode) { + io_timer_channel_allocation_t bit = 1 << channel; + channel_allocations[IOTimerChanMode_NotUsed] &= ~bit; + channel_allocations[mode] |= bit; + ret = 0; + } + + px4_leave_critical_section(flags); + + return ret; +} + + +int io_timer_unallocate_channel(unsigned channel) +{ + int mode = io_timer_get_channel_mode(channel); + + if (mode > IOTimerChanMode_NotUsed) { + io_timer_channel_allocation_t bit = 1 << channel; + channel_allocations[mode] &= ~bit; + channel_allocations[IOTimerChanMode_NotUsed] |= bit; + } + + return mode; +} + +static int allocate_channel(unsigned channel, io_timer_channel_mode_t mode) +{ + int rv = -EINVAL; + + if (mode != IOTimerChanMode_NotUsed) { + rv = io_timer_validate_channel_index(channel); + + if (rv == 0) { + rv = io_timer_allocate_channel(channel, mode); + } + } + + return rv; +} + +static int timer_set_rate(unsigned channel, unsigned rate) +{ + irqstate_t flags = px4_enter_critical_section(); + rMCTRL(channels_timer(channel)) |= (timer_io_channels[channel].sub_module_bits >> MCTRL_LDOK_SHIFT) << MCTRL_CLDOK_SHIFT + ; + rVAL1(channels_timer(channel), timer_io_channels[channel].sub_module) = (BOARD_PWM_FREQ / rate) - 1; + rMCTRL(channels_timer(channel)) |= timer_io_channels[channel].sub_module_bits; + px4_leave_critical_section(flags); + return 0; +} + +static inline void io_timer_set_oneshot_mode(unsigned channel) +{ + irqstate_t flags = px4_enter_critical_section(); + uint16_t rvalue = rCTRL(channels_timer(channel), timer_io_channels[channel].sub_module); + rvalue &= ~SMCTRL_PRSC_MASK; + rvalue |= SMCTRL_PRSC_DIV2 | SMCTRL_LDMOD; + rMCTRL(channels_timer(channel)) |= (timer_io_channels[channel].sub_module_bits >> MCTRL_LDOK_SHIFT) << MCTRL_CLDOK_SHIFT + ; + rCTRL(channels_timer(channel), timer_io_channels[channel].sub_module) = rvalue; + rMCTRL(channels_timer(channel)) |= timer_io_channels[channel].sub_module_bits; + px4_leave_critical_section(flags); + +} + +static inline void io_timer_set_PWM_mode(unsigned channel) +{ + irqstate_t flags = px4_enter_critical_section(); + uint16_t rvalue = rCTRL(channels_timer(channel), timer_io_channels[channel].sub_module); + rvalue &= ~(SMCTRL_PRSC_MASK | SMCTRL_LDMOD); + rvalue |= SMCTRL_PRSC_DIV16; + rMCTRL(channels_timer(channel)) |= (timer_io_channels[channel].sub_module_bits >> MCTRL_LDOK_SHIFT) << MCTRL_CLDOK_SHIFT + ; + rCTRL(channels_timer(channel), timer_io_channels[channel].sub_module) = rvalue; + rMCTRL(channels_timer(channel)) |= timer_io_channels[channel].sub_module_bits; + px4_leave_critical_section(flags); +} + +void io_timer_trigger(unsigned channel_mask) +{ + int oneshots = io_timer_get_mode_channels(IOTimerChanMode_OneShot) & channel_mask; + struct { + uint32_t base; + uint16_t triggers; + } action_cache[MAX_IO_TIMERS] = {0}; + int actions = 0; + + /* Pre-calculate the list of channels to Trigger */ + int mask; + + for (int timer = 0; timer < MAX_IO_TIMERS; timer++) { + action_cache[actions].base = io_timers[timer].base; + + if (action_cache[actions].base) { + uint32_t first_channel_index = io_timers_channel_mapping.element[timer].first_channel_index; + uint32_t last_channel_index = first_channel_index + io_timers_channel_mapping.element[timer].channel_count; + + for (uint32_t channel = first_channel_index; channel < last_channel_index; channel++) { + mask = get_channel_mask(channel); + + if (oneshots & mask) { + action_cache[actions].triggers |= timer_io_channels[channel].sub_module_bits; + } + } + + actions++; + } + } + + /* Now do them all with the shortest delay in between */ + + irqstate_t flags = px4_enter_critical_section(); + + for (actions = 0; action_cache[actions].base != 0 && actions < MAX_IO_TIMERS; actions++) { + _REG16(action_cache[actions].base, IMXRT_FLEXPWM_MCTRL_OFFSET) |= (action_cache[actions].triggers >> MCTRL_LDOK_SHIFT) + << MCTRL_CLDOK_SHIFT ; + _REG16(action_cache[actions].base, IMXRT_FLEXPWM_MCTRL_OFFSET) |= action_cache[actions].triggers; + } + + px4_leave_critical_section(flags); +} + +int io_timer_init_timer(unsigned timer, io_timer_channel_mode_t mode) +{ + if (validate_timer_index(timer) != 0) { + return -EINVAL; + } + + io_timer_channel_mode_t previous_mode = timer_allocations[timer]; + int rv = io_timer_allocate_timer(timer, mode); + + /* Do this only once per timer */ + if (rv == 0 && previous_mode == IOTimerChanMode_NotUsed) { + + irqstate_t flags = px4_enter_critical_section(); + + /* enable the timer clock before we try to talk to it */ + + switch (io_timers[timer].base) { + case IMXRT_FLEXPWM1_BASE: + imxrt_clockall_pwm1(); + break; + + case IMXRT_FLEXPWM2_BASE: + imxrt_clockall_pwm2(); + break; + + case IMXRT_FLEXPWM3_BASE: + imxrt_clockall_pwm3(); + break; + + case IMXRT_FLEXPWM4_BASE: + imxrt_clockall_pwm4(); + break; + } + + uint32_t first_channel_index = io_timers_channel_mapping.element[timer].first_channel_index; + uint32_t last_channel_index = first_channel_index + io_timers_channel_mapping.element[timer].channel_count; + + for (uint32_t chan = first_channel_index; chan < last_channel_index; chan++) { + + /* Clear all Faults */ + rFSTS0(timer) = FSTS_FFLAG_MASK; + + rCTRL2(timer, timer_io_channels[chan].sub_module) = SMCTRL2_CLK_SEL_EXT_CLK | SMCTRL2_DBGEN | SMCTRL2_INDEP; + rCTRL(timer, timer_io_channels[chan].sub_module) = SMCTRL_PRSC_DIV16 | SMCTRL_FULL; + /* Edge aligned at 0 */ + rINIT(channels_timer(chan), timer_io_channels[chan].sub_module) = 0; + rVAL0(channels_timer(chan), timer_io_channels[chan].sub_module) = 0; + rVAL2(channels_timer(chan), timer_io_channels[chan].sub_module) = 0; + rVAL4(channels_timer(chan), timer_io_channels[chan].sub_module) = 0; + rFFILT0(timer) &= ~FFILT_FILT_PER_MASK; + rDISMAP0(timer, timer_io_channels[chan].sub_module) = 0xf000; + rDISMAP1(timer, timer_io_channels[chan].sub_module) = 0xf000; + rOUTEN(timer) |= timer_io_channels[chan].val_offset == PWMA_VAL ? OUTEN_PWMA_EN(1 << timer_io_channels[chan].sub_module) + : OUTEN_PWMB_EN(1 << timer_io_channels[chan].sub_module); + rDTSRCSEL(timer) = 0; + rMCTRL(timer) = MCTRL_LDOK(1 << timer_io_channels[chan].sub_module); + rMCTRL(timer) = timer_io_channels[chan].sub_module_bits; + io_timer_set_PWM_mode(chan); + timer_set_rate(chan, 50); + } + + px4_leave_critical_section(flags); + } + + return rv; +} + + +int io_timer_set_pwm_rate(unsigned timer, unsigned rate) +{ + /* Change only a timer that is owned by pwm or one shot */ + if (timer_allocations[timer] != IOTimerChanMode_PWMOut && timer_allocations[timer] != IOTimerChanMode_OneShot) { + return -EINVAL; + } + + /* Get the channel bits that belong to the timer and are in PWM or OneShot mode */ + + uint32_t channels = get_channel_mask(timer) & (io_timer_get_mode_channels(IOTimerChanMode_OneShot) | + io_timer_get_mode_channels(IOTimerChanMode_PWMOut)); + + /* Request to use OneShot ?*/ + + if (PWM_RATE_ONESHOT == rate) { + + /* Request to use OneShot + */ + int changed_channels = reallocate_channel_resources(channels, IOTimerChanMode_PWMOut, IOTimerChanMode_OneShot); + + /* Did the allocation change */ + if (changed_channels) { + io_timer_set_oneshot_mode(timer); + } + + } else { + + /* Request to use PWM + */ + int changed_channels = reallocate_channel_resources(channels, IOTimerChanMode_OneShot, IOTimerChanMode_PWMOut); + + if (changed_channels) { + io_timer_set_PWM_mode(timer); + } + + timer_set_rate(timer, rate); + } + + return OK; +} + +int io_timer_channel_init(unsigned channel, io_timer_channel_mode_t mode, + channel_handler_t channel_handler, void *context) +{ + if (io_timer_validate_channel_index(channel) != 0) { + return -EINVAL; + } + + uint32_t gpio = 0; + + /* figure out the GPIO config first */ + + switch (mode) { + + case IOTimerChanMode_OneShot: + case IOTimerChanMode_PWMOut: + case IOTimerChanMode_Trigger: + gpio = timer_io_channels[channel].gpio_out; + break; + + case IOTimerChanMode_PWMIn: + case IOTimerChanMode_Capture: + return -EINVAL; + break; + + case IOTimerChanMode_NotUsed: + break; + + default: + return -EINVAL; + } + + irqstate_t flags = px4_enter_critical_section(); // atomic channel allocation and hw config + + int previous_mode = io_timer_get_channel_mode(channel); + int rv = allocate_channel(channel, mode); + unsigned timer = channels_timer(channel); + + if (rv == 0) { + /* Try to reserve & initialize the timer - it will only do it once */ + + rv = io_timer_init_timer(timer, mode); + + if (rv != 0 && previous_mode == IOTimerChanMode_NotUsed) { + /* free the channel if it was not used before */ + io_timer_unallocate_channel(channel); + } + } + + /* Valid channel should now be reserved in new mode */ + + if (rv == 0) { + + /* Set up IO */ + if (gpio) { + px4_arch_configgpio(gpio); + } + + /* configure the channel */ + + REG(timer, 0, IMXRT_FLEXPWM_MCTRL_OFFSET) |= MCTRL_RUN(1 << timer_io_channels[channel].sub_module); + + channel_handlers[channel].callback = channel_handler; + channel_handlers[channel].context = context; + } + + px4_leave_critical_section(flags); + + return rv; +} + +int io_timer_set_enable(bool state, io_timer_channel_mode_t mode, io_timer_channel_allocation_t masks) +{ + switch (mode) { + case IOTimerChanMode_NotUsed: + case IOTimerChanMode_PWMOut: + case IOTimerChanMode_OneShot: + case IOTimerChanMode_Trigger: + break; + + case IOTimerChanMode_PWMIn: + case IOTimerChanMode_Capture: + default: + return -EINVAL; + } + + /* Was the request for all channels in this mode ?*/ + + if (masks == IO_TIMER_ALL_MODES_CHANNELS) { + + /* Yes - we provide them */ + + masks = channel_allocations[mode]; + + } else { + + /* No - caller provided mask */ + + /* Only allow the channels in that mode to be affected */ + + masks &= channel_allocations[mode]; + + } + + struct { + uint32_t sm_ens; + uint32_t base; + uint32_t io_index; + uint32_t gpios[MAX_TIMER_IO_CHANNELS]; + } action_cache[MAX_IO_TIMERS]; + + memset(action_cache, 0, sizeof(action_cache)); + + for (int chan_index = 0; masks != 0 && chan_index < MAX_TIMER_IO_CHANNELS; chan_index++) { + if (masks & (1 << chan_index)) { + masks &= ~(1 << chan_index); + + if (io_timer_validate_channel_index(chan_index) == 0) { + uint32_t timer_index = channels_timer(chan_index); + action_cache[timer_index].base = io_timers[timer_index].base; + action_cache[timer_index].sm_ens |= MCTRL_RUN(1 << timer_io_channels[chan_index].sub_module) | + timer_io_channels[chan_index].sub_module_bits; + action_cache[timer_index].gpios[action_cache[timer_index].io_index++] = timer_io_channels[chan_index].gpio_out; + } + } + } + + irqstate_t flags = px4_enter_critical_section(); + + for (unsigned actions = 0; actions < arraySize(action_cache); actions++) { + if (action_cache[actions].base != 0) { + for (unsigned int index = 0; index < action_cache[actions].io_index; index++) { + if (action_cache[actions].gpios[index]) { + px4_arch_configgpio(action_cache[actions].gpios[index]); + } + + _REG16(action_cache[actions].base, IMXRT_FLEXPWM_MCTRL_OFFSET) = action_cache[actions].sm_ens; + } + } + } + + px4_leave_critical_section(flags); + return 0; +} + +int io_timer_set_ccr(unsigned channel, uint16_t value) +{ + int rv = io_timer_validate_channel_index(channel); + int mode = io_timer_get_channel_mode(channel); + + if (rv == 0) { + if ((mode != IOTimerChanMode_PWMOut) && + (mode != IOTimerChanMode_OneShot) && + (mode != IOTimerChanMode_Trigger)) { + + rv = -EIO; + + } else { + irqstate_t flags = px4_enter_critical_section(); + rMCTRL(channels_timer(channel)) |= (timer_io_channels[channel].sub_module_bits >> MCTRL_LDOK_SHIFT) << MCTRL_CLDOK_SHIFT + ; + REG(channels_timer(channel), timer_io_channels[channel].sub_module, timer_io_channels[channel].val_offset) = value - 1; + rMCTRL(channels_timer(channel)) |= timer_io_channels[channel].sub_module_bits; + px4_leave_critical_section(flags); + } + } + + return rv; +} + +uint16_t io_channel_get_ccr(unsigned channel) +{ + uint16_t value = 0; + + if (io_timer_validate_channel_index(channel) == 0) { + int mode = io_timer_get_channel_mode(channel); + + if ((mode == IOTimerChanMode_PWMOut) || + (mode == IOTimerChanMode_OneShot) || + (mode == IOTimerChanMode_Trigger)) { + value = REG(channels_timer(channel), timer_io_channels[channel].sub_module, timer_io_channels[channel].val_offset) + 1; + } + } + + return value; +} + +// The rt has 1:1 group to channel +uint32_t io_timer_get_group(unsigned group) +{ + return get_channel_mask(group); +} diff --git a/platforms/nuttx/src/px4/nxp/rt117x/io_pins/pwm_servo.c b/platforms/nuttx/src/px4/nxp/rt117x/io_pins/pwm_servo.c new file mode 100644 index 0000000000..d29ca58b02 --- /dev/null +++ b/platforms/nuttx/src/px4/nxp/rt117x/io_pins/pwm_servo.c @@ -0,0 +1,165 @@ +/**************************************************************************** + * + * Copyright (C) 2018 PX4 Development Team. All rights reserved. + * + * 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 PX4 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. + * + ****************************************************************************/ + +/* + * @file drv_pwm_servo.c + * + * Servo driver supporting PWM servos connected to FLexPWM timer blocks. + * N.B. Groups:channels have a 1:1 correspondence on FlexPWM + * + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +//#include + +int up_pwm_servo_set(unsigned channel, uint16_t value) +{ + return io_timer_set_ccr(channel, value); +} + +uint16_t up_pwm_servo_get(unsigned channel) +{ + return io_channel_get_ccr(channel); +} + +int up_pwm_servo_init(uint32_t channel_mask) +{ + /* Init channels */ + uint32_t current = io_timer_get_mode_channels(IOTimerChanMode_PWMOut) | + io_timer_get_mode_channels(IOTimerChanMode_OneShot); + + // First free the current set of PWMs + + for (unsigned channel = 0; current != 0 && channel < MAX_TIMER_IO_CHANNELS; channel++) { + if (current & (1 << channel)) { + io_timer_set_enable(false, IOTimerChanMode_PWMOut, 1 << channel); + io_timer_unallocate_channel(channel); + current &= ~(1 << channel); + } + } + + + /* Now allocate the new set */ + + int ret_val = OK; + int channels_init_mask = 0; + + for (unsigned channel = 0; channel_mask != 0 && channel < MAX_TIMER_IO_CHANNELS; channel++) { + if (channel_mask & (1 << channel)) { + + // First free any that were not PWM mode before + + ret_val = io_timer_channel_init(channel, IOTimerChanMode_PWMOut, NULL, NULL); + channel_mask &= ~(1 << channel); + + if (OK == ret_val) { + channels_init_mask |= 1 << channel; + + } else if (ret_val == -EBUSY) { + /* either timer or channel already used - this is not fatal */ + ret_val = 0; + } + } + } + + return ret_val == OK ? channels_init_mask : ret_val; +} + +void up_pwm_servo_deinit(uint32_t channel_mask) +{ + /* disable the timers */ + up_pwm_servo_arm(false, channel_mask); +} + +int up_pwm_servo_set_rate_group_update(unsigned channel, unsigned rate) +{ + if (io_timer_validate_channel_index(channel) < 0) { + return ERROR; + } + + /* Allow a rate of 0 to enter oneshot mode */ + + if (rate != 0) { + + /* limit update rate to 1..10000Hz; somewhat arbitrary but safe */ + + if (rate < 1) { + return -ERANGE; + } + + if (rate > 10000) { + return -ERANGE; + } + } + + return io_timer_set_pwm_rate(channel, rate); +} + +void up_pwm_update(unsigned channel_mask) +{ + io_timer_trigger(channel_mask); +} + +uint32_t up_pwm_servo_get_rate_group(unsigned group) +{ + /* only return the set of channels in the group which we own */ + return (io_timer_get_mode_channels(IOTimerChanMode_PWMOut) | + io_timer_get_mode_channels(IOTimerChanMode_OneShot)) & + io_timer_get_group(group); +} + +void +up_pwm_servo_arm(bool armed, uint32_t channel_mask) +{ + io_timer_set_enable(armed, IOTimerChanMode_OneShot, channel_mask); + io_timer_set_enable(armed, IOTimerChanMode_PWMOut, channel_mask); +} diff --git a/platforms/nuttx/src/px4/nxp/rt117x/io_pins/pwm_trigger.c b/platforms/nuttx/src/px4/nxp/rt117x/io_pins/pwm_trigger.c new file mode 100644 index 0000000000..4f2d6d9750 --- /dev/null +++ b/platforms/nuttx/src/px4/nxp/rt117x/io_pins/pwm_trigger.c @@ -0,0 +1,115 @@ +/**************************************************************************** + * + * Copyright (C) 2018 PX4 Development Team. All rights reserved. + * + * 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 PX4 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. + * + ****************************************************************************/ + +/* + * @file drv_pwm_trigger.c + * + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +int up_pwm_trigger_set(unsigned channel, uint16_t value) +{ + return io_timer_set_ccr(channel, value); +} + +int up_pwm_trigger_init(uint32_t channel_mask) +{ + /* Init channels */ + int ret_val = OK; + int channels_init_mask = 0; + + for (unsigned channel = 0; channel_mask != 0 && channel < MAX_TIMER_IO_CHANNELS; channel++) { + if (channel_mask & (1 << channel)) { + + ret_val = io_timer_channel_init(channel, IOTimerChanMode_Trigger, NULL, NULL); + channel_mask &= ~(1 << channel); + + if (OK == ret_val) { + channels_init_mask |= 1 << channel; + + } else if (ret_val == -EBUSY) { + /* either timer or channel already used - this is not fatal */ + ret_val = 0; + } + } + } + + /* Enable the timers */ + if (ret_val == OK) { + up_pwm_trigger_arm(true); + } + + return ret_val == OK ? channels_init_mask : ret_val; +} + +void up_pwm_trigger_deinit() +{ + /* Disable the timers */ + up_pwm_trigger_arm(false); + + /* Deinit channels */ + uint32_t current = io_timer_get_mode_channels(IOTimerChanMode_Trigger); + + for (unsigned channel = 0; current != 0 && channel < MAX_TIMER_IO_CHANNELS; channel++) { + if (current & (1 << channel)) { + + io_timer_channel_init(channel, IOTimerChanMode_NotUsed, NULL, NULL); + current &= ~(1 << channel); + } + } +} + +void +up_pwm_trigger_arm(bool armed) +{ + io_timer_set_enable(armed, IOTimerChanMode_Trigger, IO_TIMER_ALL_MODES_CHANNELS); +}