nxp:imxrt 1060/1170 bifurcation and restructuring

imxrt:117x Reuse all but io_timer_hw_description and imxrt_pinirq.c

   imxrt:ADC & LPADC bifurcation and restructuring

   imxrt:hrt support Up to GPT6

   nxp/rt117x:adc Corrected
This commit is contained in:
David Sidrane
2023-11-15 11:10:47 -05:00
committed by Daniel Agar
parent d2915743cb
commit e3f8d53718
56 changed files with 3864 additions and 5566 deletions
@@ -136,6 +136,7 @@ static int dn_to_ordinal(uint16_t dn)
static int read_id_dn(int *id, uint32_t gpio_drive, uint32_t gpio_sense, int adc_channel)
{
int rv = -EIO;
const unsigned int samples = 16;
/*
* Step one is there resistors?
@@ -158,6 +159,7 @@ static int read_id_dn(int *id, uint32_t gpio_drive, uint32_t gpio_sense, int adc
imxrt_config_gpio(PX4_MAKE_GPIO_OUTPUT_CLEAR(gpio_sense));
up_udelay(100); /* About 10 TC assuming 485 K */
/* Read Drive lines while sense are driven low */
@@ -170,7 +172,6 @@ static int read_id_dn(int *id, uint32_t gpio_drive, uint32_t gpio_sense, int adc
imxrt_gpio_write(PX4_MAKE_GPIO_OUTPUT_CLEAR(gpio_sense), 1);
up_udelay(100); /* About 10 TC assuming 485 K */
/* Read Drive lines while sense are driven high */
int high = imxrt_gpio_read(PX4_MAKE_GPIO_INPUT(gpio_drive));
@@ -192,7 +193,6 @@ static int read_id_dn(int *id, uint32_t gpio_drive, uint32_t gpio_sense, int adc
if ((high ^ low) && low == 0) {
/* Yes - Fire up the ADC (it has once control) */
if (px4_arch_adc_init(HW_REV_VER_ADC_BASE) == OK) {
/* Read the value */
@@ -221,12 +221,14 @@ static int read_id_dn(int *id, uint32_t gpio_drive, uint32_t gpio_sense, int adc
/* Turn the drive lines to digital outputs High */
imxrt_config_gpio(gpio_drive);
return rv;
}
static int determine_hw_info(int *revision, int *version)
{
int dn;
int rv = read_id_dn(&dn, GPIO_HW_REV_DRIVE, GPIO_HW_REV_SENSE, ADC_HW_REV_SENSE_CHANNEL);
+17 -1
View File
@@ -94,12 +94,28 @@
# define HRT_CLOCK_ALL() imxrt_clockall_gpt_bus() /* The Clock Gating macro for this GPT */
#elif HRT_TIMER == 2
# define HRT_CLOCK_ALL() imxrt_clockall_gpt2_bus() /* The Clock Gating macro for this GPT */
#elif HRT_TIMER == 3
# define HRT_CLOCK_ALL() imxrt_clockall_gpt3_bus() /* The Clock Gating macro for this GPT */
#elif HRT_TIMER == 4
# define HRT_CLOCK_ALL() imxrt_clockall_gpt4_bus() /* The Clock Gating macro for this GPT */
#elif HRT_TIMER == 5
# define HRT_CLOCK_ALL() imxrt_clockall_gpt5_bus() /* The Clock Gating macro for this GPT */
#elif HRT_TIMER == 6
# define HRT_CLOCK_ALL() imxrt_clockall_gpt6_bus() /* The Clock Gating macro for this GPT */
#endif
#if HRT_TIMER == 1 && defined(CONFIG_IMXRT_GPT1)
# error must not set CONFIG_IMXRT_GPT1=y and HRT_TIMER=1
#elif HRT_TIMER == 2 && defined(CONFIG_IMXRT_GPT2)
# error must not set CONFIG_IMXRT_GPT2=y and HRT_TIMER=2
#elif HRT_TIMER == 3 && defined(CONFIG_IMXRT_GPT3)
# error must not set CONFIG_IMXRT_GPT3=y and HRT_TIMER=3
#elif HRT_TIMER == 4 && defined(CONFIG_IMXRT_GPT4)
# error must not set CONFIG_IMXRT_GPT4=y and HRT_TIMER=4
#elif HRT_TIMER == 5 && defined(CONFIG_IMXRT_GPT5)
# error must not set CONFIG_IMXRT_GPT5=y and HRT_TIMER=5
#elif HRT_TIMER == 6 && defined(CONFIG_IMXRT_GPT6)
# error must not set CONFIG_IMXRT_GPT6=y and HRT_TIMER=6
#endif
/*
@@ -165,7 +181,7 @@
# define STATUS_HRT CAT(GPT_SR_OF, HRT_TIMER_CHANNEL) /* OF Output Compare Flag */
# define OFIE_HRT CAT3(GPT_IR_OF, HRT_TIMER_CHANNEL,IE) /* Output Compare Interrupt Enable */
#if (HRT_TIMER_CHANNEL > 1) || (HRT_TIMER_CHANNEL > 3)
#if (HRT_TIMER_CHANNEL < 1) || (HRT_TIMER_CHANNEL > 3)
# error HRT_TIMER_CHANNEL must be a value between 1 and 3
#endif
@@ -1,397 +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>
#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
@@ -119,6 +119,7 @@ typedef struct timer_io_channels_t {
#define PWMA_VAL IMXRT_FLEXPWM_SM0VAL3_OFFSET
#define PWMB_VAL IMXRT_FLEXPWM_SM0VAL5_OFFSET
#define PWMX_VAL IMXRT_FLEXPWM_SM0VAL0_OFFSET //FIXME
typedef void (*channel_handler_t)(void *context, const io_timers_t *timer, uint32_t chan_index,
@@ -1,611 +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 <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;
}
@@ -0,0 +1,169 @@
/****************************************************************************
*
* Copyright (c) 2022 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 px4io_serial.h
*
* Serial Interface definition for PX4IO
*/
#pragma once
#include <board_config.h>
#include <px4_platform_common/px4_config.h>
#include <px4_platform_common/micro_hal.h>
#include <perf/perf_counter.h>
#include <drivers/device/device.h>
#include <modules/px4iofirmware/protocol.h>
class PX4IO_serial : public device::Device
{
public:
PX4IO_serial();
virtual ~PX4IO_serial();
virtual int init() = 0;
virtual int read(unsigned offset, void *data, unsigned count = 1);
virtual int write(unsigned address, void *data, unsigned count = 1);
protected:
/**
* Does the PX4IO_serial instance initialization.
* @param io_buffer The IO buffer that should be used for transfers.
* @return 0 on success.
*/
int init(IOPacket *io_buffer);
/**
* Start the transaction with IO and wait for it to complete.
*/
virtual int _bus_exchange(IOPacket *_packet) = 0;
/**
* Performance counters.
*/
perf_counter_t _pc_txns;
perf_counter_t _pc_retries;
perf_counter_t _pc_timeouts;
perf_counter_t _pc_crcerrs;
perf_counter_t _pc_protoerrs;
perf_counter_t _pc_uerrs;
perf_counter_t _pc_idle;
perf_counter_t _pc_badidle;
private:
/*
* XXX tune this value
*
* At 1.5Mbps each register takes 13.3µs, and we always transfer a full packet.
* Packet overhead is 26µs for the four-byte header.
*
* 32 registers = 451µs
*
* Maybe we can just send smaller packets (e.g. 8 regs) and loop for larger (less common)
* transfers? Could cause issues with any regs expecting to be written atomically...
*/
IOPacket *_io_buffer_ptr;
/** bus-ownership lock */
px4_sem_t _bus_semaphore;
/* do not allow top copying this class */
PX4IO_serial(PX4IO_serial &);
PX4IO_serial &operator = (const PX4IO_serial &);
};
#include <imxrt_edma.h>
class ArchPX4IOSerial : public PX4IO_serial
{
public:
ArchPX4IOSerial();
ArchPX4IOSerial(ArchPX4IOSerial &) = delete;
ArchPX4IOSerial &operator = (const ArchPX4IOSerial &) = delete;
virtual ~ArchPX4IOSerial();
virtual int init();
virtual int ioctl(unsigned operation, unsigned &arg);
protected:
/**
* Start the transaction with IO and wait for it to complete.
*/
int _bus_exchange(IOPacket *_packet);
private:
DMACH_HANDLE _tx_dma;
DMACH_HANDLE _rx_dma;
IOPacket *_current_packet;
/** saved DMA status */
static const unsigned _dma_status_done = 0x00000000;
static const unsigned _dma_status_inactive = 0x00000001;
static const unsigned _dma_status_waiting = 0x00000002;
volatile int _rx_dma_result;
/** client-waiting lock/signal */
px4_sem_t _completion_semaphore;
/**
* DMA completion handler.
*/
static void _dma_callback(DMACH_HANDLE handle, void *arg, bool done, int result);
void _do_rx_dma_callback(bool done, int result);
/**
* Serial interrupt handler.
*/
static int _interrupt(int vector, void *context, void *arg);
void _do_interrupt();
/**
* Cancel any DMA in progress with an error.
*/
void _abort_dma();
/**
* Performance counters.
*/
perf_counter_t _pc_dmaerrs;
/**
* IO Buffer storage
*/
static uint8_t _io_buffer_storage[] px4_cache_aligned_data();
};
@@ -48,14 +48,10 @@ typedef struct {
} lh_t;
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_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},
};
@@ -283,7 +283,7 @@ uint32_t io_timer_channel_get_gpio_output(unsigned channel)
}
return timer_io_channels[channel].gpio_portpin | (GPIO_OUTPUT | GPIO_OUTPUT_ZERO | IOMUX_CMOS_OUTPUT | IOMUX_PULL_KEEP
| IOMUX_DRIVE_33OHM | IOMUX_SPEED_MEDIUM | IOMUX_SLEW_FAST);
| IOMUX_SLEW_FAST);
return 0;
}
@@ -42,7 +42,11 @@
#include <stdio.h>
#include <string.h>
#include <arm_internal.h>
#ifdef CONFIG_ARCH_FAMILY_IMXRT117x
#include <hardware/rt117x/imxrt117x_ocotp.h>
#else
#include <hardware/imxrt_ocotp.h>
#endif
#define CPU_UUID_BYTE_FORMAT_ORDER {3, 2, 1, 0, 7, 6, 5, 4}
#define SWAP_UINT32(x) (((x) >> 24) | (((x) & 0x00ff0000) >> 8) | (((x) & 0x0000ff00) << 8) | ((x) << 24))
@@ -89,9 +93,13 @@ void board_get_uuid32(uuid_uint32_t uuid_words)
* word [0] word[1]
* SJC_CHALL[63:32] [31:00]
*/
#ifdef CONFIG_ARCH_FAMILY_IMXRT117x
uuid_words[0] = getreg32(IMXRT_OCOTP_FUSE(0x10));
uuid_words[1] = getreg32(IMXRT_OCOTP_FUSE(0x11));
#else
uuid_words[0] = getreg32(IMXRT_OCOTP_CFG1);
uuid_words[1] = getreg32(IMXRT_OCOTP_CFG0);
#endif
}
int board_get_uuid32_formated(char *format_buffer, int size,
@@ -39,10 +39,46 @@
#include <px4_platform_common/px4_config.h>
#include <px4_platform_common/defines.h>
#include <chip.h>
#include <hardware/imxrt_usb_analog.h>
#include "arm_internal.h"
#ifdef CONFIG_ARCH_FAMILY_IMXRT117x
# include <hardware/rt117x/imxrt117x_ocotp.h>
# include <hardware/rt117x/imxrt117x_anadig.h>
#else
# include <chip.h>
# include <hardware/imxrt_usb_analog.h>
#endif
#ifdef CONFIG_ARCH_FAMILY_IMXRT117x
#define CHIP_TAG "i.MX RT11?0 r??"
#define CHIP_TAG_LEN sizeof(CHIP_TAG)-1
#define SI_REV(n) ((n & 0x7000000) >> 24)
#define DIFPROG_TYPE(n) ((n & 0xF000) >> 12)
#define DIFPROG_REV_MAJOR(n) ((n & 0xF0) >> 4)
#define DIFPROG_REV_MINOR(n) ((n & 0xF))
int board_mcu_version(char *rev, const char **revstr, const char **errata)
{
uint32_t info = getreg32(IMXRT_ANADIG_MISC_MISC_DIFPROG);
static char chip[sizeof(CHIP_TAG)] = CHIP_TAG;
*revstr = chip;
chip[CHIP_TAG_LEN - 6] = '0' + DIFPROG_TYPE(info);
chip[CHIP_TAG_LEN - 2] = 'A' + (DIFPROG_REV_MAJOR(info) - 10);
chip[CHIP_TAG_LEN - 1] = '0' + DIFPROG_REV_MINOR(info);
*rev = '0' + SI_REV(getreg32(IMXRT_OCOTP_FUSE(18)));
if (errata) {
*errata = NULL;
}
return 0;
}
#else
#define DIGPROG_MINOR_SHIFT 0
#define DIGPROG_MINOR_MASK (0xff << DIGPROG_MINOR_SHIFT)
@@ -74,3 +110,5 @@ int board_mcu_version(char *rev, const char **revstr, const char **errata)
return 0;
}
#endif
@@ -42,3 +42,5 @@ add_subdirectory(../imxrt/led_pwm led_pwm)
add_subdirectory(../imxrt/io_pins io_pins)
add_subdirectory(../imxrt/tone_alarm tone_alarm)
add_subdirectory(../imxrt/version version)
add_subdirectory(px4io_serial)
@@ -32,4 +32,14 @@
****************************************************************************/
#pragma once
#include "../../../imxrt/include/px4_arch/adc.h"
#include <board_config.h>
#if !defined(HW_REV_VER_ADC_BASE)
# define HW_REV_VER_ADC_BASE IMXRT_ADC1_BASE
#endif
#if !defined(SYSTEM_ADC_BASE)
# define SYSTEM_ADC_BASE IMXRT_ADC1_BASE
#endif
#include <px4_platform/adc.h>
@@ -1,20 +1,20 @@
/****************************************************************************
*
* Copyright (c) 2019 PX4 Development Team. All rights reserved.
* Copyright (C) 2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@@ -30,7 +30,368 @@
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#pragma once
#include "../../../imxrt/include/px4_arch/hw_description.h"
#include <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;
}
@@ -0,0 +1,36 @@
/****************************************************************************
*
* Copyright (c) 2022 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 "../../../imxrt/include/px4_arch/px4io_serial.h"
@@ -1,20 +1,20 @@
/****************************************************************************
*
* Copyright (c) 2020 PX4 Development Team. All rights reserved.
* Copyright (C) 2020 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@@ -30,11 +30,113 @@
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#pragma once
#include <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])
{
@@ -0,0 +1,36 @@
############################################################################
#
# 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.
#
############################################################################
px4_add_library(arch_px4io_serial
px4io_serial.cpp
)
@@ -0,0 +1,516 @@
/****************************************************************************
*
* Copyright (c) 2022 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 px4io_serial.cpp
*
* Serial interface for PX4IO on RT1062
*/
#include <syslog.h>
#include <px4_arch/px4io_serial.h>
#include <nuttx/cache.h>
#include "hardware/imxrt_lpuart.h"
#include "hardware/imxrt_dmamux.h"
#include "imxrt_lowputc.h"
#include "imxrt_edma.h"
#include "imxrt_periphclks.h"
/* serial register accessors */
#define REG(_x) (*(volatile uint32_t *)(PX4IO_SERIAL_BASE + (_x)))
#define rBAUD REG(IMXRT_LPUART_BAUD_OFFSET)
#define rSTAT_ERR_FLAGS_MASK (LPUART_STAT_PF | LPUART_STAT_FE | LPUART_STAT_NF | LPUART_STAT_OR)
#define rSTAT REG(IMXRT_LPUART_STAT_OFFSET)
#define rCTRL REG(IMXRT_LPUART_CTRL_OFFSET)
#define rDATA REG(IMXRT_LPUART_DATA_OFFSET)
#define DMA_BUFFER_MASK (ARMV7M_DCACHE_LINESIZE - 1)
#define DMA_ALIGN_UP(n) (((n) + DMA_BUFFER_MASK) & ~DMA_BUFFER_MASK)
uint8_t ArchPX4IOSerial::_io_buffer_storage[DMA_ALIGN_UP(sizeof(IOPacket))];
ArchPX4IOSerial::ArchPX4IOSerial() :
_tx_dma(nullptr),
_rx_dma(nullptr),
_current_packet(nullptr),
_rx_dma_result(_dma_status_inactive),
_completion_semaphore(SEM_INITIALIZER(0)),
_pc_dmaerrs(perf_alloc(PC_COUNT, MODULE_NAME": DMA errors"))
{
}
ArchPX4IOSerial::~ArchPX4IOSerial()
{
if (_tx_dma != nullptr) {
imxrt_dmach_stop(_tx_dma);
imxrt_dmach_free(_tx_dma);
}
if (_rx_dma != nullptr) {
imxrt_dmach_stop(_rx_dma);
imxrt_dmach_free(_rx_dma);
}
/* reset the UART */
rCTRL = 0;
/* detach our interrupt handler */
up_disable_irq(PX4IO_SERIAL_VECTOR);
irq_detach(PX4IO_SERIAL_VECTOR);
/* restore the GPIOs */
px4_arch_unconfiggpio(PX4IO_SERIAL_TX_GPIO);
px4_arch_unconfiggpio(PX4IO_SERIAL_RX_GPIO);
/* Disable clock for the USART peripheral */
PX4IO_SERIAL_CLOCK_OFF();
/* and kill our semaphores */
px4_sem_destroy(&_completion_semaphore);
perf_free(_pc_dmaerrs);
}
int
ArchPX4IOSerial::init()
{
/* initialize base implementation */
int r = PX4IO_serial::init((IOPacket *)&_io_buffer_storage[0]);
if (r != 0) {
return r;
}
/* allocate DMA */
_tx_dma = imxrt_dmach_alloc(PX4IO_SERIAL_TX_DMAMAP | DMAMUX_CHCFG_ENBL, 0);
_rx_dma = imxrt_dmach_alloc(PX4IO_SERIAL_RX_DMAMAP | DMAMUX_CHCFG_ENBL, 0);
if ((_tx_dma == nullptr) || (_rx_dma == nullptr)) {
return -1;
}
struct uart_config_s config = {
.baud = PX4IO_SERIAL_BITRATE,
.parity = 0, /* 0=none, 1=odd, 2=even */
.bits = 8, /* Number of bits (5-9) */
.stopbits2 = false, /* true: Configure with 2 stop bits instead of 1 */
.userts = false, /* True: Assert RTS when there are data to be sent */
.invrts = false, /* True: Invert sense of RTS pin (true=active high) */
.usects = false, /* True: Condition transmission on CTS asserted */
.users485 = false, /* True: Assert RTS while transmission progresses */
};
int rv = imxrt_lpuart_configure(PX4IO_SERIAL_BASE, &config);
if (rv == OK) {
/* configure pins for serial use */
px4_arch_configgpio(PX4IO_SERIAL_TX_GPIO);
px4_arch_configgpio(PX4IO_SERIAL_RX_GPIO);
/* attach serial interrupt handler */
irq_attach(PX4IO_SERIAL_VECTOR, _interrupt, this);
up_enable_irq(PX4IO_SERIAL_VECTOR);
/* Idel after Stop, , enable error and line idle interrupts */
uint32_t regval = rCTRL;
regval &= ~(LPUART_CTRL_IDLECFG_MASK | LPUART_CTRL_ILT);
regval |= LPUART_CTRL_ILT | LPUART_CTRL_IDLECFG_1 | LPUART_CTRL_ILIE |
LPUART_CTRL_RE | LPUART_CTRL_TE;
rCTRL = regval;
/* create semaphores */
px4_sem_init(&_completion_semaphore, 0, 0);
/* _completion_semaphore use case is a signal */
px4_sem_setprotocol(&_completion_semaphore, SEM_PRIO_NONE);
/* XXX this could try talking to IO */
}
return rv;
}
int
ArchPX4IOSerial::ioctl(unsigned operation, unsigned &arg)
{
switch (operation) {
case 1: /* XXX magic number - test operation */
switch (arg) {
case 0:
syslog(LOG_INFO, "test 0\n");
/* kill DMA, this is a PIO test */
imxrt_dmach_stop(_tx_dma);
imxrt_dmach_stop(_rx_dma);
/* disable UART DMA */
rBAUD &= ~(LPUART_BAUD_RDMAE | LPUART_BAUD_TDMAE);
for (;;) {
while (!(rSTAT & LPUART_STAT_TDRE))
;
rDATA = 0x55;
}
return 0;
case 1: {
unsigned fails = 0;
for (unsigned count = 0;; count++) {
uint16_t value = count & 0xffff;
if (write((PX4IO_PAGE_TEST << 8) | PX4IO_P_TEST_LED, &value, 1) != 0) {
fails++;
}
if (count >= 5000) {
syslog(LOG_INFO, "==== test 1 : %u failures ====\n", fails);
perf_print_counter(_pc_txns);
perf_print_counter(_pc_retries);
perf_print_counter(_pc_timeouts);
perf_print_counter(_pc_crcerrs);
perf_print_counter(_pc_dmaerrs);
perf_print_counter(_pc_protoerrs);
perf_print_counter(_pc_uerrs);
perf_print_counter(_pc_idle);
perf_print_counter(_pc_badidle);
count = 0;
}
}
return 0;
}
case 2:
syslog(LOG_INFO, "test 2\n");
return 0;
}
default:
break;
}
return -1;
}
int
ArchPX4IOSerial::_bus_exchange(IOPacket *_packet)
{
// to be paranoid ensure all previous DMA transfers are cleared
_abort_dma();
_current_packet = _packet;
/* clear data that may be in the RDR and clear overrun error: */
while (rSTAT & LPUART_STAT_RDRF) {
(void)rDATA;
}
rSTAT |= (rSTAT_ERR_FLAGS_MASK | LPUART_STAT_IDLE); /* clear the flags */
/* start RX DMA */
perf_begin(_pc_txns);
/* DMA setup time ~3µs */
_rx_dma_result = _dma_status_waiting;
struct imxrt_edma_xfrconfig_s rx_config;
rx_config.saddr = PX4IO_SERIAL_BASE + IMXRT_LPUART_DATA_OFFSET;
rx_config.daddr = reinterpret_cast<uint32_t>(_current_packet);
rx_config.soff = 0;
rx_config.doff = 1;
rx_config.iter = sizeof(*_current_packet);
rx_config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE;
rx_config.ssize = EDMA_8BIT;
rx_config.dsize = EDMA_8BIT;
rx_config.nbytes = 1;
#ifdef CONFIG_IMXRT_EDMA_ELINK
rx_config.linkch = NULL;
#endif
imxrt_dmach_xfrsetup(_rx_dma, &rx_config);
/* Enable receive DMA for the UART */
rBAUD |= LPUART_BAUD_RDMAE;
imxrt_dmach_start(_rx_dma, _dma_callback, (void *)this);
/* Clean _current_packet, so DMA can see the data */
up_clean_dcache((uintptr_t)_current_packet,
(uintptr_t)_current_packet + DMA_ALIGN_UP(sizeof(IOPacket)));
/* start TX DMA - no callback if we also expect a reply */
/* DMA setup time ~3µs */
struct imxrt_edma_xfrconfig_s tx_config;
tx_config.saddr = reinterpret_cast<uint32_t>(_current_packet);
tx_config.daddr = PX4IO_SERIAL_BASE + IMXRT_LPUART_DATA_OFFSET;
tx_config.soff = 1;
tx_config.doff = 0;
tx_config.iter = sizeof(*_current_packet);
tx_config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE;
tx_config.ssize = EDMA_8BIT;
tx_config.dsize = EDMA_8BIT;
tx_config.nbytes = 1;
#ifdef CONFIG_IMXRT_EDMA_ELINK
tx_config.linkch = NULL;
#endif
imxrt_dmach_xfrsetup(_tx_dma, &tx_config);
/* Enable transmit DMA for the UART */
rBAUD |= LPUART_BAUD_TDMAE;
imxrt_dmach_start(_tx_dma, nullptr, nullptr);
/* compute the deadline for a 10ms timeout */
struct timespec abstime;
clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_nsec += 10 * 1000 * 1000;
if (abstime.tv_nsec >= 1000 * 1000 * 1000) {
abstime.tv_sec++;
abstime.tv_nsec -= 1000 * 1000 * 1000;
}
/* wait for the transaction to complete - 64 bytes @ 1.5Mbps ~426µs */
int ret;
for (;;) {
ret = sem_timedwait(&_completion_semaphore, &abstime);
if (ret == OK) {
/* check for DMA errors */
if (_rx_dma_result != OK) {
// stream transfer error, ensure all DMA is also stopped before exiting early
_abort_dma();
perf_count(_pc_dmaerrs);
ret = -EIO;
break;
}
/* check packet CRC - corrupt packet errors mean IO receive CRC error */
uint8_t crc = _current_packet->crc;
_current_packet->crc = 0;
if ((crc != crc_packet(_current_packet)) || (PKT_CODE(*_current_packet) == PKT_CODE_CORRUPT)) {
_abort_dma();
perf_count(_pc_crcerrs);
ret = -EIO;
break;
}
/* successful txn (may still be reporting an error) */
break;
}
if (errno == ETIMEDOUT) {
/* something has broken - clear out any partial DMA state and reconfigure */
_abort_dma();
perf_count(_pc_timeouts);
perf_cancel(_pc_txns); /* don't count this as a transaction */
break;
}
/* we might? see this for EINTR */
syslog(LOG_ERR, "unexpected ret %d/%d\n", ret, errno);
}
/* reset DMA status */
_rx_dma_result = _dma_status_inactive;
/* update counters */
perf_end(_pc_txns);
return ret;
}
void
ArchPX4IOSerial::_dma_callback(DMACH_HANDLE handle, void *arg, bool done, int result)
{
if (arg != nullptr) {
ArchPX4IOSerial *ps = reinterpret_cast<ArchPX4IOSerial *>(arg);
ps->_do_rx_dma_callback(done, result);
}
}
void
ArchPX4IOSerial::_do_rx_dma_callback(bool done, int result)
{
/* on completion of a reply, wake the waiter */
if (done && _rx_dma_result == _dma_status_waiting) {
if (result != OK) {
/* check for packet overrun - this will occur after DMA completes */
uint32_t sr = rSTAT;
if (sr & (LPUART_STAT_OR | LPUART_STAT_RDRF)) {
while (rSTAT & LPUART_STAT_RDRF) {
(void)rDATA;
}
rSTAT = sr & (LPUART_STAT_OR);
result = -EIO;
}
}
/* save RX status */
_rx_dma_result = result;
/* disable UART DMA */
rBAUD &= ~(LPUART_BAUD_RDMAE | LPUART_BAUD_TDMAE);
/* complete now */
px4_sem_post(&_completion_semaphore);
}
}
int
ArchPX4IOSerial::_interrupt(int irq, void *context, void *arg)
{
if (arg != nullptr) {
ArchPX4IOSerial *instance = reinterpret_cast<ArchPX4IOSerial *>(arg);
instance->_do_interrupt();
}
return 0;
}
void
ArchPX4IOSerial::_do_interrupt()
{
uint32_t sr = rSTAT;
while (rSTAT & LPUART_STAT_RDRF) {
(void)rDATA; /* read DATA register to clear RDRF */
}
rSTAT |= sr & rSTAT_ERR_FLAGS_MASK; /* clear flags */
if (sr & (LPUART_STAT_OR | /* overrun error - packet was too big for DMA or DMA was too slow */
LPUART_STAT_NF | /* noise error - we have lost a byte due to noise */
LPUART_STAT_FE)) { /* framing error - start/stop bit lost or line break */
/*
* If we are in the process of listening for something, these are all fatal;
* abort the DMA with an error.
*/
if (_rx_dma_result == _dma_status_waiting) {
_abort_dma();
perf_count(_pc_uerrs);
/* complete DMA as though in error */
_do_rx_dma_callback(true, -EIO);
return;
}
/* XXX we might want to use FE / line break as an out-of-band handshake ... handle it here */
/* don't attempt to handle IDLE if it's set - things went bad */
return;
}
if (sr & LPUART_STAT_IDLE) {
rSTAT |= LPUART_STAT_IDLE; /* clear IDLE flag */
/* if there is DMA reception going on, this is a short packet */
if (_rx_dma_result == _dma_status_waiting) {
/* Invalidate _current_packet, so we get fresh data from RAM */
up_invalidate_dcache((uintptr_t)_current_packet,
(uintptr_t)_current_packet + DMA_ALIGN_UP(sizeof(IOPacket)));
/* verify that the received packet is complete */
size_t length = sizeof(*_current_packet) - imxrt_dmach_getcount(_rx_dma);
if ((length < 1) || (length < PKT_SIZE(*_current_packet))) {
perf_count(_pc_badidle);
/* stop the receive DMA */
imxrt_dmach_stop(_rx_dma);
/* complete the short reception */
_do_rx_dma_callback(true, -EIO);
return;
}
perf_count(_pc_idle);
/* complete the short reception */
_do_rx_dma_callback(true, _dma_status_done);
/* stop the receive DMA */
imxrt_dmach_stop(_rx_dma);
}
}
}
void
ArchPX4IOSerial::_abort_dma()
{
/* stop DMA */
imxrt_dmach_stop(_tx_dma);
imxrt_dmach_stop(_rx_dma);
/* disable UART DMA */
rBAUD &= ~(LPUART_BAUD_RDMAE | LPUART_BAUD_TDMAE);
/* clear data that may be in the DATA register and clear overrun error: */
uint32_t sr = rSTAT;
if (sr & (LPUART_STAT_OR | LPUART_STAT_RDRF)) {
while (rSTAT & LPUART_STAT_RDRF) {
(void)rDATA;
}
}
rSTAT |= sr & (rSTAT_ERR_FLAGS_MASK | LPUART_STAT_IDLE); /* clear flags */
}
@@ -0,0 +1,44 @@
############################################################################
#
# 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.
#
############################################################################
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(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,248 @@
/****************************************************************************
*
* 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 rVERID(base_address) REG(base_address, IMXRT_LPADC_VERID_OFFSET) /* Version ID Register */
#define rPARAM(base_address) REG(base_address, IMXRT_LPADC_PARAM_OFFSET) /* Parameter Register */
#define rCTRL(base_address) REG(base_address, IMXRT_LPADC_CTRL_OFFSET) /* LPADC Control Register */
#define rSTAT(base_address) REG(base_address, IMXRT_LPADC_STAT_OFFSET) /* LPADC Status Register */
#define rIE(base_address) REG(base_address, IMXRT_LPADC_IE_OFFSET) /* Interrupt Enable Register */
#define rDE(base_address) REG(base_address, IMXRT_LPADC_DE_OFFSET) /* DMA Enable Register */
#define rCFG(base_address) REG(base_address, IMXRT_LPADC_CFG_OFFSET) /* LPADC Configuration Register */
#define rPAUSE(base_address) REG(base_address, IMXRT_LPADC_PAUSE_OFFSET) /* LPADC Pause Register */
#define rFCTRL(base_address) REG(base_address, IMXRT_LPADC_FCTRL_OFFSET) /* LPADC FIFO Control Register */
#define rSWTRIG(base_address) REG(base_address, IMXRT_LPADC_SWTRIG_OFFSET) /* Software Trigger Register */
#define rCMDL1(base_address) REG(base_address, IMXRT_LPADC_CMDL1_OFFSET) /* LPADC Command Low Buffer Register */
#define rCMDH1(base_address) REG(base_address, IMXRT_LPADC_CMDH1_OFFSET) /* LPADC Command High Buffer Register */
#define rCMDL2(base_address) REG(base_address, IMXRT_LPADC_CMDL2_OFFSET) /* LPADC Command Low Buffer Register */
#define rCMDH2(base_address) REG(base_address, IMXRT_LPADC_CMDH2_OFFSET) /* LPADC Command High Buffer Register */
#define rCMDL3(base_address) REG(base_address, IMXRT_LPADC_CMDL3_OFFSET) /* LPADC Command Low Buffer Register */
#define rCMDH3(base_address) REG(base_address, IMXRT_LPADC_CMDH3_OFFSET) /* LPADC Command High Buffer Register */
#define rCMDL4(base_address) REG(base_address, IMXRT_LPADC_CMDL4_OFFSET) /* LPADC Command Low Buffer Register */
#define rCMDH4(base_address) REG(base_address, IMXRT_LPADC_CMDH4_OFFSET) /* LPADC Command High Buffer Register */
#define rCMDL5(base_address) REG(base_address, IMXRT_LPADC_CMDL5_OFFSET) /* LPADC Command Low Buffer Register */
#define rCMDH5(base_address) REG(base_address, IMXRT_LPADC_CMDH5_OFFSET) /* LPADC Command High Buffer Register */
#define rCMDL6(base_address) REG(base_address, IMXRT_LPADC_CMDL6_OFFSET) /* LPADC Command Low Buffer Register */
#define rCMDH6(base_address) REG(base_address, IMXRT_LPADC_CMDH6_OFFSET) /* LPADC Command High Buffer Register */
#define rCMDL7(base_address) REG(base_address, IMXRT_LPADC_CMDL7_OFFSET) /* LPADC Command Low Buffer Register */
#define rCMDH7(base_address) REG(base_address, IMXRT_LPADC_CMDH7_OFFSET) /* LPADC Command High Buffer Register */
#define rCMDL8(base_address) REG(base_address, IMXRT_LPADC_CMDL8_OFFSET) /* LPADC Command Low Buffer Register */
#define rCMDH8(base_address) REG(base_address, IMXRT_LPADC_CMDH8_OFFSET) /* LPADC Command High Buffer Register */
#define rCMDL9(base_address) REG(base_address, IMXRT_LPADC_CMDL9_OFFSET) /* LPADC Command Low Buffer Register */
#define rCMDH9(base_address) REG(base_address, IMXRT_LPADC_CMDH9_OFFSET) /* LPADC Command High Buffer Register */
#define rCMDL10(base_address) REG(base_address, IMXRT_LPADC_CMDL10_OFFSET) /* LPADC Command Low Buffer Register */
#define rCMDH10(base_address) REG(base_address, IMXRT_LPADC_CMDH10_OFFSET) /* LPADC Command High Buffer Register */
#define rCMDL11(base_address) REG(base_address, IMXRT_LPADC_CMDL11_OFFSET) /* LPADC Command Low Buffer Register */
#define rCMDH11(base_address) REG(base_address, IMXRT_LPADC_CMDH11_OFFSET) /* LPADC Command High Buffer Register */
#define rCMDL12(base_address) REG(base_address, IMXRT_LPADC_CMDL12_OFFSET) /* LPADC Command Low Buffer Register */
#define rCMDH12(base_address) REG(base_address, IMXRT_LPADC_CMDH12_OFFSET) /* LPADC Command High Buffer Register */
#define rCMDL13(base_address) REG(base_address, IMXRT_LPADC_CMDL13_OFFSET) /* LPADC Command Low Buffer Register */
#define rCMDH13(base_address) REG(base_address, IMXRT_LPADC_CMDH13_OFFSET) /* LPADC Command High Buffer Register */
#define rCMDL14(base_address) REG(base_address, IMXRT_LPADC_CMDL14_OFFSET) /* LPADC Command Low Buffer Register */
#define rCMDH14(base_address) REG(base_address, IMXRT_LPADC_CMDH14_OFFSET) /* LPADC Command High Buffer Register */
#define rCMDL15(base_address) REG(base_address, IMXRT_LPADC_CMDL15_OFFSET) /* LPADC Command Low Buffer Register */
#define rCMDH15(base_address) REG(base_address, IMXRT_LPADC_CMDH15_OFFSET) /* LPADC Command High Buffer Register */
#define rRESFIFO(base_address) REG(base_address, IMXRT_LPADC_RESFIFO_OFFSET) /* LPADC Data Result FIFO Register */
#define rTCTRL0(base_address) REG(base_address, IMXRT_LPADC_TCTRL0_OFFSET) /* Trigger Control Register */
#define rTCTRL1(base_address) REG(base_address, IMXRT_LPADC_TCTRL1_OFFSET) /* Trigger Control Register */
#define rTCTRL2(base_address) REG(base_address, IMXRT_LPADC_TCTRL2_OFFSET) /* Trigger Control Register */
#define rTCTRL3(base_address) REG(base_address, IMXRT_LPADC_TCTRL3_OFFSET) /* Trigger Control Register */
#define rTCTRL4(base_address) REG(base_address, IMXRT_LPADC_TCTRL4_OFFSET) /* Trigger Control Register */
#define rTCTRL5(base_address) REG(base_address, IMXRT_LPADC_TCTRL5_OFFSET) /* Trigger Control Register */
#define rTCTRL6(base_address) REG(base_address, IMXRT_LPADC_TCTRL6_OFFSET) /* Trigger Control Register */
#define rTCTRL7(base_address) REG(base_address, IMXRT_LPADC_TCTRL7_OFFSET) /* Trigger Control Register */
#define rCV1(base_address) REG(base_address, IMXRT_LPADC_CV1_OFFSET) /* Compare Value Register */
#define rCV2(base_address) REG(base_address, IMXRT_LPADC_CV2_OFFSET) /* Compare Value Register */
#define rCV3(base_address) REG(base_address, IMXRT_LPADC_CV3_OFFSET) /* Compare Value Register */
#define rCV4(base_address) REG(base_address, IMXRT_LPADC_CV4_OFFSET) /* Compare Value Register */
int px4_arch_adc_init(uint32_t base_address)
{
static bool once = false;
if (!once) {
once = true;
/* Input is ADCx_CLK_ROOT_SYS_PLL2_CLK with devide by 6.
* 528 Mhz / 6 = 88 Mhz.
*/
if (base_address == IMXRT_LPADC1_BASE) {
imxrt_clockall_adc1();
} else if (base_address == IMXRT_LPADC2_BASE) {
imxrt_clockall_adc2();
}
irqstate_t flags = px4_enter_critical_section();
rCTRL(base_address) |= IMXRT_LPADC_CTRL_RST;
rCTRL(base_address) &= ~IMXRT_LPADC_CTRL_RST;
rCTRL(base_address) |= IMXRT_LPADC_CTRL_RSTFIFO;
rCFG(base_address) = IMXRT_LPADC_CFG_REFSEL_REFSEL_0 | IMXRT_LPADC_CFG_PWREN | IMXRT_LPADC_CFG_PWRSEL_PWRSEL_3 |
IMXRT_LPADC_CFG_PUDLY(128);
rCTRL(base_address) = IMXRT_LPADC_CTRL_ADCEN;
px4_leave_critical_section(flags);
/* Read ADC1 vtemp_sensor_plus */
rCMDL1(base_address) = IMXRT_LPADC_CMDL1_ADCH_ADCH_7;
rCMDH1(base_address) = IMXRT_LPADC_CMDH1_STS_STS_7 | IMXRT_LPADC_CMDH1_AVGS_AVGS_0;
rTCTRL0(base_address) = IMXRT_LPADC_TCTRL0_TCMD_TCMD_1;
rSTAT(base_address) = IMXRT_LPADC_STAT_FOF;
/* kick off a sample and wait for it to complete */
hrt_abstime now = hrt_absolute_time();
rSWTRIG(base_address) = IMXRT_LPADC_SWTRIG_SWT0;
while (!(rSTAT(base_address) & IMXRT_LPADC_STAT_RDY)) {
/* don't wait for more than 100us, since that means something broke -
* should reset here if we see this
*/
if ((hrt_absolute_time() - now) > 100) {
rCTRL(base_address) &= ~IMXRT_LPADC_CTRL_ADCEN;
return -4;
}
}
int32_t r = (rRESFIFO(base_address) & IMXRT_LPADC_RESFIFO_D_MASK) >> 3;
UNUSED(r);
rCTRL(base_address) &= ~IMXRT_LPADC_CTRL_ADCEN;
} // once
return 0;
}
void px4_arch_adc_uninit(uint32_t base_address)
{
rCTRL(base_address) &= ~IMXRT_LPADC_CTRL_ADCEN;
if (base_address == IMXRT_LPADC1_BASE) {
imxrt_clockoff_adc1();
} else if (base_address == IMXRT_LPADC2_BASE) {
imxrt_clockoff_adc2();
}
}
uint32_t px4_arch_adc_sample(uint32_t base_address, unsigned channel)
{
uint32_t absel = (channel & 1) ? IMXRT_LPADC_CMDL1_ABSEL : 0;
channel >>= 1;
irqstate_t flags = px4_enter_critical_section();
/* clear any previous results */
rCTRL(base_address) |= IMXRT_LPADC_CTRL_RSTFIFO;
rCMDL1(base_address) = absel | (channel & IMXRT_LPADC_CMDL1_ADCH_MASK);
rCMDH1(base_address) = IMXRT_LPADC_CMDH1_STS_STS_7 | IMXRT_LPADC_CMDH1_AVGS_AVGS_0;
rTCTRL0(base_address) = IMXRT_LPADC_TCTRL0_TCMD_TCMD_1;
rSTAT(base_address) = IMXRT_LPADC_STAT_FOF;
rCTRL(base_address) = IMXRT_LPADC_CTRL_ADCEN;
up_udelay(1);
rSWTRIG(base_address) = IMXRT_LPADC_SWTRIG_SWT0;
/* wait for the conversion to complete */
hrt_abstime now = hrt_absolute_time();
while (!(rSTAT(base_address) & IMXRT_LPADC_STAT_RDY)) {
/* don't wait for more than 30us, since that means something broke
* should reset here if we see this
*/
if ((hrt_absolute_time() - now) > 30) {
rCTRL(base_address) &= ~IMXRT_LPADC_CTRL_ADCEN;
px4_leave_critical_section(flags);
return UINT32_MAX;
}
}
/* read the result and clear COCO0 */
uint32_t result = (rRESFIFO(base_address) & IMXRT_LPADC_RESFIFO_D_MASK) >> 3;
rCTRL(base_address) &= ~IMXRT_LPADC_CTRL_ADCEN;
px4_leave_critical_section(flags);
return result;
}
float px4_arch_adc_reference_v()
{
return BOARD_ADC_POS_REF_V;
}
uint32_t px4_arch_adc_temp_sensor_mask()
{
return 0;
}
uint32_t px4_arch_adc_dn_fullcount(void)
{
return 1 << 12; // 12 bit ADC
}
@@ -0,0 +1,45 @@
/****************************************************************************
*
* 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 <board_config.h>
#if !defined(HW_REV_VER_ADC_BASE)
# define HW_REV_VER_ADC_BASE IMXRT_LPADC1_BASE
#endif
#if !defined(SYSTEM_ADC_BASE)
# define SYSTEM_ADC_BASE IMXRT_LPADC1_BASE
#endif
#include <px4_platform/adc.h>
@@ -0,0 +1,475 @@
/****************************************************************************
*
* 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.
*
****************************************************************************/
#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_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
@@ -0,0 +1,35 @@
/****************************************************************************
*
* 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 "../../../imxrt/include/px4_arch/i2c_hw_description.h"
@@ -0,0 +1,36 @@
/****************************************************************************
*
* 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 "../../../imxrt/include/px4_arch/io_timer.h"
@@ -0,0 +1,700 @@
/****************************************************************************
*
* 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 <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>
#if !defined(CONFIG_ARCH_CHIP_MIMXRT1176DVMAA)
# error "This code has only been validated with IMXRT1176. Make sure it is correct before using it on another board."
#endif
static inline constexpr timer_io_channels_t initIOTimerChannel(const io_timers_t io_timers_conf[MAX_IO_TIMERS],
PWM::FlexPWMConfig pwm_config, IOMUX::Pad pad)
{
timer_io_channels_t ret{};
PWM::FlexPWM pwm {};
// FlexPWM 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_B1_23) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_23_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN23;
} else if (pad == IOMUX::Pad::GPIO_AD_00) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_00_INDEX);
ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN31;
}
break;
case PWM::Submodule1:
if (pad == IOMUX::Pad::GPIO_EMC_B1_25) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_25_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN25;
} else if (pad == IOMUX::Pad::GPIO_AD_02) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_02_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN1;
}
break;
case PWM::Submodule2:
if (pad == IOMUX::Pad::GPIO_EMC_B1_27) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_27_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN27;
} else if (pad == IOMUX::Pad::GPIO_AD_04) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_04_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN3;
}
break;
case PWM::Submodule3:
if (pad == IOMUX::Pad::GPIO_EMC_B1_38) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_38_INDEX);
ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN6;
}
break;
}
break;
case PWM::PWM1_PWM_B:
pwm = PWM::FlexPWM1;
switch (pwm_config.submodule) {
case PWM::Submodule0:
if (pad == IOMUX::Pad::GPIO_EMC_B1_24) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_24_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN24;
} else if (pad == IOMUX::Pad::GPIO_AD_01) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_01_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN0;
}
break;
case PWM::Submodule1:
if (pad == IOMUX::Pad::GPIO_EMC_B1_26) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_26_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN26;
} else if (pad == IOMUX::Pad::GPIO_AD_03) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_03_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN2;
}
break;
case PWM::Submodule2:
if (pad == IOMUX::Pad::GPIO_EMC_B1_28) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_28_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN28;
} else if (pad == IOMUX::Pad::GPIO_AD_05) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_05_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN4;
}
break;
case PWM::Submodule3:
if (pad == IOMUX::Pad::GPIO_EMC_B1_39) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_39_INDEX);
ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN7;
}
break;
}
break;
case PWM::PWM1_PWM_X:
pwm = PWM::FlexPWM1;
switch (pwm_config.submodule) {
case PWM::Submodule0:
if (pad == IOMUX::Pad::GPIO_AD_06) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_06_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN5;
}
break;
case PWM::Submodule1:
if (pad == IOMUX::Pad::GPIO_AD_07) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_07_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN6;
}
break;
case PWM::Submodule2:
if (pad == IOMUX::Pad::GPIO_AD_08) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_08_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN7;
}
break;
case PWM::Submodule3:
if (pad == IOMUX::Pad::GPIO_AD_09) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_09_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN8;
}
break;
}
break;
case PWM::PWM2_PWM_A:
pwm = PWM::FlexPWM2;
switch (pwm_config.submodule) {
case PWM::Submodule0:
if (pad == IOMUX::Pad::GPIO_EMC_B1_06) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_06_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN6;
} else if (pad == IOMUX::Pad::GPIO_AD_24) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_24_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN23;
}
break;
case PWM::Submodule1:
if (pad == IOMUX::Pad::GPIO_EMC_B1_08) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_08_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN8;
} else if (pad == IOMUX::Pad::GPIO_AD_26) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_26_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN25;
}
break;
case PWM::Submodule2:
if (pad == IOMUX::Pad::GPIO_EMC_B1_10) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_10_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN10;
} else if (pad == IOMUX::Pad::GPIO_AD_28) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_28_INDEX);
ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN27;
}
break;
case PWM::Submodule3:
if (pad == IOMUX::Pad::GPIO_EMC_B1_19) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_19_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN19;
}
break;
}
break;
case PWM::PWM2_PWM_B:
pwm = PWM::FlexPWM2;
switch (pwm_config.submodule) {
case PWM::Submodule0:
if (pad == IOMUX::Pad::GPIO_EMC_B1_07) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_07_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN7;
} else if (pad == IOMUX::Pad::GPIO_AD_25) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_25_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN24;
}
break;
case PWM::Submodule1:
if (pad == IOMUX::Pad::GPIO_EMC_B1_09) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_09_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN9;
} else if (pad == IOMUX::Pad::GPIO_AD_27) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_27_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN26;
}
break;
case PWM::Submodule2:
if (pad == IOMUX::Pad::GPIO_EMC_B1_11) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_11_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN11;
} else if (pad == IOMUX::Pad::GPIO_AD_29) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT4 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_29_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN28;
}
break;
case PWM::Submodule3:
if (pad == IOMUX::Pad::GPIO_EMC_B1_20) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_20_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN20;
}
break;
}
break;
case PWM::PWM2_PWM_X:
pwm = PWM::FlexPWM2;
switch (pwm_config.submodule) {
case PWM::Submodule0:
if (pad == IOMUX::Pad::GPIO_AD_10) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_10_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN9;
}
break;
case PWM::Submodule1:
if (pad == IOMUX::Pad::GPIO_AD_11) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_11_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN10;
}
break;
case PWM::Submodule2:
if (pad == IOMUX::Pad::GPIO_AD_12) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_12_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN11;
}
break;
case PWM::Submodule3:
if (pad == IOMUX::Pad::GPIO_AD_13) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_13_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN12;
}
break;
}
break;
case PWM::PWM3_PWM_A:
pwm = PWM::FlexPWM3;
switch (pwm_config.submodule) {
case PWM::Submodule0:
if (pad == IOMUX::Pad::GPIO_EMC_B1_29) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_29_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN29;
} else if (pad == IOMUX::Pad::GPIO_EMC_B2_00) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_00_INDEX);
ret.gpio_portpin = GPIO_PORT2 | GPIO_PIN10;
}
break;
case PWM::Submodule1:
if (pad == IOMUX::Pad::GPIO_EMC_B1_31) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_31_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN31;
} else if (pad == IOMUX::Pad::GPIO_EMC_B2_02) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_02_INDEX);
ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN12;
}
break;
case PWM::Submodule2:
if (pad == IOMUX::Pad::GPIO_EMC_B1_33) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_33_INDEX);
ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN1;
} else if (pad == IOMUX::Pad::GPIO_EMC_B2_04) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_04_INDEX);
ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN14;
}
break;
case PWM::Submodule3:
if (pad == IOMUX::Pad::GPIO_EMC_B1_21) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_21_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN21;
} else if (pad == IOMUX::Pad::GPIO_EMC_B2_06) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_06_INDEX);
ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN16;
}
break;
}
break;
case PWM::PWM3_PWM_B:
pwm = PWM::FlexPWM3;
switch (pwm_config.submodule) {
case PWM::Submodule0:
if (pad == IOMUX::Pad::GPIO_EMC_B1_30) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_30_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN30;
} else if (pad == IOMUX::Pad::GPIO_EMC_B2_01) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_01_INDEX);
ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN11;
}
break;
case PWM::Submodule1:
if (pad == IOMUX::Pad::GPIO_EMC_B1_32) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_32_INDEX);
ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN0;
} else if (pad == IOMUX::Pad::GPIO_EMC_B2_03) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_03_INDEX);
ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN13;
}
break;
case PWM::Submodule2:
if (pad == IOMUX::Pad::GPIO_EMC_B1_34) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_34_INDEX);
ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN2;
} else if (pad == IOMUX::Pad::GPIO_EMC_B2_05) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_05_INDEX);
ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN15;
}
break;
case PWM::Submodule3:
if (pad == IOMUX::Pad::GPIO_EMC_B1_22) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_22_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN22;
} else if (pad == IOMUX::Pad::GPIO_EMC_B2_07) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B2_07_INDEX);
ret.gpio_portpin = GPIO_PORT8 | GPIO_PIN17;
}
break;
}
break;
case PWM::PWM3_PWM_X:
pwm = PWM::FlexPWM3;
switch (pwm_config.submodule) {
case PWM::Submodule0:
if (pad == IOMUX::Pad::GPIO_AD_14) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_14_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN13;
}
break;
case PWM::Submodule1:
if (pad == IOMUX::Pad::GPIO_AD_15) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_15_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN14;
}
break;
case PWM::Submodule2:
if (pad == IOMUX::Pad::GPIO_AD_16) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_16_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN15;
}
break;
case PWM::Submodule3:
if (pad == IOMUX::Pad::GPIO_AD_17) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_17_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN16;
}
break;
}
break;
case PWM::PWM4_PWM_A:
pwm = PWM::FlexPWM4;
switch (pwm_config.submodule) {
case PWM::Submodule0:
if (pad == IOMUX::Pad::GPIO_EMC_B1_00) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_00_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN0;
}
break;
case PWM::Submodule1:
if (pad == IOMUX::Pad::GPIO_EMC_B1_02) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_02_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN2;
}
break;
case PWM::Submodule2:
if (pad == IOMUX::Pad::GPIO_EMC_B1_04) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_04_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN4;
}
break;
case PWM::Submodule3:
if (pad == IOMUX::Pad::GPIO_EMC_B1_17) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_17_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN17;
}
break;
}
break;
case PWM::PWM4_PWM_B:
pwm = PWM::FlexPWM4;
switch (pwm_config.submodule) {
case PWM::Submodule0:
if (pad == IOMUX::Pad::GPIO_EMC_B1_01) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_01_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN1;
}
break;
case PWM::Submodule1:
if (pad == IOMUX::Pad::GPIO_EMC_B1_03) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_03_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN3;
}
break;
case PWM::Submodule2:
if (pad == IOMUX::Pad::GPIO_EMC_B1_05) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_05_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN5;
}
break;
case PWM::Submodule3:
if (pad == IOMUX::Pad::GPIO_EMC_B1_18) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT1 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_B1_18_INDEX);
ret.gpio_portpin = GPIO_PORT1 | GPIO_PIN18;
}
break;
}
break;
case PWM::PWM4_PWM_X:
pwm = PWM::FlexPWM4;
switch (pwm_config.submodule) {
case PWM::Submodule0:
if (pad == IOMUX::Pad::GPIO_AD_18) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_18_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN17;
}
break;
case PWM::Submodule1:
if (pad == IOMUX::Pad::GPIO_AD_19) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_19_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN18;
}
break;
case PWM::Submodule2:
if (pad == IOMUX::Pad::GPIO_AD_20) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_20_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN19;
}
break;
case PWM::Submodule3:
if (pad == IOMUX::Pad::GPIO_AD_21) {
ret.gpio_out = GPIO_PERIPH | GPIO_ALT11 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_21_INDEX);
ret.gpio_portpin = GPIO_PORT9 | GPIO_PIN20;
}
break;
}
break;
}
constexpr_assert(ret.gpio_out != 0, "Invalid PWM/Pad config");
ret.gpio_out |= IOMUX_CMOS_OUTPUT | IOMUX_PULL_NONE | IOMUX_DRIVE_HIGHSTRENGTH | IOMUX_SLEW_FAST;
switch (pwm_config.module) {
case PWM::PWM1_PWM_A:
case PWM::PWM2_PWM_A:
case PWM::PWM3_PWM_A:
case PWM::PWM4_PWM_A:
ret.val_offset = PWMA_VAL;
break;
case PWM::PWM1_PWM_B:
case PWM::PWM2_PWM_B:
case PWM::PWM3_PWM_B:
case PWM::PWM4_PWM_B:
ret.val_offset = PWMB_VAL;
break;
case PWM::PWM1_PWM_X:
case PWM::PWM2_PWM_X:
case PWM::PWM3_PWM_X:
case PWM::PWM4_PWM_X:
ret.val_offset = PWMX_VAL;
break;
default:
constexpr_assert(false, "not implemented");
}
switch (pwm_config.submodule) {
case PWM::Submodule0:
ret.sub_module = SM0;
ret.sub_module_bits = MCTRL_LDOK(1 << SM0);
break;
case PWM::Submodule1:
ret.sub_module = SM1;
ret.sub_module_bits = MCTRL_LDOK(1 << SM1);
break;
case PWM::Submodule2:
ret.sub_module = SM2;
ret.sub_module_bits = MCTRL_LDOK(1 << SM2);
break;
case PWM::Submodule3:
ret.sub_module = SM3;
ret.sub_module_bits = MCTRL_LDOK(1 << SM3);
break;
}
ret.gpio_in = 0; // TODO (not used yet)
// find timer index
ret.timer_index = 0xff;
const uint32_t timer_base = getFlexPWMBaseRegister(pwm);
for (int i = 0; i < MAX_IO_TIMERS; ++i) {
if (io_timers_conf[i].base == timer_base && io_timers_conf[i].submodle == ret.sub_module) {
ret.timer_index = i;
break;
}
}
constexpr_assert(ret.timer_index != 0xff, "Timer not found");
return ret;
}
static inline constexpr io_timers_t initIOPWM(PWM::FlexPWM pwm, PWM::FlexPWMSubmodule sub)
{
io_timers_t ret{};
ret.base = getFlexPWMBaseRegister(pwm);
ret.submodle = sub;
return ret;
}
@@ -0,0 +1,108 @@
/****************************************************************************
*
* 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 "../../../nxp_common/include/px4_arch/micro_hal.h"
__BEGIN_DECLS
#define PX4_SOC_ARCH_ID PX4_SOC_ARCH_ID_NXPIMXRT1176
#// Fixme: using ??
#define PX4_BBSRAM_SIZE 2048
#define PX4_BBSRAM_GETDESC_IOCTL 0
#define PX4_NUMBER_I2C_BUSES 2 //FIXME
#define GPIO_OUTPUT_SET GPIO_OUTPUT_ONE
#define GPIO_OUTPUT_CLEAR GPIO_OUTPUT_ZERO
#include <chip.h>
#include <imxrt_lpspi.h>
#include <imxrt_lpi2c.h>
#include <imxrt_iomuxc.h>
//# include <imxrt_uid.h> todo:Upsteam UID access
/* imxrt defines the 64 bit UUID as
*
* OCOTP 0x410 bits 31:0
* OCOTP 0x420 bits 63:32
*
* PX4 uses the words in bigendian order MSB to LSB
* word [0] [1]
* bits 63-32, 31-00,
*/
#define PX4_CPU_UUID_BYTE_LENGTH 8
#define PX4_CPU_UUID_WORD32_LENGTH (PX4_CPU_UUID_BYTE_LENGTH/sizeof(uint32_t))
/* The mfguid will be an array of bytes with
* MSD @ index 0 - LSD @ index PX4_CPU_MFGUID_BYTE_LENGTH-1
*
* It will be converted to a string with the MSD on left and LSD on the right most position.
*/
#define PX4_CPU_MFGUID_BYTE_LENGTH PX4_CPU_UUID_BYTE_LENGTH
/* define common formating across all commands */
#define PX4_CPU_UUID_WORD32_FORMAT "%08x"
#define PX4_CPU_UUID_WORD32_SEPARATOR ":"
#define PX4_CPU_UUID_WORD32_UNIQUE_H 0 /* Least significant digits change the most (die wafer,X,Y */
#define PX4_CPU_UUID_WORD32_UNIQUE_M 1 /* Most significant digits change the least (lot#) */
/* Separator nnn:nnn:nnnn 2 char per byte term */
#define PX4_CPU_UUID_WORD32_FORMAT_SIZE (PX4_CPU_UUID_WORD32_LENGTH-1+(2*PX4_CPU_UUID_BYTE_LENGTH)+1)
#define PX4_CPU_MFGUID_FORMAT_SIZE ((2*PX4_CPU_MFGUID_BYTE_LENGTH)+1)
/* bus_num is 1 based on imx and must be translated from the legacy one based */
#define PX4_BUS_OFFSET 0 /* imxrt buses are 1 based no adjustment needed */
#define px4_spibus_initialize(bus_num_1based) imxrt_lpspibus_initialize(PX4_BUS_NUMBER_FROM_PX4(bus_num_1based))
#define px4_i2cbus_initialize(bus_num_1based) imxrt_i2cbus_initialize(PX4_BUS_NUMBER_FROM_PX4(bus_num_1based))
#define px4_i2cbus_uninitialize(pdev) imxrt_i2cbus_uninitialize(pdev)
#define px4_arch_configgpio(pinset) imxrt_config_gpio(pinset)
#define px4_arch_unconfiggpio(pinset)
#define px4_arch_gpioread(pinset) imxrt_gpio_read(pinset)
#define px4_arch_gpiowrite(pinset, value) imxrt_gpio_write(pinset, value)
int imxrt_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, bool event, xcpt_t func, void *arg);
#define px4_arch_gpiosetevent(pinset,r,f,e,fp,a) imxrt_gpiosetevent(pinset,r,f,e,fp,a)
#define PX4_MAKE_GPIO_INPUT(gpio) (((gpio) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | (GPIO_INPUT ))
#define PX4_MAKE_GPIO_OUTPUT_CLEAR(gpio) (((gpio) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | (GPIO_OUTPUT | GPIO_OUTPUT_ZERO | IOMUX_CMOS_OUTPUT | IOMUX_PULL_KEEP | IOMUX_SLEW_FAST))
#define PX4_MAKE_GPIO_OUTPUT_SET(gpio) (((gpio) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | (GPIO_OUTPUT | GPIO_OUTPUT_ONE | IOMUX_CMOS_OUTPUT | IOMUX_PULL_KEEP | IOMUX_SLEW_FAST))
__END_DECLS
@@ -7,14 +7,14 @@
* 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
@@ -40,12 +40,6 @@
#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{};
@@ -137,4 +131,9 @@ static inline constexpr SPI::bus_device_external_cfg_t initSPIConfigExternal(SPI
ret.drdy_gpio = drdy_gpio;
return ret;
}
constexpr bool validateSPIConfig(const px4_spi_bus_t spi_busses_conf[SPI_BUS_MAX_BUS_ITEMS])
{
return true;
}
#endif // CONFIG_SPI
@@ -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
../../imxrt/io_pins/io_timer.c
../../imxrt/io_pins/pwm_servo.c
../../imxrt/io_pins/pwm_trigger.c
../../imxrt/io_pins/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 */