mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-05-21 10:07:34 +08:00
nxp:imxrt 1060/1170 bifurcation and restructuring
This commit is contained in:
@@ -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 <stdint.h>
|
||||
|
||||
#include "hardware/imxrt_flexpwm.h"
|
||||
|
||||
#include <px4_platform_common/constexpr_util.h>
|
||||
|
||||
#include <board_config.h>
|
||||
#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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 <px4_arch/hw_description.h>
|
||||
#include <px4_platform_common/spi.h>
|
||||
|
||||
#if defined(CONFIG_SPI)
|
||||
|
||||
#include <imxrt_gpio.h>
|
||||
|
||||
//#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
|
||||
@@ -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},
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
@@ -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 <stdint.h>
|
||||
|
||||
#include "hardware/imxrt_flexpwm.h"
|
||||
|
||||
#include <px4_platform_common/constexpr_util.h>
|
||||
|
||||
#include <board_config.h>
|
||||
#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
|
||||
|
||||
@@ -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 <px4_platform_common/px4_config.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -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 <px4_arch/io_timer.h>
|
||||
#include <px4_arch/hw_description.h>
|
||||
#include <px4_platform_common/constexpr_util.h>
|
||||
#include <px4_platform_common/px4_config.h>
|
||||
#include <px4_platform/io_timer_init.h>
|
||||
|
||||
#include <hardware/imxrt_tmr.h>
|
||||
#include <hardware/imxrt_flexpwm.h>
|
||||
#include <imxrt_gpio.h>
|
||||
#include <imxrt_iomuxc.h>
|
||||
#include <hardware/imxrt_pinmux.h>
|
||||
|
||||
#include <board_config.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -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 <px4_arch/hw_description.h>
|
||||
#include <px4_platform_common/spi.h>
|
||||
|
||||
#if defined(CONFIG_SPI)
|
||||
|
||||
#include "../../../imxrt/include/px4_arch/spi_hw_description.h"
|
||||
#include <imxrt_gpio.h>
|
||||
|
||||
#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])
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
@@ -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 <board_config.h>
|
||||
#include <stdint.h>
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <drivers/drv_adc.h>
|
||||
#include <px4_arch/adc.h>
|
||||
|
||||
#include <hardware/imxrt_adc.h>
|
||||
#include <imxrt_periphclks.h>
|
||||
|
||||
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
|
||||
}
|
||||
@@ -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 <stdint.h>
|
||||
|
||||
#include "hardware/imxrt_flexpwm.h"
|
||||
|
||||
#include <px4_platform_common/constexpr_util.h>
|
||||
|
||||
#include <board_config.h>
|
||||
#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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 <px4_arch/hw_description.h>
|
||||
#include <px4_platform_common/spi.h>
|
||||
|
||||
#if defined(CONFIG_SPI)
|
||||
|
||||
#include "../../../imxrt/include/px4_arch/spi_hw_description.h"
|
||||
#include <imxrt_gpio.h>
|
||||
|
||||
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])
|
||||
{
|
||||
|
||||
@@ -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
|
||||
)
|
||||
@@ -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 <px4_platform_common/px4_config.h>
|
||||
#include <systemlib/px4_macros.h>
|
||||
|
||||
#include <arch/board/board.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#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 */
|
||||
@@ -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 <px4_platform_common/px4_config.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <time.h>
|
||||
#include <queue.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <arch/board/board.h>
|
||||
#include <drivers/drv_input_capture.h>
|
||||
#include <px4_arch/io_timer.h>
|
||||
|
||||
#include <chip.h>
|
||||
#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;
|
||||
}
|
||||
@@ -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 <px4_platform_common/px4_config.h>
|
||||
#include <systemlib/px4_macros.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <time.h>
|
||||
#include <queue.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <arch/board/board.h>
|
||||
#include <drivers/drv_pwm_output.h>
|
||||
|
||||
#include <px4_arch/io_timer.h>
|
||||
|
||||
#include <chip.h>
|
||||
#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);
|
||||
}
|
||||
@@ -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 <px4_platform_common/px4_config.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <time.h>
|
||||
#include <queue.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <arch/board/board.h>
|
||||
#include <drivers/drv_pwm_output.h>
|
||||
|
||||
#include <px4_arch/io_timer.h>
|
||||
|
||||
//#include <chip.h>
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -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 <px4_platform_common/px4_config.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <time.h>
|
||||
#include <queue.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <arch/board/board.h>
|
||||
#include <drivers/drv_pwm_trigger.h>
|
||||
|
||||
#include <px4_arch/io_timer.h>
|
||||
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user