From 6ec106a0edfebf737308592ef82ddfe1b0223f3f Mon Sep 17 00:00:00 2001 From: Niklas Hauser <121870655+niklaut@users.noreply.github.com> Date: Fri, 31 Oct 2025 13:19:10 +0100 Subject: [PATCH 001/139] INA2xx: Debounce battery connection state (#25786) To prevent critical low battery messages on a single I2C issue. --- src/drivers/power_monitor/ina220/ina220.cpp | 2 - src/drivers/power_monitor/ina226/ina226.cpp | 42 +++++++++++++------ src/drivers/power_monitor/ina226/ina226.h | 4 ++ src/drivers/power_monitor/ina228/ina228.cpp | 46 ++++++++++++++------- src/drivers/power_monitor/ina228/ina228.h | 3 ++ src/drivers/power_monitor/ina238/ina238.cpp | 45 +++++++++++++------- src/drivers/power_monitor/ina238/ina238.h | 3 ++ 7 files changed, 100 insertions(+), 45 deletions(-) diff --git a/src/drivers/power_monitor/ina220/ina220.cpp b/src/drivers/power_monitor/ina220/ina220.cpp index c8f52bf71c..bde68ce875 100644 --- a/src/drivers/power_monitor/ina220/ina220.cpp +++ b/src/drivers/power_monitor/ina220/ina220.cpp @@ -329,8 +329,6 @@ INA220::RunImpl() if (_ch_type == PM_CH_TYPE_VBATT) { _battery.setConnected(false); - _battery.updateVoltage(0.f); - _battery.updateCurrent(0.f); _battery.updateAndPublishBatteryStatus(hrt_absolute_time()); } diff --git a/src/drivers/power_monitor/ina226/ina226.cpp b/src/drivers/power_monitor/ina226/ina226.cpp index f61a7c7b79..60fb333699 100644 --- a/src/drivers/power_monitor/ina226/ina226.cpp +++ b/src/drivers/power_monitor/ina226/ina226.cpp @@ -83,10 +83,10 @@ INA226::INA226(const I2CSPIDriverConfig &config, int battery_index) : _power_lsb = 25 * _current_lsb; // We need to publish immediately, to guarantee that the first instance of the driver publishes to uORB instance 0 - _battery.setConnected(false); - _battery.updateVoltage(0.f); - _battery.updateCurrent(0.f); + setConnected(false); _battery.updateAndPublishBatteryStatus(hrt_absolute_time()); + + I2C::_retries = 5; } INA226::~INA226() @@ -226,14 +226,11 @@ INA226::collect() success = success && (read(INA226_REG_CURRENT, _current) == PX4_OK); // success = success && (read(INA226_REG_SHUNTVOLTAGE, _shunt) == PX4_OK); - if (!success) { - PX4_DEBUG("error reading from sensor"); - _bus_voltage = _power = _current = _shunt = 0; + if (setConnected(success)) { + _battery.updateVoltage(static_cast(_bus_voltage * INA226_VSCALE)); + _battery.updateCurrent(static_cast(_current * _current_lsb)); } - _battery.setConnected(success); - _battery.updateVoltage(static_cast(_bus_voltage * INA226_VSCALE)); - _battery.updateCurrent(static_cast(_current * _current_lsb)); _battery.updateAndPublishBatteryStatus(hrt_absolute_time()); perf_end(_sample_perf); @@ -246,6 +243,7 @@ INA226::collect() } } + void INA226::start() { @@ -297,9 +295,7 @@ INA226::RunImpl() ScheduleDelayed(INA226_CONVERSION_INTERVAL); } else { - _battery.setConnected(false); - _battery.updateVoltage(0.f); - _battery.updateCurrent(0.f); + setConnected(false); _battery.updateAndPublishBatteryStatus(hrt_absolute_time()); if (init() != PX4_OK) { @@ -308,6 +304,28 @@ INA226::RunImpl() } } +bool INA226::setConnected(bool state) +{ + // Filter out brief I2C failures for 2s + if (state) { + _connected = INA226_SAMPLE_FREQUENCY_HZ * 2; + + } else if (_connected > 0) { + _connected--; + } + + if (_connected > 0) { + _battery.setConnected(true); + + } else { + _battery.setConnected(false); + _battery.updateVoltage(0); + _battery.updateCurrent(0); + } + + return state; +} + void INA226::print_status() { diff --git a/src/drivers/power_monitor/ina226/ina226.h b/src/drivers/power_monitor/ina226/ina226.h index a402a079ab..a69695a1cc 100644 --- a/src/drivers/power_monitor/ina226/ina226.h +++ b/src/drivers/power_monitor/ina226/ina226.h @@ -206,6 +206,10 @@ private: int read(uint8_t address, int16_t &data); int write(uint8_t address, uint16_t data); + uint8_t _connected{0}; + // returns state unchanged + bool setConnected(bool state); + /** * Initialise the automatic measurement state machine and start it. * diff --git a/src/drivers/power_monitor/ina228/ina228.cpp b/src/drivers/power_monitor/ina228/ina228.cpp index e586590470..fd7494d3f3 100644 --- a/src/drivers/power_monitor/ina228/ina228.cpp +++ b/src/drivers/power_monitor/ina228/ina228.cpp @@ -98,11 +98,10 @@ INA228::INA228(const I2CSPIDriverConfig &config, int battery_index) : _power_lsb = 3.2f * _current_lsb; // We need to publish immediately, to guarantee that the first instance of the driver publishes to uORB instance 0 - _battery.setConnected(false); - _battery.updateVoltage(0.f); - _battery.updateCurrent(0.f); - _battery.updateTemperature(0.f); + setConnected(false); _battery.updateAndPublishBatteryStatus(hrt_absolute_time()); + + I2C::_retries = 5; } INA228::~INA228() @@ -322,15 +321,12 @@ INA228::collect() //success = success && (read(INA228_REG_VSHUNT, _shunt) == PX4_OK); success = success && (read(INA228_REG_DIETEMP, _temperature) == PX4_OK); - if (!success) { - PX4_DEBUG("error reading from sensor"); - _bus_voltage = _power = _current = _shunt = 0; + if (setConnected(success)) { + _battery.updateVoltage(static_cast(_bus_voltage * INA228_VSCALE)); + _battery.updateCurrent(static_cast(_current * _current_lsb)); + _battery.updateTemperature(static_cast(_temperature * INA228_TSCALE)); } - _battery.setConnected(success); - _battery.updateVoltage(static_cast(_bus_voltage * INA228_VSCALE)); - _battery.updateCurrent(static_cast(_current * _current_lsb)); - _battery.updateTemperature(static_cast(_temperature * INA228_TSCALE)); _battery.updateAndPublishBatteryStatus(hrt_absolute_time()); perf_end(_sample_perf); @@ -394,10 +390,7 @@ INA228::RunImpl() ScheduleDelayed(INA228_CONVERSION_INTERVAL); } else { - _battery.setConnected(false); - _battery.updateVoltage(0.f); - _battery.updateCurrent(0.f); - _battery.updateTemperature(0.f); + setConnected(false); _battery.updateAndPublishBatteryStatus(hrt_absolute_time()); if (init() != PX4_OK) { @@ -406,6 +399,29 @@ INA228::RunImpl() } } +bool INA228::setConnected(bool state) +{ + // Filter out brief I2C failures for 2s + if (state) { + _connected = INA228_SAMPLE_FREQUENCY_HZ * 2; + + } else if (_connected > 0) { + _connected--; + } + + if (_connected > 0) { + _battery.setConnected(true); + + } else { + _battery.setConnected(false); + _battery.updateVoltage(0); + _battery.updateCurrent(0); + _battery.updateTemperature(0); + } + + return state; +} + void INA228::print_status() { diff --git a/src/drivers/power_monitor/ina228/ina228.h b/src/drivers/power_monitor/ina228/ina228.h index 46e152ff00..72a89e6dcb 100644 --- a/src/drivers/power_monitor/ina228/ina228.h +++ b/src/drivers/power_monitor/ina228/ina228.h @@ -356,6 +356,9 @@ private: Battery _battery; uORB::SubscriptionInterval _parameter_update_sub{ORB_ID(parameter_update), 1_s}; + uint8_t _connected{0}; + // returns state unchanged + bool setConnected(bool state); int read(uint8_t address, int16_t &data); int write(uint8_t address, int16_t data); diff --git a/src/drivers/power_monitor/ina238/ina238.cpp b/src/drivers/power_monitor/ina238/ina238.cpp index a55f71b893..f42ae87764 100644 --- a/src/drivers/power_monitor/ina238/ina238.cpp +++ b/src/drivers/power_monitor/ina238/ina238.cpp @@ -90,11 +90,10 @@ INA238::INA238(const I2CSPIDriverConfig &config, int battery_index) : _register_cfg[2].clear_bits = ~_shunt_calibration; // We need to publish immediately, to guarantee that the first instance of the driver publishes to uORB instance 0 - _battery.setConnected(false); - _battery.updateVoltage(0.f); - _battery.updateCurrent(0.f); - _battery.updateTemperature(0.f); + setConnected(false); _battery.updateAndPublishBatteryStatus(hrt_absolute_time()); + + I2C::_retries = 5; } INA238::~INA238() @@ -178,11 +177,8 @@ int INA238::probe() int INA238::Reset() { - int ret = PX4_ERROR; - _retries = 3; - if (RegisterWrite(Register::CONFIG, (uint16_t)(ADC_RESET_BIT)) != PX4_OK) { return ret; } @@ -254,13 +250,11 @@ int INA238::collect() success = success && (RegisterRead(Register::CURRENT, (uint16_t &)current) == PX4_OK); success = success && (RegisterRead(Register::DIETEMP, (uint16_t &)temperature) == PX4_OK); - if (success) { + if (setConnected(success)) { _battery.updateVoltage(static_cast(bus_voltage * INA238_VSCALE)); _battery.updateCurrent(static_cast(current * _current_lsb)); _battery.updateTemperature(static_cast(temperature * INA238_TSCALE)); - _battery.setConnected(success); - _battery.updateAndPublishBatteryStatus(hrt_absolute_time()); } @@ -276,8 +270,7 @@ int INA238::collect() perf_count(_bad_register_perf); success = false; - _battery.setConnected(success); - + setConnected(false); _battery.updateAndPublishBatteryStatus(hrt_absolute_time()); } } @@ -338,10 +331,7 @@ void INA238::RunImpl() ScheduleDelayed(INA238_CONVERSION_INTERVAL); } else { - _battery.setConnected(false); - _battery.updateVoltage(0.f); - _battery.updateCurrent(0.f); - _battery.updateTemperature(0.f); + setConnected(false); _battery.updateAndPublishBatteryStatus(hrt_absolute_time()); if (init() != PX4_OK) { @@ -354,6 +344,29 @@ void INA238::RunImpl() } } +bool INA238::setConnected(bool state) +{ + // Filter out brief I2C failures for 2s + if (state) { + _connected = INA238_SAMPLE_FREQUENCY_HZ * 2; + + } else if (_connected > 0) { + _connected--; + } + + if (_connected > 0) { + _battery.setConnected(true); + + } else { + _battery.setConnected(false); + _battery.updateVoltage(0); + _battery.updateCurrent(0); + _battery.updateTemperature(0); + } + + return state; +} + void INA238::print_status() { I2CSPIDriverBase::print_status(); diff --git a/src/drivers/power_monitor/ina238/ina238.h b/src/drivers/power_monitor/ina238/ina238.h index 7d888aef54..62750c44c4 100644 --- a/src/drivers/power_monitor/ina238/ina238.h +++ b/src/drivers/power_monitor/ina238/ina238.h @@ -154,6 +154,9 @@ private: Battery _battery; uORB::SubscriptionInterval _parameter_update_sub{ORB_ID(parameter_update), 1_s}; + uint8_t _connected{0}; + // returns state unchanged + bool setConnected(bool state); int read(uint8_t address, uint16_t &data); int write(uint8_t address, uint16_t data); From b320ace4d11ae830a1866d91d680722daf69808f Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Fri, 31 Oct 2025 11:45:44 +0100 Subject: [PATCH 002/139] [ARK FMUv6x] Fix the timer assignments for input capture --- boards/ark/fmu-v6x/default.px4board | 1 + boards/ark/fmu-v6x/src/CMakeLists.txt | 2 - boards/ark/fmu-v6x/src/board_config.h | 4 +- boards/ark/fmu-v6x/src/init.c | 5 - boards/ark/fmu-v6x/src/spix_sync.c | 309 ------------------------ boards/ark/fmu-v6x/src/spix_sync.h | 42 ---- boards/ark/fmu-v6x/src/timer_config.cpp | 15 +- 7 files changed, 5 insertions(+), 373 deletions(-) delete mode 100644 boards/ark/fmu-v6x/src/spix_sync.c delete mode 100644 boards/ark/fmu-v6x/src/spix_sync.h diff --git a/boards/ark/fmu-v6x/default.px4board b/boards/ark/fmu-v6x/default.px4board index a4b5c42f18..d67f3a6db1 100644 --- a/boards/ark/fmu-v6x/default.px4board +++ b/boards/ark/fmu-v6x/default.px4board @@ -19,6 +19,7 @@ CONFIG_DRIVERS_DIFFERENTIAL_PRESSURE_AUAV=y CONFIG_COMMON_DISTANCE_SENSOR=y CONFIG_DRIVERS_DSHOT=y CONFIG_DRIVERS_GPS=y +CONFIG_DRIVERS_PPS_CAPTURE=y CONFIG_DRIVERS_HEATER=y CONFIG_DRIVERS_IMU_ANALOG_DEVICES_ADIS16507=y CONFIG_DRIVERS_IMU_INVENSENSE_ICM42688P=y diff --git a/boards/ark/fmu-v6x/src/CMakeLists.txt b/boards/ark/fmu-v6x/src/CMakeLists.txt index 78b8222f19..a120ebe336 100644 --- a/boards/ark/fmu-v6x/src/CMakeLists.txt +++ b/boards/ark/fmu-v6x/src/CMakeLists.txt @@ -57,8 +57,6 @@ else() mtd.cpp sdio.c spi.cpp - spix_sync.c - spix_sync.h timer_config.cpp usb.c ) diff --git a/boards/ark/fmu-v6x/src/board_config.h b/boards/ark/fmu-v6x/src/board_config.h index 302fbc22d9..16d0aa9300 100644 --- a/boards/ark/fmu-v6x/src/board_config.h +++ b/boards/ark/fmu-v6x/src/board_config.h @@ -241,7 +241,7 @@ /* PWM */ -#define DIRECT_PWM_OUTPUT_CHANNELS 8 +#define DIRECT_PWM_OUTPUT_CHANNELS 9 #define GPIO_FMU_CH1 /* PI0 */ (GPIO_INPUT|GPIO_PULLDOWN|GPIO_PORTI|GPIO_PIN0) #define GPIO_FMU_CH2 /* PH12 */ (GPIO_INPUT|GPIO_PULLDOWN|GPIO_PORTH|GPIO_PIN12) @@ -482,7 +482,7 @@ #define PX4_I2C_BUS_MTD 4,5 -#define BOARD_NUM_IO_TIMERS 3 +#define BOARD_NUM_IO_TIMERS 4 #define BOARD_SPIX_SYNC_FREQ 32000 __BEGIN_DECLS diff --git a/boards/ark/fmu-v6x/src/init.c b/boards/ark/fmu-v6x/src/init.c index 6c1c2257ed..c60f700af1 100644 --- a/boards/ark/fmu-v6x/src/init.c +++ b/boards/ark/fmu-v6x/src/init.c @@ -46,7 +46,6 @@ ****************************************************************************/ #include "board_config.h" -#include "spix_sync.h" #include #include @@ -290,9 +289,5 @@ __EXPORT int board_app_initialize(uintptr_t arg) #endif /* CONFIG_MMCSD */ - /* Configure the SPIX_SYNC output */ - spix_sync_servo_init(BOARD_SPIX_SYNC_FREQ); - spix_sync_servo_set(0, 150); - return OK; } diff --git a/boards/ark/fmu-v6x/src/spix_sync.c b/boards/ark/fmu-v6x/src/spix_sync.c deleted file mode 100644 index 056e38e75f..0000000000 --- a/boards/ark/fmu-v6x/src/spix_sync.c +++ /dev/null @@ -1,309 +0,0 @@ -/**************************************************************************** - * - * 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 Airmind 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 spix_sync.c -* -* -*/ - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include -#include - -#include - -#include "spix_sync.h" - -#define REG(_tmr, _reg) (*(volatile uint32_t *)(spix_sync_timers[_tmr].base + _reg)) - -#define rCR1(_tmr) REG(_tmr, STM32_GTIM_CR1_OFFSET) -#define rCR2(_tmr) REG(_tmr, STM32_GTIM_CR2_OFFSET) -#define rSMCR(_tmr) REG(_tmr, STM32_GTIM_SMCR_OFFSET) -#define rDIER(_tmr) REG(_tmr, STM32_GTIM_DIER_OFFSET) -#define rSR(_tmr) REG(_tmr, STM32_GTIM_SR_OFFSET) -#define rEGR(_tmr) REG(_tmr, STM32_GTIM_EGR_OFFSET) -#define rCCMR1(_tmr) REG(_tmr, STM32_GTIM_CCMR1_OFFSET) -#define rCCMR2(_tmr) REG(_tmr, STM32_GTIM_CCMR2_OFFSET) -#define rCCER(_tmr) REG(_tmr, STM32_GTIM_CCER_OFFSET) -#define rCNT(_tmr) REG(_tmr, STM32_GTIM_CNT_OFFSET) -#define rPSC(_tmr) REG(_tmr, STM32_GTIM_PSC_OFFSET) -#define rARR(_tmr) REG(_tmr, STM32_GTIM_ARR_OFFSET) -#define rCCR1(_tmr) REG(_tmr, STM32_GTIM_CCR1_OFFSET) -#define rCCR2(_tmr) REG(_tmr, STM32_GTIM_CCR2_OFFSET) -#define rCCR3(_tmr) REG(_tmr, STM32_GTIM_CCR3_OFFSET) -#define rCCR4(_tmr) REG(_tmr, STM32_GTIM_CCR4_OFFSET) -#define rDCR(_tmr) REG(_tmr, STM32_GTIM_DCR_OFFSET) -#define rDMAR(_tmr) REG(_tmr, STM32_GTIM_DMAR_OFFSET) -#define rBDTR(_tmr) REG(_tmr, STM32_ATIM_BDTR_OFFSET) - -#define BOARD_SPIX_SYNC_PWM_FREQ 1024000 - -unsigned -spix_sync_timer_get_period(unsigned timer) -{ - return (rARR(timer)); -} - -static void spix_sync_timer_init_timer(unsigned timer, unsigned rate) -{ - if (spix_sync_timers[timer].base) { - - irqstate_t flags = px4_enter_critical_section(); - - /* enable the timer clock before we try to talk to it */ - - modifyreg32(spix_sync_timers[timer].clock_register, 0, spix_sync_timers[timer].clock_bit); - - /* disable and configure the timer */ - rCR1(timer) = 0; - rCR2(timer) = 0; - rSMCR(timer) = 0; - rDIER(timer) = 0; - rCCER(timer) = 0; - rCCMR1(timer) = 0; - rCCMR2(timer) = 0; - rCCR1(timer) = 0; - rCCR2(timer) = 0; - rCCR3(timer) = 0; - rCCR4(timer) = 0; - rCCER(timer) = 0; - rDCR(timer) = 0; - - if ((spix_sync_timers[timer].base == STM32_TIM1_BASE) || (spix_sync_timers[timer].base == STM32_TIM8_BASE)) { - - /* master output enable = on */ - - rBDTR(timer) = ATIM_BDTR_MOE; - } - - /* If the timer clock source provided as clock_freq is the STM32_APBx_TIMx_CLKIN - * then configure the timer to free-run at 1MHz. - * Otherwise, other frequencies are attainable by adjusting .clock_freq accordingly. - */ - - rPSC(timer) = (spix_sync_timers[timer].clock_freq / BOARD_SPIX_SYNC_PWM_FREQ) - 1; - - /* configure the timer to update at the desired rate */ - - rARR(timer) = (BOARD_SPIX_SYNC_PWM_FREQ / rate) - 1; - - /* generate an update event; reloads the counter and all registers */ - rEGR(timer) = GTIM_EGR_UG; - - px4_leave_critical_section(flags); - } - -} - -void spix_sync_channel_init(unsigned channel) -{ - /* Only initialize used channels */ - - if (spix_sync_channels[channel].timer_channel) { - - unsigned timer = spix_sync_channels[channel].timer_index; - - /* configure the GPIO first */ - px4_arch_configgpio(spix_sync_channels[channel].gpio_out); - - uint16_t polarity = spix_sync_channels[channel].masks; - - /* configure the channel */ - switch (spix_sync_channels[channel].timer_channel) { - case 1: - rCCMR1(timer) |= (GTIM_CCMR_MODE_PWM1 << GTIM_CCMR1_OC1M_SHIFT) | GTIM_CCMR1_OC1PE; - rCCER(timer) |= polarity | GTIM_CCER_CC1E; - break; - - case 2: - rCCMR1(timer) |= (GTIM_CCMR_MODE_PWM1 << GTIM_CCMR1_OC2M_SHIFT) | GTIM_CCMR1_OC2PE; - rCCER(timer) |= polarity | GTIM_CCER_CC2E; - break; - - case 3: - rCCMR2(timer) |= (GTIM_CCMR_MODE_PWM1 << GTIM_CCMR2_OC3M_SHIFT) | GTIM_CCMR2_OC3PE; - rCCER(timer) |= polarity | GTIM_CCER_CC3E; - break; - - case 4: - rCCMR2(timer) |= (GTIM_CCMR_MODE_PWM1 << GTIM_CCMR2_OC4M_SHIFT) | GTIM_CCMR2_OC4PE; - rCCER(timer) |= polarity | GTIM_CCER_CC4E; - break; - } - } -} - -int -spix_sync_servo_set(unsigned channel, uint8_t cvalue) -{ - if (channel >= arraySize(spix_sync_channels)) { - return -1; - } - - unsigned timer = spix_sync_channels[channel].timer_index; - - /* test timer for validity */ - if ((spix_sync_timers[timer].base == 0) || - (spix_sync_channels[channel].gpio_out == 0)) { - return -1; - } - - unsigned period = spix_sync_timer_get_period(timer); - - unsigned value = (unsigned)cvalue * period / 255; - - /* configure the channel */ - if (value > 0) { - value--; - } - - - switch (spix_sync_channels[channel].timer_channel) { - case 1: - rCCR1(timer) = value; - break; - - case 2: - rCCR2(timer) = value; - break; - - case 3: - rCCR3(timer) = value; - break; - - case 4: - rCCR4(timer) = value; - break; - - default: - return -1; - } - - return 0; -} - -unsigned spix_sync_servo_get(unsigned channel) -{ - if (channel >= 3) { - return 0; - } - - unsigned timer = spix_sync_channels[channel].timer_index; - uint16_t value = 0; - - /* test timer for validity */ - if ((spix_sync_timers[timer].base == 0) || - (spix_sync_channels[channel].timer_channel == 0)) { - return 0; - } - - /* configure the channel */ - switch (spix_sync_channels[channel].timer_channel) { - case 1: - value = rCCR1(timer); - break; - - case 2: - value = rCCR2(timer); - break; - - case 3: - value = rCCR3(timer); - break; - - case 4: - value = rCCR4(timer); - break; - } - - unsigned period = spix_sync_timer_get_period(timer); - return ((value + 1) * 255 / period); -} - -int spix_sync_servo_init(unsigned rate) -{ - /* do basic timer initialisation first */ - for (unsigned i = 0; i < arraySize(spix_sync_timers); i++) { - spix_sync_timer_init_timer(i, rate); - } - - /* now init channels */ - for (unsigned i = 0; i < arraySize(spix_sync_channels); i++) { - spix_sync_channel_init(i); - } - - spix_sync_servo_arm(true); - return OK; -} - -void -spix_sync_servo_deinit(void) -{ - /* disable the timers */ - spix_sync_servo_arm(false); -} -void -spix_sync_servo_arm(bool armed) -{ - /* iterate timers and arm/disarm appropriately */ - for (unsigned i = 0; i < arraySize(spix_sync_timers); i++) { - if (spix_sync_timers[i].base != 0) { - if (armed) { - /* force an update to preload all registers */ - rEGR(i) = GTIM_EGR_UG; - - /* arm requires the timer be enabled */ - rCR1(i) |= GTIM_CR1_CEN | GTIM_CR1_ARPE; - - } else { - rCR1(i) = 0; - } - } - } -} diff --git a/boards/ark/fmu-v6x/src/spix_sync.h b/boards/ark/fmu-v6x/src/spix_sync.h deleted file mode 100644 index 2e37c89086..0000000000 --- a/boards/ark/fmu-v6x/src/spix_sync.h +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************************** - * - * 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. - * - ****************************************************************************/ - -__BEGIN_DECLS -void spix_sync_channel_init(unsigned channel); -int spix_sync_servo_set(unsigned channel, uint8_t value); -unsigned spix_sync_servo_get(unsigned channel); -int spix_sync_servo_init(unsigned rate); -void spix_sync_servo_deinit(void); -void spix_sync_servo_arm(bool armed); -unsigned spix_sync_timer_get_period(unsigned timer); -__END_DECLS diff --git a/boards/ark/fmu-v6x/src/timer_config.cpp b/boards/ark/fmu-v6x/src/timer_config.cpp index 3504c3569d..75d67bac99 100644 --- a/boards/ark/fmu-v6x/src/timer_config.cpp +++ b/boards/ark/fmu-v6x/src/timer_config.cpp @@ -60,8 +60,7 @@ constexpr io_timers_t io_timers[MAX_IO_TIMERS] = { initIOTimer(Timer::Timer5, DMA{DMA::Index1}), initIOTimer(Timer::Timer4, DMA{DMA::Index1}), initIOTimer(Timer::Timer12), - //initIOTimer(Timer::Timer1), - //initIOTimer(Timer::Timer2), + initIOTimer(Timer::Timer1), }; constexpr timer_io_channels_t timer_io_channels[MAX_TIMER_IO_CHANNELS] = { @@ -73,18 +72,8 @@ constexpr timer_io_channels_t timer_io_channels[MAX_TIMER_IO_CHANNELS] = { initIOTimerChannel(io_timers, {Timer::Timer4, Timer::Channel3}, {GPIO::PortD, GPIO::Pin14}), initIOTimerChannel(io_timers, {Timer::Timer12, Timer::Channel1}, {GPIO::PortH, GPIO::Pin6}), initIOTimerChannel(io_timers, {Timer::Timer12, Timer::Channel2}, {GPIO::PortH, GPIO::Pin9}), - //initIOTimerChannel(io_timers, {Timer::Timer1, Timer::Channel2}, {GPIO::PortE, GPIO::Pin11}), - //initIOTimerChannel(io_timers, {Timer::Timer1, Timer::Channel1}, {GPIO::PortE, GPIO::Pin9}), + initIOTimerChannelCapture(io_timers, {Timer::Timer1, Timer::Channel2}, {GPIO::PortE, GPIO::Pin11}), }; constexpr io_timers_channel_mapping_t io_timers_channel_mapping = initIOTimerChannelMapping(io_timers, timer_io_channels); - - -constexpr io_timers_t spix_sync_timers[MAX_SPIX_SYNC_TIMERS] = { - initIOTimer(Timer::Timer1), -}; - -constexpr timer_io_channels_t spix_sync_channels[MAX_SPIX_SYNC_TIMERS] = { - initIOTimerChannel(spix_sync_timers, {Timer::Timer1, Timer::Channel1}, {GPIO::PortE, GPIO::Pin9}), -}; From be9fa620fd182e74aa7d3271b439809b2b795f8b Mon Sep 17 00:00:00 2001 From: alexklimaj Date: Mon, 27 Oct 2025 14:46:05 -0600 Subject: [PATCH 003/139] drivers: rm3100 add i2c/spi ifdefs --- src/drivers/magnetometer/rm3100/rm3100.h | 4 ++++ src/drivers/magnetometer/rm3100/rm3100_i2c.cpp | 4 ++++ src/drivers/magnetometer/rm3100/rm3100_main.cpp | 16 +++++++++++++--- src/drivers/magnetometer/rm3100/rm3100_spi.cpp | 4 ++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/drivers/magnetometer/rm3100/rm3100.h b/src/drivers/magnetometer/rm3100/rm3100.h index 7e4737d48b..3057d98c27 100644 --- a/src/drivers/magnetometer/rm3100/rm3100.h +++ b/src/drivers/magnetometer/rm3100/rm3100.h @@ -91,8 +91,12 @@ #define RM3100_REVID 0x22 /* interface factories */ +#if defined(CONFIG_SPI) extern device::Device *RM3100_SPI_interface(int bus, uint32_t devid, int bus_frequency, spi_mode_e spi_mode); +#endif // CONFIG_SPI +#if defined(CONFIG_I2C) extern device::Device *RM3100_I2C_interface(int bus, int bus_frequency); +#endif // CONFIG_I2C #define RM3100_ADDRESS 0x20 diff --git a/src/drivers/magnetometer/rm3100/rm3100_i2c.cpp b/src/drivers/magnetometer/rm3100/rm3100_i2c.cpp index 3aeba5d57e..9a7826c314 100644 --- a/src/drivers/magnetometer/rm3100/rm3100_i2c.cpp +++ b/src/drivers/magnetometer/rm3100/rm3100_i2c.cpp @@ -39,6 +39,8 @@ #include +#if defined(CONFIG_I2C) + #include #include #include @@ -129,3 +131,5 @@ int RM3100_I2C::write(unsigned address, void *data, unsigned count) return transfer(&buf[0], count + 1, nullptr, 0); } + +#endif // CONFIG_I2C diff --git a/src/drivers/magnetometer/rm3100/rm3100_main.cpp b/src/drivers/magnetometer/rm3100/rm3100_main.cpp index be8571cced..3c3b51060f 100644 --- a/src/drivers/magnetometer/rm3100/rm3100_main.cpp +++ b/src/drivers/magnetometer/rm3100/rm3100_main.cpp @@ -45,12 +45,16 @@ I2CSPIDriverBase *RM3100::instantiate(const I2CSPIDriverConfig &config, int runt { device::Device *interface = nullptr; +#if defined(CONFIG_I2C) + if (config.bus_type == BOARD_I2C_BUS) { interface = RM3100_I2C_interface(config.bus, config.bus_frequency); - } else if (config.bus_type == BOARD_SPI_BUS) { - interface = RM3100_SPI_interface(config.bus, config.spi_devid, config.bus_frequency, config.spi_mode); - } + } else +#endif // CONFIG_I2C + if (config.bus_type == BOARD_SPI_BUS) { + interface = RM3100_SPI_interface(config.bus, config.spi_devid, config.bus_frequency, config.spi_mode); + } if (interface == nullptr) { PX4_ERR("alloc failed"); @@ -93,8 +97,12 @@ extern "C" int rm3100_main(int argc, char *argv[]) using ThisDriver = RM3100; int ch; BusCLIArguments cli{true, true}; +#if defined(CONFIG_I2C) cli.default_i2c_frequency = 400000; +#endif // CONFIG_I2C +#if defined(CONFIG_SPI) cli.default_spi_frequency = 1 * 1000 * 1000; +#endif // CONFIG_SPI while ((ch = cli.getOpt(argc, argv, "R:")) != EOF) { switch (ch) { @@ -111,7 +119,9 @@ extern "C" int rm3100_main(int argc, char *argv[]) return -1; } +#if defined(CONFIG_I2C) cli.i2c_address = RM3100_ADDRESS; +#endif // CONFIG_I2C BusInstanceIterator iterator(MODULE_NAME, cli, DRV_MAG_DEVTYPE_RM3100); diff --git a/src/drivers/magnetometer/rm3100/rm3100_spi.cpp b/src/drivers/magnetometer/rm3100/rm3100_spi.cpp index 3d8f84498a..b9da9f5493 100644 --- a/src/drivers/magnetometer/rm3100/rm3100_spi.cpp +++ b/src/drivers/magnetometer/rm3100/rm3100_spi.cpp @@ -39,6 +39,8 @@ #include +#if defined(CONFIG_SPI) + #include #include #include @@ -135,3 +137,5 @@ int RM3100_SPI::write(unsigned address, void *data, unsigned count) return transfer(&buf[0], &buf[0], count + 1); } + +#endif // CONFIG_SPI From 0c9ebc432185fd37afc544abeb7f560b6e04cb8f Mon Sep 17 00:00:00 2001 From: alexklimaj Date: Mon, 27 Oct 2025 14:46:40 -0600 Subject: [PATCH 004/139] boards: add ARK MAG --- .vscode/cmake-variants.yaml | 10 + boards/ark/mag/canbootloader.px4board | 5 + boards/ark/mag/default.px4board | 22 ++ boards/ark/mag/firmware.prototype | 13 ++ boards/ark/mag/init/rc.board_sensors | 6 + .../mag/nuttx-config/canbootloader/defconfig | 57 ++++++ boards/ark/mag/nuttx-config/include/board.h | 132 ++++++++++++ .../mag/nuttx-config/include/board_dma_map.h | 42 ++++ boards/ark/mag/nuttx-config/nsh/defconfig | 149 ++++++++++++++ .../scripts/canbootloader_script.ld | 134 +++++++++++++ boards/ark/mag/nuttx-config/scripts/script.ld | 146 ++++++++++++++ boards/ark/mag/src/CMakeLists.txt | 65 ++++++ boards/ark/mag/src/board_config.h | 88 ++++++++ boards/ark/mag/src/boot.c | 188 ++++++++++++++++++ boards/ark/mag/src/boot_config.h | 130 ++++++++++++ boards/ark/mag/src/can.c | 130 ++++++++++++ boards/ark/mag/src/init.c | 147 ++++++++++++++ boards/ark/mag/src/led.c | 124 ++++++++++++ boards/ark/mag/src/led.h | 37 ++++ boards/ark/mag/src/spi.cpp | 44 ++++ boards/ark/mag/uavcan_board_identity | 17 ++ 21 files changed, 1686 insertions(+) create mode 100644 boards/ark/mag/canbootloader.px4board create mode 100644 boards/ark/mag/default.px4board create mode 100644 boards/ark/mag/firmware.prototype create mode 100644 boards/ark/mag/init/rc.board_sensors create mode 100644 boards/ark/mag/nuttx-config/canbootloader/defconfig create mode 100644 boards/ark/mag/nuttx-config/include/board.h create mode 100644 boards/ark/mag/nuttx-config/include/board_dma_map.h create mode 100644 boards/ark/mag/nuttx-config/nsh/defconfig create mode 100644 boards/ark/mag/nuttx-config/scripts/canbootloader_script.ld create mode 100644 boards/ark/mag/nuttx-config/scripts/script.ld create mode 100644 boards/ark/mag/src/CMakeLists.txt create mode 100644 boards/ark/mag/src/board_config.h create mode 100644 boards/ark/mag/src/boot.c create mode 100644 boards/ark/mag/src/boot_config.h create mode 100644 boards/ark/mag/src/can.c create mode 100644 boards/ark/mag/src/init.c create mode 100644 boards/ark/mag/src/led.c create mode 100644 boards/ark/mag/src/led.h create mode 100644 boards/ark/mag/src/spi.cpp create mode 100644 boards/ark/mag/uavcan_board_identity diff --git a/.vscode/cmake-variants.yaml b/.vscode/cmake-variants.yaml index b40113f5da..504c38b2d3 100644 --- a/.vscode/cmake-variants.yaml +++ b/.vscode/cmake-variants.yaml @@ -241,6 +241,16 @@ CONFIG: buildType: MinSizeRel settings: CONFIG: ark_fpv_default + ark_mag_canbootloader: + short: ark_mag_canbootloader + buildType: MiniSizeRel + settings: + CONFIG: ark_mag_canbootloader + ark_mag_default: + short: ark_mag_default + buildType: MiniSizeRel + settings: + CONFIG: ark_mag_default ark_pi6x_bootloader: short: ark_pi6x_bootloader buildType: MinSizeRel diff --git a/boards/ark/mag/canbootloader.px4board b/boards/ark/mag/canbootloader.px4board new file mode 100644 index 0000000000..46917280f6 --- /dev/null +++ b/boards/ark/mag/canbootloader.px4board @@ -0,0 +1,5 @@ +CONFIG_BOARD_TOOLCHAIN="arm-none-eabi" +CONFIG_BOARD_ARCHITECTURE="cortex-m4" +CONFIG_BOARD_ROMFSROOT="" +CONFIG_BOARD_CONSTRAINED_MEMORY=y +CONFIG_DRIVERS_BOOTLOADERS=y diff --git a/boards/ark/mag/default.px4board b/boards/ark/mag/default.px4board new file mode 100644 index 0000000000..53f391b7e8 --- /dev/null +++ b/boards/ark/mag/default.px4board @@ -0,0 +1,22 @@ +CONFIG_BOARD_TOOLCHAIN="arm-none-eabi" +CONFIG_BOARD_ARCHITECTURE="cortex-m4" +CONFIG_BOARD_ROMFSROOT="cannode" +CONFIG_BOARD_CONSTRAINED_MEMORY=y +CONFIG_DRIVERS_BOOTLOADERS=y +CONFIG_DRIVERS_MAGNETOMETER_RM3100=y +CONFIG_BOARD_UAVCAN_INTERFACES=1 +CONFIG_DRIVERS_UAVCANNODE=y +CONFIG_UAVCANNODE_MAGNETIC_FIELD_STRENGTH=y +CONFIG_MODULES_SENSORS=y +# CONFIG_SENSORS_VEHICLE_AIRSPEED is not set +# CONFIG_SENSORS_VEHICLE_AIR_DATA is not set +# CONFIG_SENSORS_VEHICLE_GPS_POSITION is not set +CONFIG_SYSTEMCMDS_PARAM=y +CONFIG_SYSTEMCMDS_PERF=y +CONFIG_SYSTEMCMDS_REBOOT=y +CONFIG_SYSTEMCMDS_SYSTEM_TIME=y +CONFIG_SYSTEMCMDS_TOP=y +CONFIG_SYSTEMCMDS_TOPIC_LISTENER=y +CONFIG_SYSTEMCMDS_UORB=y +CONFIG_SYSTEMCMDS_VER=y +CONFIG_SYSTEMCMDS_WORK_QUEUE=y diff --git a/boards/ark/mag/firmware.prototype b/boards/ark/mag/firmware.prototype new file mode 100644 index 0000000000..35ba6379fb --- /dev/null +++ b/boards/ark/mag/firmware.prototype @@ -0,0 +1,13 @@ +{ + "board_id": 93, + "magic": "PX4FWv1", + "description": "Firmware for the ARK MAG board", + "image": "", + "build_time": 0, + "summary": "ARKMAG", + "version": "0.1", + "image_size": 0, + "image_maxsize": 2080768, + "git_identity": "", + "board_revision": 0 +} diff --git a/boards/ark/mag/init/rc.board_sensors b/boards/ark/mag/init/rc.board_sensors new file mode 100644 index 0000000000..29163fabc9 --- /dev/null +++ b/boards/ark/mag/init/rc.board_sensors @@ -0,0 +1,6 @@ +#!/bin/sh +# +# board sensors init +#------------------------------------------------------------------------------ + +rm3100 -s -b 2 start diff --git a/boards/ark/mag/nuttx-config/canbootloader/defconfig b/boards/ark/mag/nuttx-config/canbootloader/defconfig new file mode 100644 index 0000000000..11b948472f --- /dev/null +++ b/boards/ark/mag/nuttx-config/canbootloader/defconfig @@ -0,0 +1,57 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD_CUSTOM=y +CONFIG_ARCH_BOARD_CUSTOM_DIR="../../../../boards/ark/mag/nuttx-config" +CONFIG_ARCH_BOARD_CUSTOM_DIR_RELPATH=y +CONFIG_ARCH_BOARD_CUSTOM_NAME="px4" +CONFIG_ARCH_CHIP="stm32" +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_CHIP_STM32F412CE=y +CONFIG_ARCH_INTERRUPTSTACK=4096 +CONFIG_ARMV7M_MEMCPY=y +CONFIG_ARMV7M_USEBASEPRI=y +CONFIG_BINFMT_DISABLE=y +CONFIG_BOARDCTL=y +CONFIG_BOARD_LOOPSPERMSEC=16717 +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEBUG_TCBINFO=y +CONFIG_DEFAULT_SMALL=y +CONFIG_DISABLE_MOUNTPOINT=y +CONFIG_EXPERIMENTAL=y +CONFIG_FDCLONE_DISABLE=y +CONFIG_FDCLONE_STDIO=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_IDLETHREAD_STACKSIZE=4096 +CONFIG_INIT_STACKSIZE=4096 +CONFIG_LIBC_FLOATINGPOINT=y +CONFIG_LIBC_LONG_LONG=y +CONFIG_LIBC_STRERROR=y +CONFIG_MM_REGIONS=2 +CONFIG_NAME_MAX=0 +CONFIG_NUNGET_CHARS=0 +CONFIG_PREALLOC_TIMERS=0 +CONFIG_PTHREAD_STACK_MIN=512 +CONFIG_RAM_SIZE=262144 +CONFIG_RAM_START=0x20010000 +CONFIG_RAW_BINARY=y +CONFIG_SIG_DEFAULT=y +CONFIG_SIG_SIGALRM_ACTION=y +CONFIG_SIG_SIGUSR1_ACTION=y +CONFIG_SIG_SIGUSR2_ACTION=y +CONFIG_STACK_COLORATION=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=11 +CONFIG_STDIO_DISABLE_BUFFERING=y +CONFIG_STM32_FLASH_CONFIG_G=y +CONFIG_STM32_NOEXT_VECTORS=y +CONFIG_STM32_TIM8=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_USEC_PER_TICK=1000 diff --git a/boards/ark/mag/nuttx-config/include/board.h b/boards/ark/mag/nuttx-config/include/board.h new file mode 100644 index 0000000000..18079b86e1 --- /dev/null +++ b/boards/ark/mag/nuttx-config/include/board.h @@ -0,0 +1,132 @@ +/************************************************************************************ + * configs/px4fmu/include/board.h + * include/arch/board/board.h + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ +#include "board_dma_map.h" + +#ifndef __ARCH_BOARD_BOARD_H +#define __ARCH_BOARD_BOARD_H + +#include +#ifndef __ASSEMBLY__ +# include +#endif + +#include + +/* HSI - 8 MHz RC factory-trimmed + * LSI - 32 KHz RC + * HSE - 8 MHz Crystal + * LSE - not installed + */ +#define STM32_BOARD_USEHSE 1 +#define STM32_BOARD_XTAL 8000000 +#define STM32_HSE_FREQUENCY STM32_BOARD_XTAL + +#define STM32_HSI_FREQUENCY 16000000ul +#define STM32_LSI_FREQUENCY 32000 + +/* Main PLL Configuration */ +#define STM32_PLLCFG_PLLM RCC_PLLCFG_PLLM(8) +#define STM32_PLLCFG_PLLN RCC_PLLCFG_PLLN(384) +#define STM32_PLLCFG_PLLP RCC_PLLCFG_PLLP_4 +#define STM32_PLLCFG_PLLQ RCC_PLLCFG_PLLQ(8) +#define STM32_PLLCFG_PLLR RCC_PLLCFG_PLLR(2) + +#define STM32_RCC_PLLI2SCFGR_PLLI2SM RCC_PLLI2SCFGR_PLLI2SM(16) +#define STM32_RCC_PLLI2SCFGR_PLLI2SN RCC_PLLI2SCFGR_PLLI2SN(192) +#define STM32_RCC_PLLI2SCFGR_PLLI2SQ RCC_PLLI2SCFGR_PLLI2SQ(2) +#define STM32_RCC_PLLI2SCFGR_PLLI2SR RCC_PLLI2SCFGR_PLLI2SR(2) +#define STM32_RCC_PLLI2SCFGR_PLLI2SSRC RCC_PLLI2SCFGR_PLLI2SSRC(0) /* HSE or HSI depending on PLLSRC of PLLCFGR*/ + +#define STM32_RCC_DCKCFGR2_CK48MSEL RCC_DCKCFGR2_CK48MSEL_PLL +#define STM32_RCC_DCKCFGR2_FMPI2C1SEL RCC_DCKCFGR2_FMPI2C1SEL_APB +#define STM32_RCC_DCKCFGR2_SDIOSEL RCC_DCKCFGR2_SDIOSEL_48MHZ + +#define STM32_SYSCLK_FREQUENCY 96000000ul + +/* AHB clock (HCLK) is SYSCLK (96MHz) */ +#define STM32_RCC_CFGR_HPRE RCC_CFGR_HPRE_SYSCLK /* HCLK = SYSCLK / 1 */ +#define STM32_HCLK_FREQUENCY STM32_SYSCLK_FREQUENCY +#define STM32_BOARD_HCLK STM32_HCLK_FREQUENCY /* Same as above, to satisfy compiler */ + +/* APB1 clock (PCLK1) is HCLK/2 (48MHz) */ +#define STM32_RCC_CFGR_PPRE1 RCC_CFGR_PPRE1_HCLKd2 /* PCLK1 = HCLK / 2 */ +#define STM32_PCLK1_FREQUENCY (STM32_HCLK_FREQUENCY/2) + +/* Timers driven from APB1 will be twice PCLK1 (see page 112 of reference manual) */ +#define STM32_APB1_TIM2_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM3_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM4_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM5_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM12_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM13_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM14_CLKIN (2*STM32_PCLK1_FREQUENCY) + +/* APB2 clock (PCLK2) is HCLK (96MHz) */ +#define STM32_RCC_CFGR_PPRE2 RCC_CFGR_PPRE2_HCLK /* PCLK2 = HCLK */ +#define STM32_PCLK2_FREQUENCY (STM32_HCLK_FREQUENCY) + +/* Timers driven from APB2 will be PCLK2 since no prescale division */ +#define STM32_APB2_TIM1_CLKIN (STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM8_CLKIN (STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM9_CLKIN (STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM10_CLKIN (STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM11_CLKIN (STM32_PCLK2_FREQUENCY) + +/* Timer Frequencies, if APBx is set to 1, frequency is same to APBx otherwise frequency is 2xAPBx. */ +#define BOARD_TIM2_FREQUENCY (2 * STM32_PCLK1_FREQUENCY) +#define BOARD_TIM3_FREQUENCY (2 * STM32_PCLK1_FREQUENCY) +#define BOARD_TIM4_FREQUENCY (2 * STM32_PCLK1_FREQUENCY) +#define BOARD_TIM5_FREQUENCY (2 * STM32_PCLK1_FREQUENCY) +#define BOARD_TIM6_FREQUENCY (2 * STM32_PCLK1_FREQUENCY) +#define BOARD_TIM7_FREQUENCY (2 * STM32_PCLK1_FREQUENCY) +#define BOARD_TIM8_FREQUENCY (2 * STM32_PCLK2_FREQUENCY) + +/* Alternate function pin selections ************************************************/ + +/* UARTs */ +#define GPIO_USART2_RX GPIO_USART2_RX_1 +#define GPIO_USART2_TX GPIO_USART2_TX_1 + +/* CAN */ +#define GPIO_CAN1_RX GPIO_CAN1_RX_1 +#define GPIO_CAN1_TX GPIO_CAN1_TX_1 + +/* SPI */ +#define GPIO_SPI2_MISO GPIO_SPI2_MISO_1 /* PB14 */ +#define GPIO_SPI2_MOSI GPIO_SPI2_MOSI_1 /* PB15 */ +#define GPIO_SPI2_SCK GPIO_SPI2_SCK_1 /* PB10 */ + +#endif /* __ARCH_BOARD_BOARD_H */ diff --git a/boards/ark/mag/nuttx-config/include/board_dma_map.h b/boards/ark/mag/nuttx-config/include/board_dma_map.h new file mode 100644 index 0000000000..773b49fc34 --- /dev/null +++ b/boards/ark/mag/nuttx-config/include/board_dma_map.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * Copyright (c) 2021 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 + +// DMA1 Channel/Stream Selections +//--------------------------------------------//---------------------------//---------------- +#define DMACHAN_SPI2_RX DMAMAP_SPI2_RX // DMA1, Stream 3, Channel 0 +#define DMACHAN_SPI2_TX DMAMAP_SPI2_TX // DMA1, Stream 4, Channel 0 + +// DMA2 Channel/Stream Selections +//--------------------------------------------//---------------------------//---------------- diff --git a/boards/ark/mag/nuttx-config/nsh/defconfig b/boards/ark/mag/nuttx-config/nsh/defconfig new file mode 100644 index 0000000000..665ad0c1c3 --- /dev/null +++ b/boards/ark/mag/nuttx-config/nsh/defconfig @@ -0,0 +1,149 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_DISABLE_ENVIRON is not set +# CONFIG_DISABLE_PSEUDOFS_OPERATIONS is not set +# CONFIG_DISABLE_PTHREAD is not set +# CONFIG_NSH_DISABLEBG is not set +# CONFIG_NSH_DISABLESCRIPT is not set +# CONFIG_NSH_DISABLE_CAT is not set +# CONFIG_NSH_DISABLE_CD is not set +# CONFIG_NSH_DISABLE_CP is not set +# CONFIG_NSH_DISABLE_DATE is not set +# CONFIG_NSH_DISABLE_DF is not set +# CONFIG_NSH_DISABLE_ECHO is not set +# CONFIG_NSH_DISABLE_ENV is not set +# CONFIG_NSH_DISABLE_EXEC is not set +# CONFIG_NSH_DISABLE_EXPORT is not set +# CONFIG_NSH_DISABLE_FREE is not set +# CONFIG_NSH_DISABLE_GET is not set +# CONFIG_NSH_DISABLE_HELP is not set +# CONFIG_NSH_DISABLE_ITEF is not set +# CONFIG_NSH_DISABLE_KILL is not set +# CONFIG_NSH_DISABLE_LOOPS is not set +# CONFIG_NSH_DISABLE_LS is not set +# CONFIG_NSH_DISABLE_MKDIR is not set +# CONFIG_NSH_DISABLE_MOUNT is not set +# CONFIG_NSH_DISABLE_MV is not set +# CONFIG_NSH_DISABLE_PS is not set +# CONFIG_NSH_DISABLE_PSSTACKUSAGE is not set +# CONFIG_NSH_DISABLE_PWD is not set +# CONFIG_NSH_DISABLE_RM is not set +# CONFIG_NSH_DISABLE_RMDIR is not set +# CONFIG_NSH_DISABLE_SEMICOLON is not set +# CONFIG_NSH_DISABLE_SET is not set +# CONFIG_NSH_DISABLE_SLEEP is not set +# CONFIG_NSH_DISABLE_SOURCE is not set +# CONFIG_NSH_DISABLE_TEST is not set +# CONFIG_NSH_DISABLE_TIME is not set +# CONFIG_NSH_DISABLE_UMOUNT is not set +# CONFIG_NSH_DISABLE_UNSET is not set +# CONFIG_NSH_DISABLE_USLEEP is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD_CUSTOM=y +CONFIG_ARCH_BOARD_CUSTOM_DIR="../../../../boards/ark/mag/nuttx-config" +CONFIG_ARCH_BOARD_CUSTOM_DIR_RELPATH=y +CONFIG_ARCH_BOARD_CUSTOM_NAME="px4" +CONFIG_ARCH_CHIP="stm32" +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_CHIP_STM32F412CE=y +CONFIG_ARCH_INTERRUPTSTACK=768 +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARMV7M_MEMCPY=y +CONFIG_ARMV7M_USEBASEPRI=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_ASSERT_RESET_VALUE=0 +CONFIG_BOARD_LOOPSPERMSEC=16717 +CONFIG_BOARD_RESET_ON_ASSERT=2 +CONFIG_BUILTIN=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_HARDFAULT_ALERT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEBUG_TCBINFO=y +CONFIG_DEFAULT_SMALL=y +CONFIG_DEV_PIPE_MAXSIZE=1024 +CONFIG_DEV_PIPE_SIZE=70 +CONFIG_FDCLONE_STDIO=y +CONFIG_FS_CROMFS=y +CONFIG_FS_ROMFS=y +CONFIG_GRAN=y +CONFIG_GRAN_INTR=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_IDLETHREAD_STACKSIZE=750 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=2624 +CONFIG_LIBC_FLOATINGPOINT=y +CONFIG_LIBC_LONG_LONG=y +CONFIG_LIBC_MAX_EXITFUNS=1 +CONFIG_MEMSET_64BIT=y +CONFIG_MEMSET_OPTSPEED=y +CONFIG_MM_REGIONS=2 +CONFIG_NAME_MAX=40 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_ARGCAT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_CMDPARMS=y +CONFIG_NSH_CROMFSETC=y +CONFIG_NSH_LINELEN=128 +CONFIG_NSH_MAXARGUMENTS=15 +CONFIG_NSH_NESTDEPTH=8 +CONFIG_NSH_QUOTE=y +CONFIG_NSH_ROMFSETC=y +CONFIG_NSH_ROMFSSECTSIZE=128 +CONFIG_NSH_VARS=y +CONFIG_PIPES=y +CONFIG_PREALLOC_TIMERS=50 +CONFIG_PTHREAD_MUTEX_ROBUST=y +CONFIG_PTHREAD_STACK_MIN=512 +CONFIG_RAM_SIZE=262144 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_READLINE_TABCOMPLETION=y +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_HPWORKPRIORITY=254 +CONFIG_SCHED_HPWORKSTACKSIZE=3000 +CONFIG_SCHED_INSTRUMENTATION=y +CONFIG_SCHED_INSTRUMENTATION_EXTERNAL=y +CONFIG_SCHED_INSTRUMENTATION_SWITCH=y +CONFIG_SCHED_WAITPID=y +CONFIG_SERIAL_TERMIOS=y +CONFIG_SIG_DEFAULT=y +CONFIG_SIG_SIGALRM_ACTION=y +CONFIG_SIG_SIGUSR1_ACTION=y +CONFIG_SIG_SIGUSR2_ACTION=y +CONFIG_SIG_SIGWORK=4 +CONFIG_STACK_COLORATION=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=11 +CONFIG_STDIO_BUFFER_SIZE=32 +CONFIG_STM32_ADC1=y +CONFIG_STM32_DISABLE_IDLE_SLEEP_DURING_DEBUG=y +CONFIG_STM32_DMA1=y +CONFIG_STM32_DMA2=y +CONFIG_STM32_FLASH_CONFIG_G=y +CONFIG_STM32_FLASH_PREFETCH=y +CONFIG_STM32_FLOWCONTROL_BROKEN=y +CONFIG_STM32_JTAG_SW_ENABLE=y +CONFIG_STM32_PWR=y +CONFIG_STM32_SERIALBRK_BSDCOMPAT=y +CONFIG_STM32_SERIAL_DISABLE_REORDERING=y +CONFIG_STM32_SPI2=y +CONFIG_STM32_SPI2_DMA=y +CONFIG_STM32_SPI2_DMA_BUFFER=2048 +CONFIG_STM32_TIM8=y +CONFIG_STM32_USART2=y +CONFIG_STM32_USART_BREAKS=y +CONFIG_STM32_WWDG=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=24 +CONFIG_USART2_BAUD=57600 +CONFIG_USART2_RXBUFSIZE=600 +CONFIG_USART2_SERIAL_CONSOLE=y +CONFIG_USART2_TXBUFSIZE=1100 +CONFIG_USEC_PER_TICK=1000 diff --git a/boards/ark/mag/nuttx-config/scripts/canbootloader_script.ld b/boards/ark/mag/nuttx-config/scripts/canbootloader_script.ld new file mode 100644 index 0000000000..48a59fe92d --- /dev/null +++ b/boards/ark/mag/nuttx-config/scripts/canbootloader_script.ld @@ -0,0 +1,134 @@ +/**************************************************************************** + * nuttx-config/scripts/canbootloader_script.ld + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* The STM32F412 has 1M of FLASH beginning at address 0x0800:0000 and + * 256Kb of SRAM. SRAM is split up into three blocks: + * + * 1) 112Kb of SRAM beginning at address 0x2000:0000 + * 2) 16Kb of SRAM beginning at address 0x2001:c000 + * 3) 64Kb of SRAM beginning at address 0x2002:0000 + * 4) 64Kb of TCM SRAM beginning at address 0x1000:0000 + * + * When booting from FLASH, FLASH memory is aliased to address 0x0000:0000 + * where the code expects to begin execution by jumping to the entry point in + * the 0x0800:0000 address range. + * + * The first 0x10000 of flash is reserved for the bootloader. + */ + +MEMORY +{ + flash (rx) : ORIGIN = 0x08000000, LENGTH = 32K + sram (rwx) : ORIGIN = 0x20000000, LENGTH = 192K +} + +OUTPUT_ARCH(arm) + +ENTRY(__start) /* treat __start as the anchor for dead code stripping */ +EXTERN(_vectors) /* force the vectors to be included in the output */ + +/* + * Ensure that abort() is present in the final object. The exception handling + * code pulled in by libgcc.a requires it (and that code cannot be easily avoided). + */ +EXTERN(abort) +SECTIONS +{ + .text : { + _stext = ABSOLUTE(.); + *(.vectors) + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.rodata .rodata.*) + *(.gnu.linkonce.t.*) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + _etext = ABSOLUTE(.); + } > flash + + /* + * Init functions (static constructors and the like) + */ + .init_section : { + _sinit = ABSOLUTE(.); + KEEP(*(.init_array .init_array.*)) + _einit = ABSOLUTE(.); + } > flash + + .ARM.extab : { + *(.ARM.extab*) + } > flash + + __exidx_start = ABSOLUTE(.); + .ARM.exidx : { + *(.ARM.exidx*) + } > flash + __exidx_end = ABSOLUTE(.); + + _eronly = ABSOLUTE(.); + + .data : { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + _edata = ABSOLUTE(.); + } > sram AT > flash + + .bss : { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = ABSOLUTE(.); + } > sram + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/boards/ark/mag/nuttx-config/scripts/script.ld b/boards/ark/mag/nuttx-config/scripts/script.ld new file mode 100644 index 0000000000..2f4769b8f5 --- /dev/null +++ b/boards/ark/mag/nuttx-config/scripts/script.ld @@ -0,0 +1,146 @@ +/**************************************************************************** + * scripts/ld.script + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* The STM32F412 has 1M of FLASH beginning at address 0x0800:0000 and + * 256Kb of SRAM. SRAM is split up into three blocks: + * + * 1) 112Kb of SRAM beginning at address 0x2000:0000 + * 2) 16Kb of SRAM beginning at address 0x2001:c000 + * 3) 64Kb of SRAM beginning at address 0x2002:0000 + * 4) 64Kb of TCM SRAM beginning at address 0x1000:0000 + * + * When booting from FLASH, FLASH memory is aliased to address 0x0000:0000 + * where the code expects to begin execution by jumping to the entry point in + * the 0x0800:0000 address range. + * + * The first 0x10000 of flash is reserved for the bootloader. + */ + +MEMORY +{ + flash (rx) : ORIGIN = 0x08010000, LENGTH = 928K + sram (rwx) : ORIGIN = 0x20000000, LENGTH = 192K +} + +OUTPUT_ARCH(arm) + +ENTRY(__start) /* treat __start as the anchor for dead code stripping */ +EXTERN(_vectors) /* force the vectors to be included in the output */ + +/* + * Ensure that abort() is present in the final object. The exception handling + * code pulled in by libgcc.a requires it (and that code cannot be easily avoided). + */ +EXTERN(abort) +EXTERN(_bootdelay_signature) + +SECTIONS +{ + .text : { + _stext = ABSOLUTE(.); + *(.vectors) + . = ALIGN(8); + /* + * This section positions the app_descriptor_t used + * by the make_can_boot_descriptor.py tool to set + * the application image's descriptor so that the + * uavcan bootloader has the ability to validate the + * image crc, size etc + */ + KEEP(*(.app_descriptor)) + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.rodata .rodata.*) + *(.gnu.linkonce.t.*) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + _etext = ABSOLUTE(.); + } > flash + + /* + * Init functions (static constructors and the like) + */ + .init_section : { + _sinit = ABSOLUTE(.); + KEEP(*(.init_array .init_array.*)) + _einit = ABSOLUTE(.); + } > flash + + + .ARM.extab : { + *(.ARM.extab*) + } > flash + + __exidx_start = ABSOLUTE(.); + .ARM.exidx : { + *(.ARM.exidx*) + } > flash + __exidx_end = ABSOLUTE(.); + + _eronly = ABSOLUTE(.); + + .data : { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + _edata = ABSOLUTE(.); + } > sram AT > flash + + .bss : { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = ABSOLUTE(.); + } > sram + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/boards/ark/mag/src/CMakeLists.txt b/boards/ark/mag/src/CMakeLists.txt new file mode 100644 index 0000000000..4fae41fc0e --- /dev/null +++ b/boards/ark/mag/src/CMakeLists.txt @@ -0,0 +1,65 @@ +############################################################################ +# +# 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. +# +############################################################################ + +if("${PX4_BOARD_LABEL}" STREQUAL "canbootloader") + + add_library(drivers_board + boot_config.h + boot.c + led.c + ) + target_link_libraries(drivers_board + PRIVATE + nuttx_arch + nuttx_drivers + canbootloader + ) + target_include_directories(drivers_board PRIVATE ${PX4_SOURCE_DIR}/platforms/nuttx/src/canbootloader) + +else() + add_library(drivers_board + can.c + init.c + led.c + spi.cpp + ) + + target_link_libraries(drivers_board + PRIVATE + arch_spi + drivers__led # drv_led_start + nuttx_arch + nuttx_drivers + px4_layer + ) +endif() diff --git a/boards/ark/mag/src/board_config.h b/boards/ark/mag/src/board_config.h new file mode 100644 index 0000000000..ca6e5bb094 --- /dev/null +++ b/boards/ark/mag/src/board_config.h @@ -0,0 +1,88 @@ +/**************************************************************************** + * + * Copyright (c) 2021 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 board_config.h + * + * board internal definitions + */ + +#pragma once + +#include +#include +#include + +/* CAN Silent mode control */ +#define GPIO_CAN1_SILENT_S0 /* PB11 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_CLEAR|GPIO_PORTB|GPIO_PIN11) + +/* CAN termination software control */ +#define GPIO_CAN1_TERMINATION /* PB13 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_CLEAR|GPIO_PORTB|GPIO_PIN13) +#define GPIO_CAN_TERM GPIO_CAN1_TERMINATION + +/* Boot config */ +#define GPIO_BOOT_CONFIG /* PC15 */ (GPIO_INPUT|GPIO_PULLUP|GPIO_PORTC|GPIO_PIN15|GPIO_EXTI) + +/* LEDs are driven with open drain to support Anode to 5V or 3.3V */ +#define GPIO_TIM1_CH1 /* PA8 */ (GPIO_TIM1_CH1_1|GPIO_OPENDRAIN|GPIO_SPEED_2MHz) +#define GPIO_TIM1_CH2 /* PA9 */ (GPIO_TIM1_CH2_1|GPIO_OPENDRAIN|GPIO_SPEED_2MHz) +#define GPIO_TIM1_CH3 /* PA10 */ (GPIO_TIM1_CH3_1|GPIO_OPENDRAIN|GPIO_SPEED_2MHz) + +#define FLASH_BASED_PARAMS + +/* High-resolution timer */ +#define HRT_TIMER 3 /* use timer 3 for the HRT */ +#define HRT_TIMER_CHANNEL 4 /* use capture/compare channel 4 */ + +#define PX4_GPIO_INIT_LIST { \ + GPIO_BOOT_CONFIG, \ + GPIO_CAN1_TX, \ + GPIO_CAN1_RX, \ + GPIO_CAN1_SILENT_S0, \ + GPIO_CAN1_TERMINATION, \ + } + +__BEGIN_DECLS + +#define BOARD_HAS_N_S_RGB_LED 1 +#define BOARD_MAX_LEDS BOARD_HAS_N_S_RGB_LED + +#ifndef __ASSEMBLY__ + +extern void stm32_spiinitialize(void); + +#include + +#endif /* __ASSEMBLY__ */ + +__END_DECLS diff --git a/boards/ark/mag/src/boot.c b/boards/ark/mag/src/boot.c new file mode 100644 index 0000000000..a26034e254 --- /dev/null +++ b/boards/ark/mag/src/boot.c @@ -0,0 +1,188 @@ +/**************************************************************************** + * + * Copyright (c) 2021 PX4 Development Team. All rights reserved. + * Author: Ben Dyer + * Pavel Kirienko + * David Sidrane + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "boot_config.h" +#include "board.h" + +#include +#include +#include + +#include +#include "led.h" + +/************************************************************************************ + * Name: stm32_boardinitialize + * + * Description: + * All STM32 architectures must provide the following entry point. This entry point + * is called early in the initialization -- after all memory has been configured + * and mapped but before any devices have been initialized. + * + ************************************************************************************/ + +__EXPORT void stm32_boardinitialize(void) +{ + putreg32(getreg32(STM32_RCC_APB1ENR) | RCC_APB1ENR_CAN1EN, STM32_RCC_APB1ENR); + stm32_configgpio(GPIO_CAN1_RX); + stm32_configgpio(GPIO_CAN1_TX); + stm32_configgpio(GPIO_CAN1_SILENT_S0); + stm32_configgpio(GPIO_CAN1_TERMINATION); + putreg32(getreg32(STM32_RCC_APB1RSTR) | RCC_APB1RSTR_CAN1RST, STM32_RCC_APB1RSTR); + putreg32(getreg32(STM32_RCC_APB1RSTR) & ~RCC_APB1RSTR_CAN1RST, STM32_RCC_APB1RSTR); + +#if defined(OPT_WAIT_FOR_GETNODEINFO_JUMPER_GPIO) + stm32_configgpio(GPIO_GETNODEINFO_JUMPER); +#endif + +} + +/************************************************************************************ + * Name: board_deinitialize + * + * Description: + * This function is called by the bootloader code prior to booting + * the application. Is should place the HW into an benign initialized state. + * + ************************************************************************************/ + +void board_deinitialize(void) +{ + putreg32(getreg32(STM32_RCC_APB1RSTR) | RCC_APB1RSTR_CAN1RST, STM32_RCC_APB1RSTR); +} + +/**************************************************************************** + * Name: board_get_product_name + * + * Description: + * Called to retrieve the product name. The returned value is a assumed + * to be written to a pascal style string that will be length prefixed + * and not null terminated + * + * Input Parameters: + * product_name - A pointer to a buffer to write the name. + * maxlen - The maximum number of charter that can be written + * + * Returned Value: + * The length of characters written to the buffer. + * + ****************************************************************************/ + +uint8_t board_get_product_name(uint8_t *product_name, size_t maxlen) +{ + DEBUGASSERT(maxlen > UAVCAN_STRLEN(HW_UAVCAN_NAME)); + memcpy(product_name, HW_UAVCAN_NAME, UAVCAN_STRLEN(HW_UAVCAN_NAME)); + return UAVCAN_STRLEN(HW_UAVCAN_NAME); +} + +/**************************************************************************** + * Name: board_get_hardware_version + * + * Description: + * Called to retrieve the hardware version information. The function + * will first initialize the the callers struct to all zeros. + * + * Input Parameters: + * hw_version - A pointer to a uavcan_hardwareversion_t. + * + * Returned Value: + * Length of the unique_id + * + ****************************************************************************/ + +size_t board_get_hardware_version(uavcan_HardwareVersion_t *hw_version) +{ + memset(hw_version, 0, sizeof(uavcan_HardwareVersion_t)); + + hw_version->major = HW_VERSION_MAJOR; + hw_version->minor = HW_VERSION_MINOR; + + return board_get_mfguid(*(mfguid_t *) hw_version->unique_id); +} + +/**************************************************************************** + * Name: board_indicate + * + * Description: + * Provides User feedback to indicate the state of the bootloader + * on board specific hardware. + * + * Input Parameters: + * indication - A member of the uiindication_t + * + * Returned Value: + * None + * + ****************************************************************************/ +#define led(n, code, r , g , b, h) {.red = (r),.green = (g), .blue = (b),.hz = (h)} + +typedef begin_packed_struct struct led_t { + uint8_t red; + uint8_t green; + uint8_t blue; + uint8_t hz; +} end_packed_struct led_t; + +static const led_t i2l[] = { + + led(0, off, 0, 0, 0, 0), + led(1, reset, 128, 128, 128, 30), + led(2, autobaud_start, 0, 128, 0, 1), + led(3, autobaud_end, 0, 128, 0, 2), + led(4, allocation_start, 0, 0, 64, 2), + led(5, allocation_end, 0, 128, 64, 3), + led(6, fw_update_start, 32, 128, 64, 3), + led(7, fw_update_erase_fail, 32, 128, 32, 3), + led(8, fw_update_invalid_response, 64, 0, 0, 1), + led(9, fw_update_timeout, 64, 0, 0, 2), + led(a, fw_update_invalid_crc, 64, 0, 0, 4), + led(b, jump_to_app, 0, 128, 0, 10), + +}; + +void board_indicate(uiindication_t indication) +{ + rgb_led(i2l[indication].red, + i2l[indication].green, + i2l[indication].blue, + i2l[indication].hz); +} diff --git a/boards/ark/mag/src/boot_config.h b/boards/ark/mag/src/boot_config.h new file mode 100644 index 0000000000..76782f9a93 --- /dev/null +++ b/boards/ark/mag/src/boot_config.h @@ -0,0 +1,130 @@ +/**************************************************************************** + * + * Copyright (c) 2021 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 boot_config.h + * + * bootloader definitions that configures the behavior and options + * of the Boot loader + * This file is relies on the parent folder's boot_config.h file and defines + * different usages of the hardware for bootloading + */ + +#pragma once + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +/* Bring in the board_config.h definitions + * todo:make this be pulled in from a targed's build + * files in nuttx*/ + +#include "board_config.h" +#include "uavcan.h" +#include + +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define OPT_PREFERRED_NODE_ID ANY_NODE_ID + +//todo:wrap OPT_x in in ifdefs for command line definitions +#define OPT_TBOOT_MS 3000 +#define OPT_NODE_STATUS_RATE_MS 800 +#define OPT_NODE_INFO_RATE_MS 50 +#define OPT_BL_NUMBER_TIMERS 7 + +/* + * This Option set is set to 1 ensure a provider of firmware has an + * opportunity update the node's firmware. + * This Option is the default policy and can be overridden by + * a jumper + * When this Policy is set, the node will ignore tboot and + * wait indefinitely for a GetNodeInfo request before booting. + * + * OPT_WAIT_FOR_GETNODEINFO_JUMPER_GPIO_INVERT is used to allow + * the polarity of the jumper to be True Active + * + * wait OPT_WAIT_FOR_GETNODEINFO OPT_WAIT_FOR_GETNODEINFO_JUMPER_GPIO + * Jumper + * yes 1 0 x + * yes 1 1 Active + * no 1 1 Not Active + * no 0 0 X + * yes 0 1 Active + * no 0 1 Not Active + * + */ +#define OPT_WAIT_FOR_GETNODEINFO 0 +#define OPT_WAIT_FOR_GETNODEINFO_JUMPER_GPIO 1 +#define OPT_WAIT_FOR_GETNODEINFO_JUMPER_GPIO_INVERT 1 + +#define OPT_ENABLE_WD 1 + +#define OPT_RESTART_TIMEOUT_MS 20000 + +/* Reserved for the Booloader */ +#define OPT_BOOTLOADER_SIZE_IN_K (1024*64) + +/* Reserved for the application out of the total + * system flash minus the BOOTLOADER_SIZE_IN_K + */ +#define OPT_APPLICATION_RESERVER_IN_K 0 + +#define OPT_APPLICATION_IMAGE_OFFSET OPT_BOOTLOADER_SIZE_IN_K +#define OPT_APPLICATION_IMAGE_LENGTH (FLASH_SIZE-(OPT_BOOTLOADER_SIZE_IN_K+OPT_APPLICATION_RESERVER_IN_K)) + + +#define FLASH_BASE STM32_FLASH_BASE +#define FLASH_SIZE STM32_FLASH_SIZE + +#define APPLICATION_LOAD_ADDRESS (FLASH_BASE + OPT_APPLICATION_IMAGE_OFFSET) +#define APPLICATION_SIZE (FLASH_SIZE-OPT_APPLICATION_IMAGE_OFFSET) +#define APPLICATION_LAST_8BIT_ADDRRESS ((uint8_t *)((APPLICATION_LOAD_ADDRESS+APPLICATION_SIZE)-sizeof(uint8_t))) +#define APPLICATION_LAST_32BIT_ADDRRESS ((uint32_t *)((APPLICATION_LOAD_ADDRESS+APPLICATION_SIZE)-sizeof(uint32_t))) +#define APPLICATION_LAST_64BIT_ADDRRESS ((uint64_t *)((APPLICATION_LOAD_ADDRESS+APPLICATION_SIZE)-sizeof(uint64_t))) + +/* If this board uses big flash that have large sectors */ + +#define OPT_USE_YIELD + +/* Bootloader Option***************************************************************** + * + */ +#define GPIO_GETNODEINFO_JUMPER (GPIO_BOOT_CONFIG & ~GPIO_EXTI) diff --git a/boards/ark/mag/src/can.c b/boards/ark/mag/src/can.c new file mode 100644 index 0000000000..7737965dc6 --- /dev/null +++ b/boards/ark/mag/src/can.c @@ -0,0 +1,130 @@ +/**************************************************************************** + * + * Copyright (C) 2021 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 can.c + * + * Board-specific CAN functions. + */ + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include "chip.h" +#include "arm_internal.h" + +#include "stm32.h" +#include "stm32_can.h" +#include "board_config.h" + +#ifdef CONFIG_CAN + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ +/* Configuration ********************************************************************/ + +#if defined(CONFIG_STM32_CAN1) && defined(CONFIG_STM32_CAN2) +# warning "Both CAN1 and CAN2 are enabled. Assuming only CAN1." +# undef CONFIG_STM32_CAN2 +#endif + +#ifdef CONFIG_STM32_CAN1 +# define CAN_PORT 1 +#else +# define CAN_PORT 2 +#endif + +/************************************************************************************ + * Private Functions + ************************************************************************************/ + +/************************************************************************************ + * Public Functions + ************************************************************************************/ +int can_devinit(void); + +/************************************************************************************ + * Name: can_devinit + * + * Description: + * All STM32 architectures must provide the following interface to work with + * examples/can. + * + ************************************************************************************/ + +int can_devinit(void) +{ + static bool initialized = false; + struct can_dev_s *can; + int ret; + + /* Check if we have already initialized */ + + if (!initialized) { + /* Call stm32_caninitialize() to get an instance of the CAN interface */ + + can = stm32_caninitialize(CAN_PORT); + + if (can == NULL) { + canerr("ERROR: Failed to get CAN interface\n"); + return -ENODEV; + } + + /* Register the CAN driver at "/dev/can0" */ + + ret = can_register("/dev/can0", can); + + if (ret < 0) { + canerr("ERROR: can_register failed: %d\n", ret); + return ret; + } + + /* Now we are initialized */ + + initialized = true; + } + + return OK; +} + +#endif diff --git a/boards/ark/mag/src/init.c b/boards/ark/mag/src/init.c new file mode 100644 index 0000000000..a6290bdc7a --- /dev/null +++ b/boards/ark/mag/src/init.c @@ -0,0 +1,147 @@ +/**************************************************************************** + * + * Copyright (c) 2021 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 init.c + * + * board specific early startup code. This file implements the + * board_app_initialize() function that is called early by nsh during startup. + * + * Code here is run before the rcS script is invoked; it should start required + * subsystems and perform board-specific initialization. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include "board_config.h" +#include "led.h" +#include + +#include + +#include +#include +#include + +#include + +#include +#include + +# if defined(FLASH_BASED_PARAMS) +# include +#endif + +/************************************************************************************ + * Name: stm32_boardinitialize + * + * Description: + * All STM32 architectures must provide the following entry point. This entry point + * is called early in the initialization -- after all memory has been configured + * and mapped but before any devices have been initialized. + * + ************************************************************************************/ + +__EXPORT void stm32_boardinitialize(void) +{ + watchdog_init(); + + /* configure pins */ + const uint32_t gpio[] = PX4_GPIO_INIT_LIST; + px4_gpio_init(gpio, arraySize(gpio)); + + // Configure SPI all interfaces GPIO & enable power. + stm32_spiinitialize(); +} + +/**************************************************************************** + * Name: board_app_initialize + * + * Description: + * Perform application specific initialization. This function is never + * called directly from application code, but only indirectly via the + * (non-standard) boardctl() interface using the command BOARDIOC_INIT. + * + * Input Parameters: + * arg - The boardctl() argument is passed to the board_app_initialize() + * implementation without modification. The argument has no + * meaning to NuttX; the meaning of the argument is a contract + * between the board-specific initalization logic and the the + * matching application logic. The value cold be such things as a + * mode enumeration value, a set of DIP switch switch settings, a + * pointer to configuration data read from a file or serial FLASH, + * or whatever you would like to do with it. Every implementation + * should accept zero/NULL as a default configuration. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure to indicate the nature of the failure. + * + ****************************************************************************/ + +__EXPORT int board_app_initialize(uintptr_t arg) +{ + px4_platform_init(); + +#if defined(FLASH_BASED_PARAMS) + static sector_descriptor_t params_sector_map[] = { + {2, 16 * 1024, 0x08008000}, + {3, 16 * 1024, 0x0800C000}, + {0, 0, 0}, + }; + + /* Initialize the flashfs layer to use heap allocated memory */ + int result = parameter_flashfs_init(params_sector_map, NULL, 0); + + if (result != OK) { + syslog(LOG_ERR, "[boot] FAILED to init params in FLASH %d\n", result); + } + +#endif // FLASH_BASED_PARAMS + + /* Configure the HW based on the manifest */ + //px4_platform_configure(); + + return OK; +} diff --git a/boards/ark/mag/src/led.c b/boards/ark/mag/src/led.c new file mode 100644 index 0000000000..24c3c42bf4 --- /dev/null +++ b/boards/ark/mag/src/led.c @@ -0,0 +1,124 @@ +/**************************************************************************** + * + * Copyright (c) 2021 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 led.c + * + * LED backend. + */ + +#include + +#include + +#include "chip.h" +#include "stm32_gpio.h" +#include "board_config.h" + +#include +#include + +#include "led.h" + +#define TMR_BASE STM32_TIM1_BASE +#define TMR_FREQUENCY STM32_APB2_TIM1_CLKIN +#define TMR_REG(o) (TMR_BASE+(o)) + +void rgb_led(int r, int g, int b, int freqs) +{ + + long fosc = TMR_FREQUENCY; + long prescale = 2048; + long p1s = fosc / prescale; + long p0p5s = p1s / 2; + uint16_t val; + static bool once = 0; + + if (!once) { + once = 1; + + /* Enable Clock to Block */ + modifyreg32(STM32_RCC_APB2ENR, 0, RCC_APB2ENR_TIM1EN); + + /* Reload */ + + val = getreg16(TMR_REG(STM32_BTIM_EGR_OFFSET)); + val |= ATIM_EGR_UG; + putreg16(val, TMR_REG(STM32_BTIM_EGR_OFFSET)); + + /* Set Prescaler STM32_TIM_SETCLOCK */ + + putreg16(prescale, TMR_REG(STM32_BTIM_PSC_OFFSET)); + + /* Enable STM32_TIM_SETMODE*/ + + putreg16(ATIM_CR1_CEN | ATIM_CR1_ARPE, TMR_REG(STM32_BTIM_CR1_OFFSET)); + + + putreg16((ATIM_CCMR_MODE_PWM1 << ATIM_CCMR1_OC1M_SHIFT) | ATIM_CCMR1_OC1PE | + (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR1_OC2M_SHIFT) | ATIM_CCMR1_OC2PE, TMR_REG(STM32_GTIM_CCMR1_OFFSET)); + putreg16((ATIM_CCMR_MODE_PWM1 << ATIM_CCMR2_OC3M_SHIFT) | ATIM_CCMR2_OC3PE, TMR_REG(STM32_GTIM_CCMR2_OFFSET)); + putreg16(ATIM_CCER_CC3E | ATIM_CCER_CC3P | + ATIM_CCER_CC2E | ATIM_CCER_CC2P | + ATIM_CCER_CC1E | ATIM_CCER_CC1P, TMR_REG(STM32_GTIM_CCER_OFFSET)); + + + stm32_configgpio(GPIO_TIM1_CH1); + stm32_configgpio(GPIO_TIM1_CH2); + stm32_configgpio(GPIO_TIM1_CH3); + + /* master output enable = on */ + putreg16(ATIM_BDTR_MOE, (TMR_REG(STM32_ATIM_BDTR_OFFSET))); + } + + long p = freqs == 0 ? p1s : p1s / freqs; + putreg32(p, TMR_REG(STM32_BTIM_ARR_OFFSET)); + + p = freqs == 0 ? p1s + 1 : p0p5s / freqs; + + putreg32((r * p) / 255, TMR_REG(STM32_GTIM_CCR1_OFFSET)); + putreg32((g * p) / 255, TMR_REG(STM32_GTIM_CCR2_OFFSET)); + putreg32((b * p) / 255, TMR_REG(STM32_GTIM_CCR3_OFFSET)); + + val = getreg16(TMR_REG(STM32_BTIM_CR1_OFFSET)); + + if (freqs == 0) { + val &= ~ATIM_CR1_CEN; + + } else { + val |= ATIM_CR1_CEN; + } + + putreg16(val, TMR_REG(STM32_BTIM_CR1_OFFSET)); + +} diff --git a/boards/ark/mag/src/led.h b/boards/ark/mag/src/led.h new file mode 100644 index 0000000000..b68e4aa70d --- /dev/null +++ b/boards/ark/mag/src/led.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * + * Copyright (C) 2015 PX4 Development Team. All rights reserved. + * Author: David Sidrane + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name 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. + * + ****************************************************************************/ + +__BEGIN_DECLS +void rgb_led(int r, int g, int b, int freqs); +__END_DECLS diff --git a/boards/ark/mag/src/spi.cpp b/boards/ark/mag/src/spi.cpp new file mode 100644 index 0000000000..b32d42b514 --- /dev/null +++ b/boards/ark/mag/src/spi.cpp @@ -0,0 +1,44 @@ +/**************************************************************************** + * + * Copyright (C) 2021 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include +#include +#include + +constexpr px4_spi_bus_t px4_spi_buses[SPI_BUS_MAX_BUS_ITEMS] = { + initSPIBus(SPI::Bus::SPI2, { + initSPIDevice(DRV_MAG_DEVTYPE_RM3100, SPI::CS{GPIO::PortB, GPIO::Pin12}, SPI::DRDY{GPIO::PortB, GPIO::Pin4}), + }), +}; + +static constexpr bool unused = validateSPIConfig(px4_spi_buses); diff --git a/boards/ark/mag/uavcan_board_identity b/boards/ark/mag/uavcan_board_identity new file mode 100644 index 0000000000..1e30c3d822 --- /dev/null +++ b/boards/ark/mag/uavcan_board_identity @@ -0,0 +1,17 @@ +# UAVCAN boot loadable Module ID +set(uavcanblid_sw_version_major ${PX4_VERSION_MAJOR}) +set(uavcanblid_sw_version_minor ${PX4_VERSION_MINOR}) +add_definitions( + -DAPP_VERSION_MAJOR=${uavcanblid_sw_version_major} + -DAPP_VERSION_MINOR=${uavcanblid_sw_version_minor} +) + +set(uavcanblid_hw_version_major 0) +set(uavcanblid_hw_version_minor 93) +set(uavcanblid_name "\"org.ark.mag\"") + +add_definitions( + -DHW_UAVCAN_NAME=${uavcanblid_name} + -DHW_VERSION_MAJOR=${uavcanblid_hw_version_major} + -DHW_VERSION_MINOR=${uavcanblid_hw_version_minor} +) From d5eea0dd924b8581e3d4216d41106c36c71b48c1 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Mon, 8 Sep 2025 11:49:27 +0300 Subject: [PATCH 005/139] sensors/VehicleImu: Don't set _backup_schedule_timeout_us shorter than normal scheduling interval With IMUs of higher report rate (e.g. ADIS16470), setting backup schedule timeout simply to half of the ORB queue length may cause the backup firing before required updates are received. Set backup schedule to queue length - 1 instead. Additionally, double-check that the backup doesn't get too short after finding the largest integer multiple of gyro_integral_samples. Signed-off-by: Jukka Laitinen --- src/modules/sensors/vehicle_imu/VehicleIMU.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/modules/sensors/vehicle_imu/VehicleIMU.cpp b/src/modules/sensors/vehicle_imu/VehicleIMU.cpp index b8c0a9547e..7ba258a66b 100644 --- a/src/modules/sensors/vehicle_imu/VehicleIMU.cpp +++ b/src/modules/sensors/vehicle_imu/VehicleIMU.cpp @@ -706,8 +706,8 @@ void VehicleIMU::UpdateIntegratorConfiguration() _gyro_integrator.set_reset_interval(roundf((gyro_integral_samples - 0.5f) * gyro_interval_us)); _gyro_integrator.set_reset_samples(gyro_integral_samples); - _backup_schedule_timeout_us = math::constrain((int)math::min(sensor_accel_s::ORB_QUEUE_LENGTH * accel_interval_us, - sensor_gyro_s::ORB_QUEUE_LENGTH * gyro_interval_us) / 2, 1000, 20000); + _backup_schedule_timeout_us = math::constrain((int)math::min((sensor_accel_s::ORB_QUEUE_LENGTH - 1) * accel_interval_us, + (sensor_gyro_s::ORB_QUEUE_LENGTH - 1) * gyro_interval_us), 1000, 20000); // gyro: find largest integer multiple of gyro_integral_samples for (int n = sensor_gyro_s::ORB_QUEUE_LENGTH; n > 0; n--) { @@ -716,6 +716,12 @@ void VehicleIMU::UpdateIntegratorConfiguration() } if (gyro_integral_samples % n == 0) { + // Make sure _backup_schedule_timeout_us is not smaller than normal scheduling interval + + if (_backup_schedule_timeout_us < n * gyro_interval_us) { + _backup_schedule_timeout_us = (n + 1) * gyro_interval_us; + } + _sensor_gyro_sub.set_required_updates(n); _sensor_gyro_sub.registerCallback(); From f3ee45b1735325176693e4a31d53653772ada97d Mon Sep 17 00:00:00 2001 From: Jacob Dahl <37091262+dakejahl@users.noreply.github.com> Date: Sat, 1 Nov 2025 09:38:02 -0800 Subject: [PATCH 006/139] ark: fmuv6x: fix imu start after spi sync removal (#25851) --- boards/ark/fmu-v6x/init/rc.board_sensors | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/boards/ark/fmu-v6x/init/rc.board_sensors b/boards/ark/fmu-v6x/init/rc.board_sensors index aacbc22db0..c16ed31f69 100644 --- a/boards/ark/fmu-v6x/init/rc.board_sensors +++ b/boards/ark/fmu-v6x/init/rc.board_sensors @@ -1,6 +1,6 @@ #!/bin/sh # -# ARK FMUARKV6X specific board sensors init +# ARK FMU V6X specific board sensors init #------------------------------------------------------------------------------ set HAVE_PM2 yes set HAVE_PM3 yes @@ -69,28 +69,25 @@ fi if ver hwtypecmp ARKV6X000 then - # Internal SPI bus IIM42652 with SPIX measured frequency of 32.051kHz - iim42652 -R 3 -s -b 1 -C 32051 start + # Internal SPI bus IIM42652 + iim42652 -R 3 -s -b 1 start - # Internal SPI bus ICM42688p with SPIX measured frequency of 32.051kHz - icm42688p -R 9 -s -b 2 -C 32051 start + # Internal SPI bus ICM42688p + icm42688p -R 9 -s -b 2 start - # Internal SPI bus ICM42688p with SPIX measured frequency of 32.051kHz - icm42688p -R 6 -s -b 3 -C 32051 start + # Internal SPI bus ICM42688p + icm42688p -R 6 -s -b 3 start fi if ver hwtypecmp ARKV6X001 then - # Internal SPI bus IIM42653 with SPIX measured frequency of 32.051kHz - #iim42653 -R 3 -s -b 1 -C 32051 start + # Internal SPI bus IIM42653 iim42653 -R 3 -s -b 1 start - # Internal SPI bus IIM42653 with SPIX measured frequency of 32.051kHz - #iim42653 -R 9 -s -b 2 -C 32051 start + # Internal SPI bus IIM42653 iim42653 -R 9 -s -b 2 start - # Internal SPI bus IIM42653 with SPIX measured frequency of 32.051kHz - #iim42653 -R 6 -s -b 3 -C 32051 start + # Internal SPI bus IIM42653 iim42653 -R 6 -s -b 3 start fi From cfe4cc82eae25d25bb1382b2e392d2bcfb164f13 Mon Sep 17 00:00:00 2001 From: Claudio Chies <61051109+Claudio-Chies@users.noreply.github.com> Date: Mon, 3 Nov 2025 09:34:54 +0100 Subject: [PATCH 007/139] UAVCAN: fix message definition issues (#25809) --- .../uavcannode/Publishers/BatteryInfo.hpp | 61 ++++++++++++++----- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/src/drivers/uavcannode/Publishers/BatteryInfo.hpp b/src/drivers/uavcannode/Publishers/BatteryInfo.hpp index 686dc05086..7cd45d6f2a 100644 --- a/src/drivers/uavcannode/Publishers/BatteryInfo.hpp +++ b/src/drivers/uavcannode/Publishers/BatteryInfo.hpp @@ -36,6 +36,7 @@ #include "UavcanPublisherBase.hpp" #include +#include #include #include @@ -47,15 +48,18 @@ namespace uavcannode class BatteryInfo : public UavcanPublisherBase, private uORB::SubscriptionCallbackWorkItem, - private uavcan::Publisher + private uavcan::Publisher, + private uavcan::Publisher { public: BatteryInfo(px4::WorkItem *work_item, uavcan::INode &node) : UavcanPublisherBase(uavcan::equipment::power::BatteryInfo::DefaultDataTypeID), uORB::SubscriptionCallbackWorkItem(work_item, ORB_ID(battery_status)), - uavcan::Publisher(node) + uavcan::Publisher(node), + uavcan::Publisher(node) { - this->setPriority(uavcan::TransferPriority::MiddleLower); + uavcan::Publisher::setPriority(uavcan::TransferPriority::MiddleLower); + uavcan::Publisher::setPriority(uavcan::TransferPriority::MiddleLower); } void PrintInfo() override @@ -65,36 +69,63 @@ public: uORB::SubscriptionCallbackWorkItem::get_topic()->o_name, uavcan::equipment::power::BatteryInfo::getDataTypeFullName(), uavcan::equipment::power::BatteryInfo::DefaultDataTypeID); + printf("\t%s -> %s:%d\n", + uORB::SubscriptionCallbackWorkItem::get_topic()->o_name, + ardupilot::equipment::power::BatteryInfoAux::getDataTypeFullName(), + ardupilot::equipment::power::BatteryInfoAux::DefaultDataTypeID); } } void BroadcastAnyUpdates() override { - // battery_status -> uavcan::equipment::power::BatteryInfo + // battery_status -> uavcan::equipment::power::BatteryInfo & ardupilot::equipment::power::BatteryInfoAux battery_status_s battery; if (uORB::SubscriptionCallbackWorkItem::update(&battery)) { + ardupilot::equipment::power::BatteryInfoAux battery_info_aux{}; + + battery_info_aux.timestamp.usec = battery.timestamp; + + for (uint8_t i = 0; i < battery.cell_count && i < battery.voltage_cell_v.size(); i++) { + battery_info_aux.voltage_cell.push_back(battery.voltage_cell_v[i]); + } + + battery_info_aux.cycle_count = battery.cycle_count; + battery_info_aux.over_discharge_count = battery.over_discharge_count; + battery_info_aux.max_current = battery.current_a; + battery_info_aux.nominal_voltage = battery.nominal_voltage; + battery_info_aux.is_powering_off = battery.is_powering_off; + battery_info_aux.battery_id = battery.id; + + uavcan::Publisher::broadcast(battery_info_aux); + uavcan::equipment::power::BatteryInfo battery_info{}; battery_info.voltage = battery.voltage_v; - battery_info.current = fabs(battery.current_a); + battery_info.current = battery.current_a; battery_info.temperature = battery.temperature - atmosphere::kAbsoluteNullCelsius; // convert from C to K - battery_info.full_charge_capacity_wh = battery.capacity; - battery_info.remaining_capacity_wh = battery.remaining * battery.capacity; - battery_info.state_of_charge_pct = battery.remaining * 100; + battery_info.full_charge_capacity_wh = battery.full_charge_capacity_wh; + battery_info.remaining_capacity_wh = battery.remaining_capacity_wh; + battery_info.state_of_charge_pct = battery.remaining * 100.0f; battery_info.state_of_charge_pct_stdev = battery.max_error; + battery_info.battery_id = battery.id; battery_info.model_instance_id = 0; // TODO: what goes here? - battery_info.model_name = "ARK BMS Rev 0.2"; - battery_info.battery_id = battery.serial_number; - battery_info.hours_to_full_charge = 0; // TODO: Read BQ40Z80_TIME_TO_FULL + battery_info.model_name = "PX4 CAN Battery"; + + // State of health battery_info.state_of_health_pct = battery.state_of_health; - if (battery.current_a > 0.0f) { - battery_info.status_flags = uavcan::equipment::power::BatteryInfo::STATUS_FLAG_CHARGING; + uint8_t status_flags = 0; - } else { - battery_info.status_flags = uavcan::equipment::power::BatteryInfo::STATUS_FLAG_IN_USE; + if (battery.connected) { + status_flags |= uavcan::equipment::power::BatteryInfo::STATUS_FLAG_IN_USE; } + if (battery.warning == battery_status_s::STATE_CHARGING) { + status_flags |= uavcan::equipment::power::BatteryInfo::STATUS_FLAG_CHARGING; + } + + battery_info.status_flags = status_flags; + uavcan::Publisher::broadcast(battery_info); // ensure callback is registered From 9702a2a899c9a48a3f22444d8ee49e066fdbfe83 Mon Sep 17 00:00:00 2001 From: Matthew Berk <8104397+msberk@users.noreply.github.com> Date: Mon, 3 Nov 2025 10:52:26 -0600 Subject: [PATCH 008/139] Navigator: Fix mission RTL for fixed-wing by setting previous waypoint correctly (#25600) This aligns setActiveMissionItems() in rtl_direct_mission_land.cpp and in rtl_mission_fast.cpp with what was already in mission.cpp. It probably was on oversight when the RTL restructure happened. The FW landing requires the previous waypoint to be correctly set, that's why it was only noticeable there. * Fix position setpoint update logic in Mission RTL Currently, when proceeding to the landing point the previous setpoint is not updated, which results in an unexpected and off course landing pattern in fixed wing. (see #25436) * Change to work more like `mission.cpp` * Fix rtl_direct_misssion_land formatting for style guide * rtl_mission_fast: fix FW landing by setting previous wp in landing Signed-off-by: Silvan --------- Signed-off-by: Silvan Co-authored-by: Silvan --- src/modules/navigator/rtl_direct_mission_land.cpp | 9 +++++++-- src/modules/navigator/rtl_mission_fast.cpp | 10 +++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/modules/navigator/rtl_direct_mission_land.cpp b/src/modules/navigator/rtl_direct_mission_land.cpp index 7e8b3d4aa4..7fdbe1add5 100644 --- a/src/modules/navigator/rtl_direct_mission_land.cpp +++ b/src/modules/navigator/rtl_direct_mission_land.cpp @@ -122,6 +122,7 @@ void RtlDirectMissionLand::setActiveMissionItems() { WorkItemType new_work_item_type{WorkItemType::WORK_ITEM_TYPE_DEFAULT}; position_setpoint_triplet_s *pos_sp_triplet = _navigator->get_position_setpoint_triplet(); + const position_setpoint_s current_setpoint_copy = pos_sp_triplet->current; // Climb to altitude if (_needs_climbing && _work_item_type == WorkItemType::WORK_ITEM_TYPE_DEFAULT) { @@ -203,8 +204,6 @@ void RtlDirectMissionLand::setActiveMissionItems() _mission_item.autocontinue = true; _mission_item.time_inside = 0.0f; - - pos_sp_triplet->previous = pos_sp_triplet->current; } if (num_found_items > 0) { @@ -213,6 +212,12 @@ void RtlDirectMissionLand::setActiveMissionItems() mission_item_to_position_setpoint(_mission_item, &pos_sp_triplet->current); + // Only set the previous position item if the current one really changed + if ((_work_item_type != WorkItemType::WORK_ITEM_TYPE_MOVE_TO_LAND) && + !position_setpoint_equal(&pos_sp_triplet->current, ¤t_setpoint_copy)) { + pos_sp_triplet->previous = current_setpoint_copy; + } + // prevent lateral guidance from loitering at a waypoint as part of a mission landing if the altitude // is not achieved. const bool fw_on_mission_landing = _vehicle_status_sub.get().vehicle_type == vehicle_status_s::VEHICLE_TYPE_FIXED_WING diff --git a/src/modules/navigator/rtl_mission_fast.cpp b/src/modules/navigator/rtl_mission_fast.cpp index a8a7809549..bb73fd6952 100644 --- a/src/modules/navigator/rtl_mission_fast.cpp +++ b/src/modules/navigator/rtl_mission_fast.cpp @@ -108,6 +108,7 @@ void RtlMissionFast::setActiveMissionItems() { WorkItemType new_work_item_type{WorkItemType::WORK_ITEM_TYPE_DEFAULT}; position_setpoint_triplet_s *pos_sp_triplet = _navigator->get_position_setpoint_triplet(); + const position_setpoint_s current_setpoint_copy = pos_sp_triplet->current; /* Skip VTOL/FW Takeoff item if in air, fixed-wing and didn't start the takeoff already*/ if ((_mission_item.nav_cmd == NAV_CMD_VTOL_TAKEOFF || _mission_item.nav_cmd == NAV_CMD_TAKEOFF) && @@ -175,17 +176,20 @@ void RtlMissionFast::setActiveMissionItems() _mission_item.autocontinue = true; _mission_item.time_inside = 0.0f; - pos_sp_triplet->previous = pos_sp_triplet->current; } - - if (num_found_items > 0) { mission_item_to_position_setpoint(next_mission_items[0u], &pos_sp_triplet->next); } mission_item_to_position_setpoint(_mission_item, &pos_sp_triplet->current); + // Only set the previous position item if the current one really changed + if ((_work_item_type != WorkItemType::WORK_ITEM_TYPE_MOVE_TO_LAND) && + !position_setpoint_equal(&pos_sp_triplet->current, ¤t_setpoint_copy)) { + pos_sp_triplet->previous = current_setpoint_copy; + } + if (_vehicle_status_sub.get().vehicle_type == vehicle_status_s::VEHICLE_TYPE_FIXED_WING && isLanding() && _mission_item.nav_cmd == NAV_CMD_WAYPOINT) { pos_sp_triplet->current.alt_acceptance_radius = FLT_MAX; From c44e0be18ae58fc2850da472e41dee4a3dbe1398 Mon Sep 17 00:00:00 2001 From: Thijs Hof Date: Sat, 1 Nov 2025 15:18:36 +0100 Subject: [PATCH 009/139] fix bidir dshot for nxp xrt boards --- platforms/nuttx/src/px4/nxp/imxrt/dshot/dshot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platforms/nuttx/src/px4/nxp/imxrt/dshot/dshot.c b/platforms/nuttx/src/px4/nxp/imxrt/dshot/dshot.c index 233d4fc288..d0558592a5 100644 --- a/platforms/nuttx/src/px4/nxp/imxrt/dshot/dshot.c +++ b/platforms/nuttx/src/px4/nxp/imxrt/dshot/dshot.c @@ -425,7 +425,7 @@ int up_bdshot_num_erpm_ready(void) for (unsigned i = 0; i < DSHOT_TIMERS; ++i) { // We only check that data has been received, rather than if it's valid. // This ensures data is published even if one channel has bit errors. - if (bdshot_recv_mask & (1 << i)) { + if (bdshot_parsed_recv_mask & (1 << i)) { ++num_ready; } } From ae03630570254b2e3037039569a38d13885e8e9d Mon Sep 17 00:00:00 2001 From: Matthias Grob Date: Tue, 28 Oct 2025 16:03:55 +0100 Subject: [PATCH 010/139] uavcan: more efficient calculation of esc.RawCommand.cmd array size --- src/drivers/uavcan/actuators/esc.cpp | 29 +++------------------------- src/drivers/uavcan/actuators/esc.hpp | 7 ++----- src/drivers/uavcan/uavcan_main.cpp | 16 +++++++++++++-- 3 files changed, 19 insertions(+), 33 deletions(-) diff --git a/src/drivers/uavcan/actuators/esc.cpp b/src/drivers/uavcan/actuators/esc.cpp index cefc5b276d..15b5504c45 100644 --- a/src/drivers/uavcan/actuators/esc.cpp +++ b/src/drivers/uavcan/actuators/esc.cpp @@ -1,6 +1,6 @@ /**************************************************************************** * - * Copyright (C) 2014 PX4 Development Team. All rights reserved. + * Copyright (C) 2014-2025 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 @@ -74,20 +74,13 @@ UavcanEscController::init() _uavcan_pub_raw_cmd.getTransferSender().setIfaceMask(iface_mask); } - char param_name[17]; - - for (unsigned i = 0; i < MAX_ACTUATORS; ++i) { - snprintf(param_name, sizeof(param_name), "UAVCAN_EC_FUNC%d", i + 1); - _param_handles[i] = param_find(param_name); - } - _initialized = true; return res; } void -UavcanEscController::update_outputs(uint16_t outputs[MAX_ACTUATORS], unsigned total_outputs) +UavcanEscController::update_outputs(uint16_t outputs[MAX_ACTUATORS], uint8_t output_array_size) { // TODO: configurable rate limit const auto timestamp = _node.getMonotonicTime(); @@ -100,26 +93,10 @@ UavcanEscController::update_outputs(uint16_t outputs[MAX_ACTUATORS], unsigned to uavcan::equipment::esc::RawCommand msg = {}; - // directly output values from mixer - for (unsigned i = 0; i < total_outputs; i++) { + for (unsigned i = 0; i < output_array_size; i++) { msg.cmd.push_back(static_cast(outputs[i])); } - // but only output as many channels as are configured - uint8_t min_size = 0; - - for (int i = 0; i < MAX_ACTUATORS; i++) { - int32_t val = 0; - - if (param_get(_param_handles[i], &val) == 0) { - if (val > 0) { - min_size = i + 1; - } - } - } - - msg.cmd.resize(min_size); - _uavcan_pub_raw_cmd.broadcast(msg); } diff --git a/src/drivers/uavcan/actuators/esc.hpp b/src/drivers/uavcan/actuators/esc.hpp index e758bb1030..e488cf823a 100644 --- a/src/drivers/uavcan/actuators/esc.hpp +++ b/src/drivers/uavcan/actuators/esc.hpp @@ -1,6 +1,6 @@ /**************************************************************************** * - * Copyright (C) 2014 PX4 Development Team. All rights reserved. + * Copyright (C) 2014-2025 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 @@ -71,7 +71,7 @@ public: bool initialized() { return _initialized; }; - void update_outputs(uint16_t outputs[MAX_ACTUATORS], unsigned total_outputs); + void update_outputs(uint16_t outputs[MAX_ACTUATORS], uint8_t output_array_size); /** * Sets the number of rotors and enable timer @@ -114,7 +114,4 @@ private: uavcan::INode &_node; uavcan::Publisher _uavcan_pub_raw_cmd; uavcan::Subscriber _uavcan_sub_status; - - - param_t _param_handles[MAX_ACTUATORS] {PARAM_INVALID}; }; diff --git a/src/drivers/uavcan/uavcan_main.cpp b/src/drivers/uavcan/uavcan_main.cpp index 37e36c2217..28f64049db 100644 --- a/src/drivers/uavcan/uavcan_main.cpp +++ b/src/drivers/uavcan/uavcan_main.cpp @@ -1,6 +1,6 @@ /**************************************************************************** * - * Copyright (c) 2014-2022 PX4 Development Team. All rights reserved. + * Copyright (c) 2014-2025 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 @@ -1082,7 +1082,19 @@ bool UavcanMixingInterfaceESC::updateOutputs(uint16_t outputs[MAX_ACTUATORS], un unsigned num_control_groups_updated) { if (_esc_controller.initialized()) { - _esc_controller.update_outputs(outputs, num_outputs); + // num_outputs is the maximum possible number of outputs (8) + // output_array_size adapts to the highest output index that is mapped (4 for a quad) + // this allows for sending less CAN frames depending on what output indices are mapped + uint8_t output_array_size = 0; + + for (int i = MAX_ACTUATORS - 1; i >= 0; i--) { + if (mixingOutput().isFunctionSet(i)) { + output_array_size = i + 1; + break; + } + } + + _esc_controller.update_outputs(outputs, output_array_size); } return true; From b010fe904c5b7ee19edcec8a0ffb10e275fd986d Mon Sep 17 00:00:00 2001 From: Vincello <58676585+holydust@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:25:40 +0800 Subject: [PATCH 011/139] fix board_id --- .../743v1/extras/corvon_743v1_bootloader.bin | Bin 41044 -> 41172 bytes boards/corvon/743v1/firmware.prototype | 2 +- boards/corvon/743v1/src/hw_config.h | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/corvon/743v1/extras/corvon_743v1_bootloader.bin b/boards/corvon/743v1/extras/corvon_743v1_bootloader.bin index a9209278330a4ab0132e5db7161ac06841e6dce4..0875784c2cc2581783805b47f15c0ca74f715813 100644 GIT binary patch delta 22009 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 T%2B{~06-rLP(Lc!N5AzyMgj29 delta 21698 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 GUHd Date: Mon, 3 Nov 2025 21:47:35 -0600 Subject: [PATCH 012/139] flight_modes_fw/return.md: remove warning about now-fixed bug in mission RTLs in FW --- docs/en/flight_modes_fw/return.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/en/flight_modes_fw/return.md b/docs/en/flight_modes_fw/return.md index 01ceafe6a4..393d1c6a13 100644 --- a/docs/en/flight_modes_fw/return.md +++ b/docs/en/flight_modes_fw/return.md @@ -25,11 +25,6 @@ The default type is recommended. ::: -::: warning -There is a known issue ([PX4-Autopilot#25436](https://github.com/PX4/PX4-Autopilot/issues/25436)) with fixed-wing approaches and landings while in RTL mode. -Please review the issue and verify in simulation that the behavior you get is safe in an RTL landing scenario (if not, consider using rally points). -::: - ## Technical Summary Fixed-wing vehicles use the _mission landing/rally point_ return type by default. From 8cb1c31f46775b0994f76e1849978fd0d760dc67 Mon Sep 17 00:00:00 2001 From: Hubert <1701213518@sz.pku.edu.cn> Date: Wed, 5 Nov 2025 00:16:38 +0800 Subject: [PATCH 013/139] boards: add new board micoair743-lite (#25777) Authored-by: Minderring <1701213518@sz.edu.pku.cn> Manufacturer supported board. --- .vscode/cmake-variants.yaml | 10 + Makefile | 1 + boards/micoair/h743-lite/bootloader.px4board | 3 + boards/micoair/h743-lite/default.px4board | 108 +++++ .../extras/micoair_h743-lite_bootloader.bin | Bin 0 -> 41032 bytes boards/micoair/h743-lite/firmware.prototype | 13 + .../micoair/h743-lite/init/rc.board_defaults | 28 ++ boards/micoair/h743-lite/init/rc.board_extras | 7 + .../micoair/h743-lite/init/rc.board_sensors | 13 + .../nuttx-config/bootloader/defconfig | 85 ++++ .../h743-lite/nuttx-config/include/board.h | 414 ++++++++++++++++++ .../nuttx-config/include/board_dma_map.h | 36 ++ .../h743-lite/nuttx-config/nsh/defconfig | 244 +++++++++++ .../nuttx-config/scripts/bootloader_script.ld | 213 +++++++++ .../h743-lite/nuttx-config/scripts/script.ld | 228 ++++++++++ boards/micoair/h743-lite/src/CMakeLists.txt | 68 +++ boards/micoair/h743-lite/src/board_config.h | 199 +++++++++ .../micoair/h743-lite/src/bootloader_main.c | 75 ++++ boards/micoair/h743-lite/src/hw_config.h | 135 ++++++ boards/micoair/h743-lite/src/i2c.cpp | 39 ++ boards/micoair/h743-lite/src/init.c | 208 +++++++++ boards/micoair/h743-lite/src/led.c | 114 +++++ boards/micoair/h743-lite/src/sdio.c | 177 ++++++++ boards/micoair/h743-lite/src/spi.cpp | 45 ++ boards/micoair/h743-lite/src/timer_config.cpp | 63 +++ boards/micoair/h743-lite/src/usb.c | 78 ++++ 26 files changed, 2604 insertions(+) create mode 100644 boards/micoair/h743-lite/bootloader.px4board create mode 100644 boards/micoair/h743-lite/default.px4board create mode 100755 boards/micoair/h743-lite/extras/micoair_h743-lite_bootloader.bin create mode 100644 boards/micoair/h743-lite/firmware.prototype create mode 100644 boards/micoair/h743-lite/init/rc.board_defaults create mode 100644 boards/micoair/h743-lite/init/rc.board_extras create mode 100644 boards/micoair/h743-lite/init/rc.board_sensors create mode 100644 boards/micoair/h743-lite/nuttx-config/bootloader/defconfig create mode 100644 boards/micoair/h743-lite/nuttx-config/include/board.h create mode 100644 boards/micoair/h743-lite/nuttx-config/include/board_dma_map.h create mode 100644 boards/micoair/h743-lite/nuttx-config/nsh/defconfig create mode 100644 boards/micoair/h743-lite/nuttx-config/scripts/bootloader_script.ld create mode 100644 boards/micoair/h743-lite/nuttx-config/scripts/script.ld create mode 100644 boards/micoair/h743-lite/src/CMakeLists.txt create mode 100644 boards/micoair/h743-lite/src/board_config.h create mode 100644 boards/micoair/h743-lite/src/bootloader_main.c create mode 100644 boards/micoair/h743-lite/src/hw_config.h create mode 100644 boards/micoair/h743-lite/src/i2c.cpp create mode 100644 boards/micoair/h743-lite/src/init.c create mode 100644 boards/micoair/h743-lite/src/led.c create mode 100644 boards/micoair/h743-lite/src/sdio.c create mode 100644 boards/micoair/h743-lite/src/spi.cpp create mode 100644 boards/micoair/h743-lite/src/timer_config.cpp create mode 100644 boards/micoair/h743-lite/src/usb.c diff --git a/.vscode/cmake-variants.yaml b/.vscode/cmake-variants.yaml index 504c38b2d3..b80cdb73c8 100644 --- a/.vscode/cmake-variants.yaml +++ b/.vscode/cmake-variants.yaml @@ -421,6 +421,16 @@ CONFIG: buildType: MinSizeRel settings: CONFIG: micoair_h743-v2_default + micoair_h743-lite_bootloader: + short: micoair_h743-lite_bootloader + buildType: MinSizeRel + settings: + CONFIG: micoair_h743-lite_bootloader + micoair_h743-lite_default: + short: micoair_h743-lite + buildType: MinSizeRel + settings: + CONFIG: micoair_h743-lite_default modalai_fc-v1_default: short: modalai_fc-v1 buildType: MinSizeRel diff --git a/Makefile b/Makefile index 80e0ee1f64..3639bbdee4 100644 --- a/Makefile +++ b/Makefile @@ -346,6 +346,7 @@ bootloaders_update: \ micoair_h743_bootloader \ micoair_h743-aio_bootloader \ micoair_h743-v2_bootloader \ + micoair_h743-lite_bootloader \ modalai_fc-v2_bootloader \ mro_ctrl-zero-classic_bootloader \ mro_ctrl-zero-h7_bootloader \ diff --git a/boards/micoair/h743-lite/bootloader.px4board b/boards/micoair/h743-lite/bootloader.px4board new file mode 100644 index 0000000000..19b6e662be --- /dev/null +++ b/boards/micoair/h743-lite/bootloader.px4board @@ -0,0 +1,3 @@ +CONFIG_BOARD_TOOLCHAIN="arm-none-eabi" +CONFIG_BOARD_ARCHITECTURE="cortex-m7" +CONFIG_BOARD_ROMFSROOT="" diff --git a/boards/micoair/h743-lite/default.px4board b/boards/micoair/h743-lite/default.px4board new file mode 100644 index 0000000000..68a87e863c --- /dev/null +++ b/boards/micoair/h743-lite/default.px4board @@ -0,0 +1,108 @@ +CONFIG_BOARD_TOOLCHAIN="arm-none-eabi" +CONFIG_BOARD_ARCHITECTURE="cortex-m7" +CONFIG_BOARD_SERIAL_URT6="/dev/ttyS6" +CONFIG_BOARD_SERIAL_GPS1="/dev/ttyS2" +CONFIG_BOARD_SERIAL_GPS2="/dev/ttyS1" +CONFIG_BOARD_SERIAL_TEL1="/dev/ttyS0" +CONFIG_BOARD_SERIAL_TEL2="/dev/ttyS3" +CONFIG_BOARD_SERIAL_TEL3="/dev/ttyS4" +CONFIG_BOARD_SERIAL_TEL4="/dev/ttyS7" +CONFIG_BOARD_SERIAL_RC="/dev/ttyS5" +CONFIG_BOARD_PARAM_FILE="/fs/microsd/params" +CONFIG_DRIVERS_ADC_BOARD_ADC=y +CONFIG_DRIVERS_BAROMETER_GOERTEK_SPA06=y +CONFIG_DRIVERS_CAMERA_CAPTURE=y +CONFIG_DRIVERS_CAMERA_TRIGGER=y +CONFIG_DRIVERS_CDCACM_AUTOSTART=y +CONFIG_COMMON_DIFFERENTIAL_PRESSURE=y +CONFIG_DRIVERS_DIFFERENTIAL_PRESSURE_ASP5033=y +CONFIG_DRIVERS_DIFFERENTIAL_PRESSURE_ETS=y +CONFIG_DRIVERS_DIFFERENTIAL_PRESSURE_MS4515=y +CONFIG_COMMON_DISTANCE_SENSOR=y +CONFIG_DRIVERS_DSHOT=y +CONFIG_DRIVERS_GNSS_SEPTENTRIO=y +CONFIG_DRIVERS_GPS=y +CONFIG_DRIVERS_IMU_INVENSENSE_ICM45686=y +CONFIG_COMMON_MAGNETOMETER=y +CONFIG_COMMON_OPTICAL_FLOW=y +CONFIG_DRIVERS_POWER_MONITOR_INA220=y +CONFIG_DRIVERS_POWER_MONITOR_INA226=y +CONFIG_DRIVERS_POWER_MONITOR_INA228=y +CONFIG_DRIVERS_POWER_MONITOR_INA238=y +CONFIG_DRIVERS_POWER_MONITOR_PM_SELECTOR_AUTERION=y +CONFIG_DRIVERS_POWER_MONITOR_VOXLPM=y +CONFIG_DRIVERS_PPS_CAPTURE=y +CONFIG_DRIVERS_PWM_OUT=y +CONFIG_COMMON_RC=y +CONFIG_DRIVERS_RC_INPUT=y +CONFIG_COMMON_RPM=y +CONFIG_DRIVERS_SMART_BATTERY_BATMON=y +CONFIG_DRIVERS_TAP_ESC=y +CONFIG_COMMON_TELEMETRY=y +CONFIG_DRIVERS_TONE_ALARM=y +CONFIG_COMMON_UWB=y +CONFIG_COMMON_WIND_SENSOR=y +CONFIG_MODULES_AIRSHIP_ATT_CONTROL=y +CONFIG_MODULES_AIRSPEED_SELECTOR=y +CONFIG_MODULES_BATTERY_STATUS=y +CONFIG_MODULES_CAMERA_FEEDBACK=y +CONFIG_MODULES_COMMANDER=y +CONFIG_MODULES_CONTROL_ALLOCATOR=y +CONFIG_MODULES_DATAMAN=y +CONFIG_MODULES_EKF2=y +CONFIG_MODULES_ESC_BATTERY=y +CONFIG_MODULES_EVENTS=y +CONFIG_MODULES_FLIGHT_MODE_MANAGER=y +CONFIG_MODULES_FW_ATT_CONTROL=y +CONFIG_MODULES_FW_AUTOTUNE_ATTITUDE_CONTROL=y +CONFIG_MODULES_FW_POS_CONTROL=y +CONFIG_MODULES_FW_RATE_CONTROL=y +CONFIG_MODULES_GIMBAL=y +CONFIG_MODULES_GYRO_CALIBRATION=y +CONFIG_MODULES_GYRO_FFT=y +CONFIG_MODULES_LAND_DETECTOR=y +CONFIG_MODULES_LANDING_TARGET_ESTIMATOR=y +CONFIG_MODULES_LOAD_MON=y +CONFIG_MODULES_LOCAL_POSITION_ESTIMATOR=y +CONFIG_MODULES_LOGGER=y +CONFIG_MODULES_MAG_BIAS_ESTIMATOR=y +CONFIG_MODULES_MANUAL_CONTROL=y +CONFIG_MODULES_MAVLINK=y +CONFIG_MODULES_MC_ATT_CONTROL=y +CONFIG_MODULES_MC_AUTOTUNE_ATTITUDE_CONTROL=y +CONFIG_MODULES_MC_HOVER_THRUST_ESTIMATOR=y +CONFIG_MODULES_MC_POS_CONTROL=y +CONFIG_MODULES_MC_RATE_CONTROL=y +CONFIG_MODULES_NAVIGATOR=y +CONFIG_MODULES_PAYLOAD_DELIVERER=y +CONFIG_MODULES_RC_UPDATE=y +CONFIG_MODULES_SENSORS=y +CONFIG_MODULES_TEMPERATURE_COMPENSATION=y +CONFIG_MODULES_UXRCE_DDS_CLIENT=y +CONFIG_MODULES_VTOL_ATT_CONTROL=y +CONFIG_SYSTEMCMDS_ACTUATOR_TEST=y +CONFIG_SYSTEMCMDS_BL_UPDATE=y +CONFIG_SYSTEMCMDS_BSONDUMP=y +CONFIG_SYSTEMCMDS_DMESG=y +CONFIG_SYSTEMCMDS_DUMPFILE=y +CONFIG_SYSTEMCMDS_FAILURE=y +CONFIG_SYSTEMCMDS_GPIO=y +CONFIG_SYSTEMCMDS_HARDFAULT_LOG=y +CONFIG_SYSTEMCMDS_I2CDETECT=y +CONFIG_SYSTEMCMDS_NSHTERM=y +CONFIG_SYSTEMCMDS_PARAM=y +CONFIG_SYSTEMCMDS_PERF=y +CONFIG_SYSTEMCMDS_REBOOT=y +CONFIG_SYSTEMCMDS_SD_BENCH=y +CONFIG_SYSTEMCMDS_SD_STRESS=y +CONFIG_SYSTEMCMDS_SERIAL_PASSTHRU=y +CONFIG_SYSTEMCMDS_SERIAL_TEST=y +CONFIG_SYSTEMCMDS_SYSTEM_TIME=y +CONFIG_SYSTEMCMDS_TESTS=y +CONFIG_SYSTEMCMDS_TOP=y +CONFIG_SYSTEMCMDS_TOPIC_LISTENER=y +CONFIG_SYSTEMCMDS_TUNE_CONTROL=y +CONFIG_SYSTEMCMDS_UORB=y +CONFIG_SYSTEMCMDS_USB_CONNECTED=y +CONFIG_SYSTEMCMDS_VER=y +CONFIG_SYSTEMCMDS_WORK_QUEUE=y diff --git a/boards/micoair/h743-lite/extras/micoair_h743-lite_bootloader.bin b/boards/micoair/h743-lite/extras/micoair_h743-lite_bootloader.bin new file mode 100755 index 0000000000000000000000000000000000000000..e9bf775cde0f8803b1ef1dca130071b8a3c8d2cc GIT binary patch literal 41032 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 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ +#ifndef __NUTTX_CONFIG_MICOAIR743_LITE_INCLUDE_BOARD_H +#define __NUTTX_CONFIG_MICOAIR743_LITE_INCLUDE_BOARD_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include "board_dma_map.h" + +#include + +#ifndef __ASSEMBLY__ +# include +#endif + +#include "stm32_rcc.h" +#include "stm32_sdmmc.h" + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +/* Clocking *************************************************************************/ +/* The MicoAir743-Lite board provides the following clock sources: + * + * X1: 8 MHz crystal for HSE + * + * So we have these clock source available within the STM32 + * + * HSI: 64 MHz RC factory-trimmed + * HSE: 8 MHz crystal for HSE + */ + +#define STM32_BOARD_XTAL 8000000ul + +#define STM32_HSI_FREQUENCY 16000000ul +#define STM32_LSI_FREQUENCY 32000 +#define STM32_HSE_FREQUENCY STM32_BOARD_XTAL +#define STM32_LSE_FREQUENCY 32768 + +/* Main PLL Configuration. + * + * PLL source is HSE = 8,000,000 + * + * PLL_VCOx = (STM32_HSE_FREQUENCY / PLLM) * PLLN + * Subject to: + * + * 1 <= PLLM <= 63 + * 4 <= PLLN <= 512 + * 150 MHz <= PLL_VCOL <= 420MHz + * 192 MHz <= PLL_VCOH <= 836MHz + * + * SYSCLK = PLL_VCO / PLLP + * CPUCLK = SYSCLK / D1CPRE + * Subject to + * + * PLLP1 = {2, 4, 6, 8, ..., 128} + * PLLP2,3 = {2, 3, 4, ..., 128} + * CPUCLK <= 480 MHz + */ + +#define STM32_BOARD_USEHSE + +#define STM32_PLLCFG_PLLSRC RCC_PLLCKSELR_PLLSRC_HSE + +/* PLL1, wide 4 - 8 MHz input, enable DIVP, DIVQ, DIVR + * + * PLL1_VCO = (8,000,000 / 1) * 120 = 960 MHz + * + * PLL1P = PLL1_VCO/2 = 960 MHz / 2 = 480 MHz + * PLL1Q = PLL1_VCO/4 = 960 MHz / 4 = 240 MHz + * PLL1R = PLL1_VCO/8 = 960 MHz / 8 = 120 MHz + */ + +#define STM32_PLLCFG_PLL1CFG (RCC_PLLCFGR_PLL1VCOSEL_WIDE | \ + RCC_PLLCFGR_PLL1RGE_4_8_MHZ | \ + RCC_PLLCFGR_DIVP1EN | \ + RCC_PLLCFGR_DIVQ1EN | \ + RCC_PLLCFGR_DIVR1EN) +#define STM32_PLLCFG_PLL1M RCC_PLLCKSELR_DIVM1(1) +#define STM32_PLLCFG_PLL1N RCC_PLL1DIVR_N1(120) +#define STM32_PLLCFG_PLL1P RCC_PLL1DIVR_P1(2) +#define STM32_PLLCFG_PLL1Q RCC_PLL1DIVR_Q1(4) +#define STM32_PLLCFG_PLL1R RCC_PLL1DIVR_R1(8) + +#define STM32_VCO1_FREQUENCY ((STM32_HSE_FREQUENCY / 1) * 120) +#define STM32_PLL1P_FREQUENCY (STM32_VCO1_FREQUENCY / 2) +#define STM32_PLL1Q_FREQUENCY (STM32_VCO1_FREQUENCY / 4) +#define STM32_PLL1R_FREQUENCY (STM32_VCO1_FREQUENCY / 8) + +/* PLL2 */ + +#define STM32_PLLCFG_PLL2CFG (RCC_PLLCFGR_PLL2VCOSEL_WIDE | \ + RCC_PLLCFGR_PLL2RGE_4_8_MHZ | \ + RCC_PLLCFGR_DIVP2EN | \ + RCC_PLLCFGR_DIVQ2EN | \ + RCC_PLLCFGR_DIVR2EN) +#define STM32_PLLCFG_PLL2M RCC_PLLCKSELR_DIVM2(2) +#define STM32_PLLCFG_PLL2N RCC_PLL2DIVR_N2(48) +#define STM32_PLLCFG_PLL2P RCC_PLL2DIVR_P2(2) +#define STM32_PLLCFG_PLL2Q RCC_PLL2DIVR_Q2(2) +#define STM32_PLLCFG_PLL2R RCC_PLL2DIVR_R2(2) + +#define STM32_VCO2_FREQUENCY ((STM32_HSE_FREQUENCY / 2) * 48) +#define STM32_PLL2P_FREQUENCY (STM32_VCO2_FREQUENCY / 2) +#define STM32_PLL2Q_FREQUENCY (STM32_VCO2_FREQUENCY / 2) +#define STM32_PLL2R_FREQUENCY (STM32_VCO2_FREQUENCY / 2) + +/* PLL3 */ + +#define STM32_PLLCFG_PLL3CFG (RCC_PLLCFGR_PLL3VCOSEL_WIDE | \ + RCC_PLLCFGR_PLL3RGE_4_8_MHZ | \ + RCC_PLLCFGR_DIVQ3EN) +#define STM32_PLLCFG_PLL3M RCC_PLLCKSELR_DIVM3(2) +#define STM32_PLLCFG_PLL3N RCC_PLL3DIVR_N3(48) +#define STM32_PLLCFG_PLL3P RCC_PLL3DIVR_P3(2) +#define STM32_PLLCFG_PLL3Q RCC_PLL3DIVR_Q3(4) +#define STM32_PLLCFG_PLL3R RCC_PLL3DIVR_R3(2) + +#define STM32_VCO3_FREQUENCY ((STM32_HSE_FREQUENCY / 2) * 48) +#define STM32_PLL3P_FREQUENCY (STM32_VCO3_FREQUENCY / 2) +#define STM32_PLL3Q_FREQUENCY (STM32_VCO3_FREQUENCY / 4) +#define STM32_PLL3R_FREQUENCY (STM32_VCO3_FREQUENCY / 2) + +/* SYSCLK = PLL1P = 480MHz + * CPUCLK = SYSCLK / 1 = 480 MHz + */ + +#define STM32_RCC_D1CFGR_D1CPRE (RCC_D1CFGR_D1CPRE_SYSCLK) +#define STM32_SYSCLK_FREQUENCY (STM32_PLL1P_FREQUENCY) +#define STM32_CPUCLK_FREQUENCY (STM32_SYSCLK_FREQUENCY / 1) + +/* Configure Clock Assignments */ + +/* AHB clock (HCLK) is SYSCLK/2 (240 MHz max) + * HCLK1 = HCLK2 = HCLK3 = HCLK4 = 240 + */ + +#define STM32_RCC_D1CFGR_HPRE RCC_D1CFGR_HPRE_SYSCLKd2 /* HCLK = SYSCLK / 2 */ +#define STM32_ACLK_FREQUENCY (STM32_CPUCLK_FREQUENCY / 2) /* ACLK in D1, HCLK3 in D1 */ +#define STM32_HCLK_FREQUENCY (STM32_CPUCLK_FREQUENCY / 2) /* HCLK in D2, HCLK4 in D3 */ +#define STM32_BOARD_HCLK STM32_HCLK_FREQUENCY /* same as above, to satisfy compiler */ + +/* APB1 clock (PCLK1) is HCLK/2 (120 MHz) */ + +#define STM32_RCC_D2CFGR_D2PPRE1 RCC_D2CFGR_D2PPRE1_HCLKd2 /* PCLK1 = HCLK / 2 */ +#define STM32_PCLK1_FREQUENCY (STM32_HCLK_FREQUENCY/2) + +/* APB2 clock (PCLK2) is HCLK/2 (120 MHz) */ + +#define STM32_RCC_D2CFGR_D2PPRE2 RCC_D2CFGR_D2PPRE2_HCLKd2 /* PCLK2 = HCLK / 2 */ +#define STM32_PCLK2_FREQUENCY (STM32_HCLK_FREQUENCY/2) + +/* APB3 clock (PCLK3) is HCLK/2 (120 MHz) */ + +#define STM32_RCC_D1CFGR_D1PPRE RCC_D1CFGR_D1PPRE_HCLKd2 /* PCLK3 = HCLK / 2 */ +#define STM32_PCLK3_FREQUENCY (STM32_HCLK_FREQUENCY/2) + +/* APB4 clock (PCLK4) is HCLK/4 (120 MHz) */ + +#define STM32_RCC_D3CFGR_D3PPRE RCC_D3CFGR_D3PPRE_HCLKd2 /* PCLK4 = HCLK / 2 */ +#define STM32_PCLK4_FREQUENCY (STM32_HCLK_FREQUENCY/2) + +/* Timer clock frequencies */ + +/* Timers driven from APB1 will be twice PCLK1 */ + +#define STM32_APB1_TIM2_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM3_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM4_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM5_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM6_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM7_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM12_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM13_CLKIN (2*STM32_PCLK1_FREQUENCY) +#define STM32_APB1_TIM14_CLKIN (2*STM32_PCLK1_FREQUENCY) + +/* Timers driven from APB2 will be twice PCLK2 */ + +#define STM32_APB2_TIM1_CLKIN (2*STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM8_CLKIN (2*STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM15_CLKIN (2*STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM16_CLKIN (2*STM32_PCLK2_FREQUENCY) +#define STM32_APB2_TIM17_CLKIN (2*STM32_PCLK2_FREQUENCY) + +/* Kernel Clock Configuration + * + * Note: look at Table 54 in ST Manual + */ + +/* I2C123 clock source */ + +#define STM32_RCC_D2CCIP2R_I2C123SRC RCC_D2CCIP2R_I2C123SEL_HSI + +/* I2C4 clock source */ + +#define STM32_RCC_D3CCIPR_I2C4SRC RCC_D3CCIPR_I2C4SEL_HSI + +/* SPI123 clock source */ + +#define STM32_RCC_D2CCIP1R_SPI123SRC RCC_D2CCIP1R_SPI123SEL_PLL2 + +/* SPI45 clock source */ + +#define STM32_RCC_D2CCIP1R_SPI45SRC RCC_D2CCIP1R_SPI45SEL_PLL2 + +/* SPI6 clock source */ + +#define STM32_RCC_D3CCIPR_SPI6SRC RCC_D3CCIPR_SPI6SEL_PLL2 + +/* USB 1 and 2 clock source */ + +#define STM32_RCC_D2CCIP2R_USBSRC RCC_D2CCIP2R_USBSEL_PLL3 + +/* ADC 1 2 3 clock source */ + +#define STM32_RCC_D3CCIPR_ADCSEL RCC_D3CCIPR_ADCSEL_PLL2 + +/* FDCAN 1 clock source */ + +#define STM32_RCC_D2CCIP1R_FDCANSEL RCC_D2CCIP1R_FDCANSEL_HSE /* FDCAN 1 2 clock source */ + +#define STM32_FDCANCLK STM32_HSE_FREQUENCY + +/* FLASH wait states + * + * ------------ ---------- ----------- + * Vcore MAX ACLK WAIT STATES + * ------------ ---------- ----------- + * 1.15-1.26 V 70 MHz 0 + * (VOS1 level) 140 MHz 1 + * 210 MHz 2 + * 1.05-1.15 V 55 MHz 0 + * (VOS2 level) 110 MHz 1 + * 165 MHz 2 + * 220 MHz 3 + * 0.95-1.05 V 45 MHz 0 + * (VOS3 level) 90 MHz 1 + * 135 MHz 2 + * 180 MHz 3 + * 225 MHz 4 + * ------------ ---------- ----------- + */ + +#define BOARD_FLASH_WAITSTATES 2 + +/* SDMMC definitions ********************************************************/ + +/* Init 480kHz, freq = PLL1Q/(2*div) div = PLL1Q/(2*freq) */ + +#define STM32_SDMMC_INIT_CLKDIV (300 << STM32_SDMMC_CLKCR_CLKDIV_SHIFT) + +/* 20 MHz Max for now - more reliable on some boards than 25 MHz + * 20 MHz = PLL1Q/(2*div), div = PLL1Q/(2*freq), div = 6 = 240 / 40 + */ + +#if defined(CONFIG_STM32H7_SDMMC_XDMA) || defined(CONFIG_STM32H7_SDMMC_IDMA) +# define STM32_SDMMC_MMCXFR_CLKDIV (6 << STM32_SDMMC_CLKCR_CLKDIV_SHIFT) +#else +# define STM32_SDMMC_MMCXFR_CLKDIV (100 << STM32_SDMMC_CLKCR_CLKDIV_SHIFT) +#endif +#if defined(CONFIG_STM32H7_SDMMC_XDMA) || defined(CONFIG_STM32H7_SDMMC_IDMA) +# define STM32_SDMMC_SDXFR_CLKDIV (6 << STM32_SDMMC_CLKCR_CLKDIV_SHIFT) +#else +# define STM32_SDMMC_SDXFR_CLKDIV (100 << STM32_SDMMC_CLKCR_CLKDIV_SHIFT) +#endif + +#define STM32_SDMMC_CLKCR_EDGE STM32_SDMMC_CLKCR_NEGEDGE + +/* LED definitions ******************************************************************/ +/* The board has two, LED_GREEN a Green LED and LED_BLUE a Blue LED, + * that can be controlled by software. + * + * If CONFIG_ARCH_LEDS is not defined, then the user can control the LEDs in any way. + * The following definitions are used to access individual LEDs. + */ + +/* LED index values for use with board_userled() */ + +#define BOARD_LED1 0 +#define BOARD_LED2 1 +#define BOARD_LED3 2 +#define BOARD_NLEDS 3 + +#define BOARD_LED_RED BOARD_LED1 +#define BOARD_LED_GREEN BOARD_LED2 +#define BOARD_LED_BLUE BOARD_LED3 + +/* LED bits for use with board_userled_all() */ + +#define BOARD_LED1_BIT (1 << BOARD_LED1) +#define BOARD_LED2_BIT (1 << BOARD_LED2) +#define BOARD_LED3_BIT (1 << BOARD_LED3) + +/* If CONFIG_ARCH_LEDS is defined, the usage by the board port is defined in + * include/board.h and src/stm32_leds.c. The LEDs are used to encode OS-related + * events as follows: + * + * + * SYMBOL Meaning LED state + * Red Green Blue + * ---------------------- -------------------------- ------ ------ ----*/ + +#define LED_STARTED 0 /* NuttX has been started OFF OFF OFF */ +#define LED_HEAPALLOCATE 1 /* Heap has been allocated OFF OFF ON */ +#define LED_IRQSENABLED 2 /* Interrupts enabled OFF ON OFF */ +#define LED_STACKCREATED 3 /* Idle stack created OFF ON ON */ +#define LED_INIRQ 4 /* In an interrupt N/C N/C GLOW */ +#define LED_SIGNAL 5 /* In a signal handler N/C GLOW N/C */ +#define LED_ASSERTION 6 /* An assertion failed GLOW N/C GLOW */ +#define LED_PANIC 7 /* The system has crashed Blink OFF N/C */ +#define LED_IDLE 8 /* MCU is is sleep mode ON OFF OFF */ + +/* Thus if the Green LED is statically on, NuttX has successfully booted and + * is, apparently, running normally. If the Red LED is flashing at + * approximately 2Hz, then a fatal error has been detected and the system + * has halted. + */ + +/* Alternate function pin selections ************************************************/ + +#define GPIO_USART1_RX GPIO_USART1_RX_2 /* PA10 */ +#define GPIO_USART1_TX GPIO_USART1_TX_2 /* PA9 */ + +#define GPIO_USART2_RX GPIO_USART2_RX_1 /* PA3 */ +#define GPIO_USART2_TX GPIO_USART2_TX_1 /* PA2 */ + +#define GPIO_USART3_RX GPIO_USART3_RX_3 /* PD9 */ +#define GPIO_USART3_TX GPIO_USART3_TX_3 /* PD8 */ + +#define GPIO_UART4_RX GPIO_UART4_RX_2 /* PA1 */ +#define GPIO_UART4_TX GPIO_UART4_TX_2 /* PA0 */ + +#define GPIO_UART5_RX GPIO_UART5_RX_2 /* PB5 */ +#define GPIO_UART5_TX GPIO_UART5_TX_2 /* PB6 */ + +#define GPIO_USART6_RX GPIO_USART6_RX_1 /* PC7 */ +#define GPIO_USART6_TX GPIO_USART6_TX_1 /* PC6 */ + +#define GPIO_UART7_RX GPIO_UART7_RX_3 /* PE7 */ +#define GPIO_UART7_TX GPIO_UART7_TX_3 /* PE8 */ + +#define GPIO_UART8_RX GPIO_UART8_RX_1 /* PE0 */ +#define GPIO_UART8_TX GPIO_UART8_TX_1 /* PE1 */ + + +/* SPI + * + + */ + +#define ADJ_SLEW_RATE(p) (((p) & ~GPIO_SPEED_MASK) | (GPIO_SPEED_2MHz)) + +#define GPIO_SPI3_MISO GPIO_SPI3_MISO_1 /* PB4 */ +#define GPIO_SPI3_MOSI GPIO_SPI3_MOSI_1 /* PD6 */ +#define GPIO_SPI3_SCK ADJ_SLEW_RATE(GPIO_SPI3_SCK_1) /* PB3 */ + +/* I2C + * + + * + */ + +#define GPIO_I2C1_SCL GPIO_I2C1_SCL_2 /* PB8 */ +#define GPIO_I2C1_SDA GPIO_I2C1_SDA_2 /* PB9 */ + +#define GPIO_I2C1_SCL_GPIO (GPIO_OUTPUT | GPIO_OPENDRAIN | GPIO_SPEED_50MHz | GPIO_OUTPUT_SET | GPIO_PORTB | GPIO_PIN8) +#define GPIO_I2C1_SDA_GPIO (GPIO_OUTPUT | GPIO_OPENDRAIN | GPIO_SPEED_50MHz | GPIO_OUTPUT_SET | GPIO_PORTB | GPIO_PIN9) + +#define GPIO_I2C2_SCL GPIO_I2C2_SCL_1 /* PB10 */ +#define GPIO_I2C2_SDA GPIO_I2C2_SDA_1 /* PB11 */ + +#define GPIO_I2C2_SCL_GPIO (GPIO_OUTPUT | GPIO_OPENDRAIN | GPIO_SPEED_50MHz | GPIO_OUTPUT_SET | GPIO_PORTB | GPIO_PIN10) +#define GPIO_I2C2_SDA_GPIO (GPIO_OUTPUT | GPIO_OPENDRAIN | GPIO_SPEED_50MHz | GPIO_OUTPUT_SET | GPIO_PORTB | GPIO_PIN11) + +# define PROBE_INIT(mask) +# define PROBE(n,s) +# define PROBE_MARK(n) + +#endif /*__NUTTX_CONFIG_MICOAIR743_LITE_INCLUDE_BOARD_H */ diff --git a/boards/micoair/h743-lite/nuttx-config/include/board_dma_map.h b/boards/micoair/h743-lite/nuttx-config/include/board_dma_map.h new file mode 100644 index 0000000000..fd6a97722a --- /dev/null +++ b/boards/micoair/h743-lite/nuttx-config/include/board_dma_map.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * + * Copyright (c) 2021 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 +#define DMAMAP_SPI3_RX DMAMAP_DMA12_SPI3RX_0 +#define DMAMAP_SPI3_TX DMAMAP_DMA12_SPI3TX_0 diff --git a/boards/micoair/h743-lite/nuttx-config/nsh/defconfig b/boards/micoair/h743-lite/nuttx-config/nsh/defconfig new file mode 100644 index 0000000000..c5f981cbd4 --- /dev/null +++ b/boards/micoair/h743-lite/nuttx-config/nsh/defconfig @@ -0,0 +1,244 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_DEV_CONSOLE is not set +# CONFIG_DISABLE_ENVIRON is not set +# CONFIG_DISABLE_PSEUDOFS_OPERATIONS is not set +# CONFIG_DISABLE_PTHREAD is not set +# CONFIG_MMCSD_HAVE_CARDDETECT is not set +# CONFIG_MMCSD_HAVE_WRITEPROTECT is not set +# CONFIG_MMCSD_MMCSUPPORT is not set +# CONFIG_MMCSD_SPI is not set +# CONFIG_NSH_DISABLEBG is not set +# CONFIG_NSH_DISABLESCRIPT is not set +# CONFIG_NSH_DISABLE_CAT is not set +# CONFIG_NSH_DISABLE_CD is not set +# CONFIG_NSH_DISABLE_CP is not set +# CONFIG_NSH_DISABLE_DATE is not set +# CONFIG_NSH_DISABLE_DF is not set +# CONFIG_NSH_DISABLE_ECHO is not set +# CONFIG_NSH_DISABLE_ENV is not set +# CONFIG_NSH_DISABLE_EXEC is not set +# CONFIG_NSH_DISABLE_EXIT is not set +# CONFIG_NSH_DISABLE_EXPORT is not set +# CONFIG_NSH_DISABLE_FREE is not set +# CONFIG_NSH_DISABLE_GET is not set +# CONFIG_NSH_DISABLE_HELP is not set +# CONFIG_NSH_DISABLE_ITEF is not set +# CONFIG_NSH_DISABLE_KILL is not set +# CONFIG_NSH_DISABLE_LOOPS is not set +# CONFIG_NSH_DISABLE_LS is not set +# CONFIG_NSH_DISABLE_MKDIR is not set +# CONFIG_NSH_DISABLE_MKFATFS is not set +# CONFIG_NSH_DISABLE_MOUNT is not set +# CONFIG_NSH_DISABLE_MV is not set +# CONFIG_NSH_DISABLE_PRINTF is not set +# CONFIG_NSH_DISABLE_PS is not set +# CONFIG_NSH_DISABLE_PSSTACKUSAGE is not set +# CONFIG_NSH_DISABLE_PWD is not set +# CONFIG_NSH_DISABLE_RM is not set +# CONFIG_NSH_DISABLE_RMDIR is not set +# CONFIG_NSH_DISABLE_SEMICOLON is not set +# CONFIG_NSH_DISABLE_SET is not set +# CONFIG_NSH_DISABLE_SLEEP is not set +# CONFIG_NSH_DISABLE_SOURCE is not set +# CONFIG_NSH_DISABLE_TEST is not set +# CONFIG_NSH_DISABLE_TIME is not set +# CONFIG_NSH_DISABLE_UMOUNT is not set +# CONFIG_NSH_DISABLE_UNSET is not set +# CONFIG_NSH_DISABLE_USLEEP is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD_CUSTOM=y +CONFIG_ARCH_BOARD_CUSTOM_DIR="../../../../boards/micoair/h743-lite/nuttx-config" +CONFIG_ARCH_BOARD_CUSTOM_DIR_RELPATH=y +CONFIG_ARCH_BOARD_CUSTOM_NAME="px4" +CONFIG_ARCH_CHIP="stm32h7" +CONFIG_ARCH_CHIP_STM32H743VI=y +CONFIG_ARCH_CHIP_STM32H7=y +CONFIG_ARCH_INTERRUPTSTACK=768 +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARMV7M_BASEPRI_WAR=y +CONFIG_ARMV7M_DCACHE=y +CONFIG_ARMV7M_DTCM=y +CONFIG_ARMV7M_ICACHE=y +CONFIG_ARMV7M_MEMCPY=y +CONFIG_ARMV7M_USEBASEPRI=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_ASSERT_RESET_VALUE=0 +CONFIG_BOARD_CRASHDUMP=y +CONFIG_BOARD_LOOPSPERMSEC=95150 +CONFIG_BOARD_RESET_ON_ASSERT=2 +CONFIG_BUILTIN=y +CONFIG_CDCACM=y +CONFIG_CDCACM_IFLOWCONTROL=y +CONFIG_CDCACM_PRODUCTID=0x0036 +CONFIG_CDCACM_PRODUCTSTR="MicoAir743-Lite" +CONFIG_CDCACM_RXBUFSIZE=6000 +CONFIG_CDCACM_TXBUFSIZE=12000 +CONFIG_CDCACM_VENDORID=0x1B8C +CONFIG_CDCACM_VENDORSTR="MicoAir" +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_HARDFAULT_ALERT=y +CONFIG_DEBUG_MEMFAULT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEFAULT_SMALL=y +CONFIG_DEV_FIFO_SIZE=0 +CONFIG_DEV_PIPE_MAXSIZE=1024 +CONFIG_DEV_PIPE_SIZE=70 +CONFIG_EXPERIMENTAL=y +CONFIG_FAT_DMAMEMORY=y +CONFIG_FAT_LCNAMES=y +CONFIG_FAT_LFN=y +CONFIG_FAT_LFN_ALIAS_HASH=y +CONFIG_FDCLONE_STDIO=y +CONFIG_FS_BINFS=y +CONFIG_FS_CROMFS=y +CONFIG_FS_FAT=y +CONFIG_FS_FATTIME=y +CONFIG_FS_PROCFS=y +CONFIG_FS_PROCFS_INCLUDE_PROGMEM=y +CONFIG_FS_PROCFS_MAX_TASKS=64 +CONFIG_FS_PROCFS_REGISTER=y +CONFIG_FS_ROMFS=y +CONFIG_GRAN=y +CONFIG_GRAN_INTR=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_I2C=y +CONFIG_I2C_RESET=y +CONFIG_IDLETHREAD_STACKSIZE=750 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=3194 +CONFIG_IOB_NBUFFERS=24 +CONFIG_IOB_NCHAINS=24 +CONFIG_LIBC_FLOATINGPOINT=y +CONFIG_LIBC_LONG_LONG=y +CONFIG_LIBC_MAX_EXITFUNS=1 +CONFIG_LIBC_STRERROR=y +CONFIG_MEMSET_64BIT=y +CONFIG_MEMSET_OPTSPEED=y +CONFIG_MMCSD=y +CONFIG_MMCSD_SDIO=y +CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE=y +CONFIG_MM_IOB=y +CONFIG_MM_REGIONS=4 +CONFIG_NAME_MAX=40 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_ARGCAT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_CMDPARMS=y +CONFIG_NSH_CROMFSETC=y +CONFIG_NSH_LINELEN=128 +CONFIG_NSH_MAXARGUMENTS=15 +CONFIG_NSH_NESTDEPTH=8 +CONFIG_NSH_QUOTE=y +CONFIG_NSH_ROMFSETC=y +CONFIG_NSH_ROMFSSECTSIZE=128 +CONFIG_NSH_STRERROR=y +CONFIG_NSH_VARS=y +CONFIG_OTG_ID_GPIO_DISABLE=y +CONFIG_PIPES=y +CONFIG_PREALLOC_TIMERS=50 +CONFIG_PRIORITY_INHERITANCE=y +CONFIG_PTHREAD_MUTEX_ROBUST=y +CONFIG_PTHREAD_STACK_MIN=512 +CONFIG_RAM_SIZE=245760 +CONFIG_RAM_START=0x20010000 +CONFIG_RAW_BINARY=y +CONFIG_RTC_DATETIME=y +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_HPWORKPRIORITY=249 +CONFIG_SCHED_HPWORKSTACKSIZE=1280 +CONFIG_SCHED_INSTRUMENTATION=y +CONFIG_SCHED_INSTRUMENTATION_EXTERNAL=y +CONFIG_SCHED_INSTRUMENTATION_SWITCH=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_LPWORKPRIORITY=50 +CONFIG_SCHED_LPWORKSTACKSIZE=1632 +CONFIG_SCHED_WAITPID=y +CONFIG_SDMMC1_SDIO_PULLUP=y +CONFIG_SEM_PREALLOCHOLDERS=32 +CONFIG_SERIAL_TERMIOS=y +CONFIG_SIG_DEFAULT=y +CONFIG_SIG_SIGALRM_ACTION=y +CONFIG_SIG_SIGUSR1_ACTION=y +CONFIG_SIG_SIGUSR2_ACTION=y +CONFIG_SIG_SIGWORK=4 +CONFIG_STACK_COLORATION=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=11 +CONFIG_STDIO_BUFFER_SIZE=256 +CONFIG_STM32H7_ADC1=y +CONFIG_STM32H7_ADC3=y +CONFIG_STM32H7_BBSRAM=y +CONFIG_STM32H7_BBSRAM_FILES=5 +CONFIG_STM32H7_BDMA=y +CONFIG_STM32H7_BKPSRAM=y +CONFIG_STM32H7_DMA1=y +CONFIG_STM32H7_DMA2=y +CONFIG_STM32H7_DMACAPABLE=y +CONFIG_STM32H7_FLASH_OVERRIDE_I=y +CONFIG_STM32H7_I2C1=y +CONFIG_STM32H7_I2C2=y +CONFIG_STM32H7_I2C_DYNTIMEO=y +CONFIG_STM32H7_I2C_DYNTIMEO_STARTSTOP=10 +CONFIG_STM32H7_OTGFS=y +CONFIG_STM32H7_PROGMEM=y +CONFIG_STM32H7_RTC=y +CONFIG_STM32H7_RTC_HSECLOCK=y +CONFIG_STM32H7_RTC_MAGIC_REG=1 +CONFIG_STM32H7_SAVE_CRASHDUMP=y +CONFIG_STM32H7_SDMMC1=y +CONFIG_STM32H7_SERIALBRK_BSDCOMPAT=y +CONFIG_STM32H7_SERIAL_DISABLE_REORDERING=y +CONFIG_STM32H7_SPI3=y +CONFIG_STM32H7_SPI3_DMA=y +CONFIG_STM32H7_SPI3_DMA_BUFFER=2048 +CONFIG_STM32H7_SPI_DMATHRESHOLD=8 +CONFIG_STM32H7_TIM15=y +CONFIG_STM32H7_TIM12=y +CONFIG_STM32H7_TIM1=y +CONFIG_STM32H7_TIM3=y +CONFIG_STM32H7_TIM4=y +CONFIG_STM32H7_TIM8=y +CONFIG_STM32H7_UART4=y +CONFIG_STM32H7_UART5=y +CONFIG_STM32H7_UART7=y +CONFIG_STM32H7_UART8=y +CONFIG_STM32H7_USART1=y +CONFIG_STM32H7_USART2=y +CONFIG_STM32H7_USART3=y +CONFIG_STM32H7_USART6=y +CONFIG_STM32H7_USART_BREAKS=y +CONFIG_STM32H7_USART_INVERT=y +CONFIG_STM32H7_USART_SINGLEWIRE=y +CONFIG_STM32H7_USART_SWAP=y +CONFIG_SYSTEM_CDCACM=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=24 +CONFIG_UART4_RXBUFSIZE=600 +CONFIG_UART4_TXBUFSIZE=800 +CONFIG_UART5_RXBUFSIZE=600 +CONFIG_UART5_TXBUFSIZE=800 +CONFIG_UART7_RXBUFSIZE=600 +CONFIG_UART7_TXBUFSIZE=800 +CONFIG_UART8_RXBUFSIZE=600 +CONFIG_UART8_TXBUFSIZE=800 +CONFIG_USART1_RXBUFSIZE=1200 +CONFIG_USART1_TXBUFSIZE=1500 +CONFIG_USART2_RXBUFSIZE=600 +CONFIG_USART2_TXBUFSIZE=800 +CONFIG_USART3_RXBUFSIZE=600 +CONFIG_USART3_TXBUFSIZE=800 +CONFIG_USART6_BAUD=57600 +CONFIG_USART6_RXBUFSIZE=600 +CONFIG_USART6_TXBUFSIZE=800 +CONFIG_USBDEV=y +CONFIG_USBDEV_BUSPOWERED=y +CONFIG_USBDEV_MAXPOWER=500 +CONFIG_USEC_PER_TICK=1000 +CONFIG_WATCHDOG=y diff --git a/boards/micoair/h743-lite/nuttx-config/scripts/bootloader_script.ld b/boards/micoair/h743-lite/nuttx-config/scripts/bootloader_script.ld new file mode 100644 index 0000000000..fb877cc443 --- /dev/null +++ b/boards/micoair/h743-lite/nuttx-config/scripts/bootloader_script.ld @@ -0,0 +1,213 @@ +/**************************************************************************** + * scripts/script.ld + * + * Copyright (C) 2016, 2019 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* The Durandal-v1 uses an STM32H743II has 2048Kb of main FLASH memory. + * The flash memory is partitioned into a User Flash memory and a System + * Flash memory. Each of these memories has two banks: + * + * 1) User Flash memory: + * + * Bank 1: Start address 0x0800:0000 to 0x080F:FFFF with 8 sectors, 128Kb each + * Bank 2: Start address 0x0810:0000 to 0x081F:FFFF with 8 sectors, 128Kb each + * + * 2) System Flash memory: + * + * Bank 1: Start address 0x1FF0:0000 to 0x1FF1:FFFF with 1 x 128Kb sector + * Bank 1: Start address 0x1FF4:0000 to 0x1FF5:FFFF with 1 x 128Kb sector + * + * 3) User option bytes for user configuration, only in Bank 1. + * + * In the STM32H743II, two different boot spaces can be selected through + * the BOOT pin and the boot base address programmed in the BOOT_ADD0 and + * BOOT_ADD1 option bytes: + * + * 1) BOOT=0: Boot address defined by user option byte BOOT_ADD0[15:0]. + * ST programmed value: Flash memory at 0x0800:0000 + * 2) BOOT=1: Boot address defined by user option byte BOOT_ADD1[15:0]. + * ST programmed value: System bootloader at 0x1FF0:0000 + * + * The Durandal has a Switch on board, the BOOT0 pin is at ground so by default, + * the STM32 will boot to address 0x0800:0000 in FLASH unless the swiutch is + * drepresed, then the boot will be from 0x1FF0:0000 + * + * The STM32H743ZI also has 1024Kb of data SRAM. + * SRAM is split up into several blocks and into three power domains: + * + * 1) TCM SRAMs are dedicated to the Cortex-M7 and are accessible with + * 0 wait states by the Cortex-M7 and by MDMA through AHBS slave bus + * + * 1.1) 128Kb of DTCM-RAM beginning at address 0x2000:0000 + * + * The DTCM-RAM is organized as 2 x 64Kb DTCM-RAMs on 2 x 32 bit + * DTCM ports. The DTCM-RAM could be used for critical real-time + * data, such as interrupt service routines or stack / heap memory. + * Both DTCM-RAMs can be used in parallel (for load/store operations) + * thanks to the Cortex-M7 dual issue capability. + * + * 1.2) 64Kb of ITCM-RAM beginning at address 0x0000:0000 + * + * This RAM is connected to ITCM 64-bit interface designed for + * execution of critical real-times routines by the CPU. + * + * 2) AXI SRAM (D1 domain) accessible by all system masters except BDMA + * through D1 domain AXI bus matrix + * + * 2.1) 512Kb of SRAM beginning at address 0x2400:0000 + * + * 3) AHB SRAM (D2 domain) accessible by all system masters except BDMA + * through D2 domain AHB bus matrix + * + * 3.1) 128Kb of SRAM1 beginning at address 0x3000:0000 + * 3.2) 128Kb of SRAM2 beginning at address 0x3002:0000 + * 3.3) 32Kb of SRAM3 beginning at address 0x3004:0000 + * + * SRAM1 - SRAM3 are one contiguous block: 288Kb at address 0x3000:0000 + * + * 4) AHB SRAM (D3 domain) accessible by most of system masters + * through D3 domain AHB bus matrix + * + * 4.1) 64Kb of SRAM4 beginning at address 0x3800:0000 + * 4.1) 4Kb of backup RAM beginning at address 0x3880:0000 + * + * When booting from FLASH, FLASH memory is aliased to address 0x0000:0000 + * where the code expects to begin execution by jumping to the entry point in + * the 0x0800:0000 address range. + */ + +MEMORY +{ + itcm (rwx) : ORIGIN = 0x00000000, LENGTH = 64K + flash (rx) : ORIGIN = 0x08000000, LENGTH = 2048K + dtcm1 (rwx) : ORIGIN = 0x20000000, LENGTH = 64K + dtcm2 (rwx) : ORIGIN = 0x20010000, LENGTH = 64K + sram (rwx) : ORIGIN = 0x24000000, LENGTH = 512K + sram1 (rwx) : ORIGIN = 0x30000000, LENGTH = 128K + sram2 (rwx) : ORIGIN = 0x30020000, LENGTH = 128K + sram3 (rwx) : ORIGIN = 0x30040000, LENGTH = 32K + sram4 (rwx) : ORIGIN = 0x38000000, LENGTH = 64K + bbram (rwx) : ORIGIN = 0x38800000, LENGTH = 4K +} + +OUTPUT_ARCH(arm) +EXTERN(_vectors) +ENTRY(_stext) + +/* + * Ensure that abort() is present in the final object. The exception handling + * code pulled in by libgcc.a requires it (and that code cannot be easily avoided). + */ +EXTERN(abort) +EXTERN(_bootdelay_signature) + +SECTIONS +{ + .text : { + _stext = ABSOLUTE(.); + *(.vectors) + . = ALIGN(32); + /* + This signature provides the bootloader with a way to delay booting + */ + _bootdelay_signature = ABSOLUTE(.); + FILL(0xffecc2925d7d05c5) + . += 8; + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.rodata .rodata.*) + *(.gnu.linkonce.t.*) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + _etext = ABSOLUTE(.); + + } > flash + + /* + * Init functions (static constructors and the like) + */ + .init_section : { + _sinit = ABSOLUTE(.); + KEEP(*(.init_array .init_array.*)) + _einit = ABSOLUTE(.); + } > flash + + + .ARM.extab : { + *(.ARM.extab*) + } > flash + + __exidx_start = ABSOLUTE(.); + .ARM.exidx : { + *(.ARM.exidx*) + } > flash + __exidx_end = ABSOLUTE(.); + + _eronly = ABSOLUTE(.); + + .data : { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + _edata = ABSOLUTE(.); + } > sram AT > flash + + .bss : { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = ABSOLUTE(.); + } > sram + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/boards/micoair/h743-lite/nuttx-config/scripts/script.ld b/boards/micoair/h743-lite/nuttx-config/scripts/script.ld new file mode 100644 index 0000000000..85f4990724 --- /dev/null +++ b/boards/micoair/h743-lite/nuttx-config/scripts/script.ld @@ -0,0 +1,228 @@ +/**************************************************************************** + * scripts/script.ld + * + * Copyright (C) 2020 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* The board uses an STM32H743II and has 2048Kb of main FLASH memory. + * The flash memory is partitioned into a User Flash memory and a System + * Flash memory. Each of these memories has two banks: + * + * 1) User Flash memory: + * + * Bank 1: Start address 0x0800:0000 to 0x080F:FFFF with 8 sectors, 128Kb each + * Bank 2: Start address 0x0810:0000 to 0x081F:FFFF with 8 sectors, 128Kb each + * + * 2) System Flash memory: + * + * Bank 1: Start address 0x1FF0:0000 to 0x1FF1:FFFF with 1 x 128Kb sector + * Bank 1: Start address 0x1FF4:0000 to 0x1FF5:FFFF with 1 x 128Kb sector + * + * 3) User option bytes for user configuration, only in Bank 1. + * + * In the STM32H743II, two different boot spaces can be selected through + * the BOOT pin and the boot base address programmed in the BOOT_ADD0 and + * BOOT_ADD1 option bytes: + * + * 1) BOOT=0: Boot address defined by user option byte BOOT_ADD0[15:0]. + * ST programmed value: Flash memory at 0x0800:0000 + * 2) BOOT=1: Boot address defined by user option byte BOOT_ADD1[15:0]. + * ST programmed value: System bootloader at 0x1FF0:0000 + * + * There's a switch on board, the BOOT0 pin is at ground so by default, + * the STM32 will boot to address 0x0800:0000 in FLASH unless the switch is + * drepresed, then the boot will be from 0x1FF0:0000 + * + * The STM32H743ZI also has 1024Kb of data SRAM. + * SRAM is split up into several blocks and into three power domains: + * + * 1) TCM SRAMs are dedicated to the Cortex-M7 and are accessible with + * 0 wait states by the Cortex-M7 and by MDMA through AHBS slave bus + * + * 1.1) 128Kb of DTCM-RAM beginning at address 0x2000:0000 + * + * The DTCM-RAM is organized as 2 x 64Kb DTCM-RAMs on 2 x 32 bit + * DTCM ports. The DTCM-RAM could be used for critical real-time + * data, such as interrupt service routines or stack / heap memory. + * Both DTCM-RAMs can be used in parallel (for load/store operations) + * thanks to the Cortex-M7 dual issue capability. + * + * 1.2) 64Kb of ITCM-RAM beginning at address 0x0000:0000 + * + * This RAM is connected to ITCM 64-bit interface designed for + * execution of critical real-times routines by the CPU. + * + * 2) AXI SRAM (D1 domain) accessible by all system masters except BDMA + * through D1 domain AXI bus matrix + * + * 2.1) 512Kb of SRAM beginning at address 0x2400:0000 + * + * 3) AHB SRAM (D2 domain) accessible by all system masters except BDMA + * through D2 domain AHB bus matrix + * + * 3.1) 128Kb of SRAM1 beginning at address 0x3000:0000 + * 3.2) 128Kb of SRAM2 beginning at address 0x3002:0000 + * 3.3) 32Kb of SRAM3 beginning at address 0x3004:0000 + * + * SRAM1 - SRAM3 are one contiguous block: 288Kb at address 0x3000:0000 + * + * 4) AHB SRAM (D3 domain) accessible by most of system masters + * through D3 domain AHB bus matrix + * + * 4.1) 64Kb of SRAM4 beginning at address 0x3800:0000 + * 4.1) 4Kb of backup RAM beginning at address 0x3880:0000 + * + * When booting from FLASH, FLASH memory is aliased to address 0x0000:0000 + * where the code expects to begin execution by jumping to the entry point in + * the 0x0800:0000 address range. + */ + +MEMORY +{ + ITCM_RAM (rwx) : ORIGIN = 0x00000000, LENGTH = 64K + FLASH (rx) : ORIGIN = 0x08020000, LENGTH = 1920K + + DTCM1_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K + DTCM2_RAM (rwx) : ORIGIN = 0x20010000, LENGTH = 64K + AXI_SRAM (rwx) : ORIGIN = 0x24000000, LENGTH = 512K /* D1 domain AXI bus */ + SRAM1 (rwx) : ORIGIN = 0x30000000, LENGTH = 128K /* D2 domain AHB bus */ + SRAM2 (rwx) : ORIGIN = 0x30020000, LENGTH = 128K /* D2 domain AHB bus */ + SRAM3 (rwx) : ORIGIN = 0x30040000, LENGTH = 32K /* D2 domain AHB bus */ + SRAM4 (rwx) : ORIGIN = 0x38000000, LENGTH = 64K /* D3 domain */ + BKPRAM (rwx) : ORIGIN = 0x38800000, LENGTH = 4K +} + +OUTPUT_ARCH(arm) +EXTERN(_vectors) +ENTRY(_stext) + +/* + * Ensure that abort() is present in the final object. The exception handling + * code pulled in by libgcc.a requires it (and that code cannot be easily avoided). + */ +EXTERN(abort) +EXTERN(_bootdelay_signature) + +SECTIONS +{ + .text : { + _stext = ABSOLUTE(.); + *(.vectors) + . = ALIGN(32); + /* + This signature provides the bootloader with a way to delay booting + */ + _bootdelay_signature = ABSOLUTE(.); + FILL(0xffecc2925d7d05c5) + . += 8; + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.rodata .rodata.*) + *(.gnu.linkonce.t.*) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + _etext = ABSOLUTE(.); + + } > FLASH + + /* + * Init functions (static constructors and the like) + */ + .init_section : { + _sinit = ABSOLUTE(.); + KEEP(*(.init_array .init_array.*)) + _einit = ABSOLUTE(.); + } > FLASH + + + .ARM.extab : { + *(.ARM.extab*) + } > FLASH + + __exidx_start = ABSOLUTE(.); + .ARM.exidx : { + *(.ARM.exidx*) + } > FLASH + __exidx_end = ABSOLUTE(.); + + _eronly = ABSOLUTE(.); + + .data : { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + _edata = ABSOLUTE(.); + + /* Pad out last section as the STM32H7 Flash write size is 256 bits. 32 bytes */ + . = ALIGN(16); + FILL(0xffff) + . += 16; + } > AXI_SRAM AT > FLASH = 0xffff + + .bss : { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = ABSOLUTE(.); + } > AXI_SRAM + + /* Emit the the D3 power domain section for locating BDMA data */ + + .sram4_reserve (NOLOAD) : + { + *(.sram4) + . = ALIGN(4); + _sram4_heap_start = ABSOLUTE(.); + } > SRAM4 + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/boards/micoair/h743-lite/src/CMakeLists.txt b/boards/micoair/h743-lite/src/CMakeLists.txt new file mode 100644 index 0000000000..c47215375d --- /dev/null +++ b/boards/micoair/h743-lite/src/CMakeLists.txt @@ -0,0 +1,68 @@ +############################################################################ +# +# Copyright (c) 2021 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. +# +############################################################################ +if("${PX4_BOARD_LABEL}" STREQUAL "bootloader") + add_library(drivers_board + bootloader_main.c + usb.c + ) + target_link_libraries(drivers_board + PRIVATE + nuttx_arch + nuttx_drivers + bootloader + ) + target_include_directories(drivers_board PRIVATE ${PX4_SOURCE_DIR}/platforms/nuttx/src/bootloader/common) + +else() + add_library(drivers_board + i2c.cpp + init.c + led.c + sdio.c + spi.cpp + timer_config.cpp + usb.c + ) + add_dependencies(drivers_board arch_board_hw_info) + + target_link_libraries(drivers_board + PRIVATE + arch_io_pins + arch_spi + arch_board_hw_info + drivers__led + nuttx_arch + nuttx_drivers + px4_layer + ) +endif() diff --git a/boards/micoair/h743-lite/src/board_config.h b/boards/micoair/h743-lite/src/board_config.h new file mode 100644 index 0000000000..2eef26d59b --- /dev/null +++ b/boards/micoair/h743-lite/src/board_config.h @@ -0,0 +1,199 @@ +/**************************************************************************** + * + * Copyright (c) 2021 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 board_config.h + * + * Board internal definitions + */ + +#pragma once + +/**************************************************************************************************** + * Included Files + ****************************************************************************************************/ + +#include +#include +#include + +#include + +/**************************************************************************************************** + * Definitions + ****************************************************************************************************/ + + + +/* LEDs are driven with push open drain to support Anode to 5V or 3.3V */ + +# define GPIO_nLED_RED /* PE3 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN3) +# define GPIO_nLED_GREEN /* PE2 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN2) +# define GPIO_nLED_BLUE /* PE4 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN4) + +# define BOARD_HAS_CONTROL_STATUS_LEDS 1 +# define BOARD_OVERLOAD_LED LED_RED +# define BOARD_ARMED_STATE_LED LED_BLUE + + +/* + * ADC channels + * + * These are the channel numbers of the ADCs of the microcontroller that + * can be used by the Px4 Firmware in the adc driver + */ + +/* ADC defines to be used in sensors.cpp to read from a particular channel */ +#define SYSTEM_ADC_BASE STM32_ADC1_BASE +#define ADC1_CH(n) (n) + +/* Define GPIO pins used as ADC N.B. Channel numbers must match below */ +#define PX4_ADC_GPIO \ + /* PC0 */ GPIO_ADC123_INP10, \ + /* PC1 */ GPIO_ADC123_INP11 + + +/* Define Channel numbers must match above GPIO pin IN(n)*/ +#define ADC_BATTERY_VOLTAGE_CHANNEL /* PC0 */ ADC1_CH(10) +#define ADC_BATTERY_CURRENT_CHANNEL /* PC1 */ ADC1_CH(11) + + +#define ADC_CHANNELS \ + ((1 << ADC_BATTERY_VOLTAGE_CHANNEL) | \ + (1 << ADC_BATTERY_CURRENT_CHANNEL)) + + +/* Define Battery 1 Voltage Divider and A per V + */ + +// #define BOARD_BATTERY1_V_DIV (11.0f) /* measured with the provided PM board */ +// #define BOARD_BATTERY1_A_PER_V (40.0f) +// #define BOARD_BATTERY2_V_DIV (11.0f) /* measured with the provided PM board */ + + +/* PWM + */ +#define DIRECT_PWM_OUTPUT_CHANNELS 14 +#define DIRECT_INPUT_TIMER_CHANNELS 14 + +#define BOARD_HAS_PWM DIRECT_PWM_OUTPUT_CHANNELS + +#define GPIO_TONE_ALARM_IDLE /* PD15 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_CLEAR|GPIO_PORTD|GPIO_PIN15) +#define GPIO_TONE_ALARM_GPIO /* PD15 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_SET|GPIO_PORTD|GPIO_PIN15) + +/* USB OTG FS + * + * PA8 OTG_FS_VBUS VBUS sensing + */ + +#define GPIO_OTGFS_VBUS /* PA8 */ (GPIO_INPUT|GPIO_PULLDOWN|GPIO_SPEED_100MHz|GPIO_PORTA|GPIO_PIN8) + + +/* High-resolution timer */ +#define HRT_TIMER 8 /* use timer8 for the HRT */ +#define HRT_TIMER_CHANNEL 3 /* use capture/compare channel 3 */ + + +/* RC Serial port */ +#define RC_SERIAL_PORT "/dev/ttyS5" +#define BOARD_SUPPORTS_RC_SERIAL_PORT_OUTPUT + +//#define GPIO_I2C2_DRDY1_SPA06 /* PD0 */ (GPIO_INPUT|GPIO_FLOAT|GPIO_EXTI|GPIO_PORTD|GPIO_PIN0) + + +/* SD Card */ +#define SDIO_SLOTNO 0 /* Only one slot */ +#define SDIO_MINOR 0 + +/* This board provides a DMA pool and APIs */ +#define BOARD_DMA_ALLOC_POOL_SIZE 5120 + +/* This board provides the board_on_reset interface */ +#define BOARD_HAS_ON_RESET 1 + +#define PX4_GPIO_INIT_LIST { \ + PX4_ADC_GPIO, \ + GPIO_TONE_ALARM_IDLE, \ + } + +#define BOARD_ENABLE_CONSOLE_BUFFER + + +#define BOARD_NUM_IO_TIMERS 6 + + +__BEGIN_DECLS + +/**************************************************************************************************** + * Public Types + ****************************************************************************************************/ + +/**************************************************************************************************** + * Public data + ****************************************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************************************** + * Public Functions + ****************************************************************************************************/ + +/**************************************************************************** + * Name: stm32_sdio_initialize + * + * Description: + * Initialize SDIO-based MMC/SD card support + * + ****************************************************************************/ + +int stm32_sdio_initialize(void); + +/**************************************************************************************************** + * Name: stm32_spiinitialize + * + * Description: + * Called to configure SPI chip select GPIO pins for the board. + * + ****************************************************************************************************/ + +extern void stm32_spiinitialize(void); + +extern void stm32_usbinitialize(void); + +extern void board_peripheral_reset(int ms); + +#include + +#endif /* __ASSEMBLY__ */ + +__END_DECLS diff --git a/boards/micoair/h743-lite/src/bootloader_main.c b/boards/micoair/h743-lite/src/bootloader_main.c new file mode 100644 index 0000000000..5670308a29 --- /dev/null +++ b/boards/micoair/h743-lite/src/bootloader_main.c @@ -0,0 +1,75 @@ +/**************************************************************************** + * + * Copyright (c) 2021 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 bootloader_main.c + * + * FMU-specific early startup code for bootloader +*/ + +#include "board_config.h" +#include "bl.h" + +#include +#include +#include +#include +#include +#include "arm_internal.h" +#include + +extern int sercon_main(int c, char **argv); + +__EXPORT void board_on_reset(int status) {} + +__EXPORT void stm32_boardinitialize(void) +{ + /* configure USB interfaces */ + stm32_usbinitialize(); +} + +__EXPORT int board_app_initialize(uintptr_t arg) +{ + return 0; +} + +void board_late_initialize(void) +{ + sercon_main(0, NULL); +} + +extern void sys_tick_handler(void); +void board_timerhook(void) +{ + sys_tick_handler(); +} diff --git a/boards/micoair/h743-lite/src/hw_config.h b/boards/micoair/h743-lite/src/hw_config.h new file mode 100644 index 0000000000..ac210d78d4 --- /dev/null +++ b/boards/micoair/h743-lite/src/hw_config.h @@ -0,0 +1,135 @@ +/**************************************************************************** + * + * Copyright (C) 2021 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 + +/**************************************************************************** + * 10-8--2016: + * To simplify the ripple effect on the tools, we will be using + * /dev/serial/by-id/PX4 to locate PX4 devices. Therefore + * moving forward all Bootloaders must contain the prefix "PX4 BL " + * in the USBDEVICESTRING + * This Change will be made in an upcoming BL release + ****************************************************************************/ +/* + * Define usage to configure a bootloader + * + * + * Constant example Usage + * APP_LOAD_ADDRESS 0x08004000 - The address in Linker Script, where the app fw is org-ed + * BOOTLOADER_DELAY 5000 - Ms to wait while under USB pwr or bootloader request + * BOARD_FMUV2 + * INTERFACE_USB 1 - (Optional) Scan and use the USB interface for bootloading + * INTERFACE_USART 1 - (Optional) Scan and use the Serial interface for bootloading + * USBDEVICESTRING "PX4 BL FMU v2.x" - USB id string + * USBPRODUCTID 0x0011 - PID Should match defconfig + * BOOT_DELAY_ADDRESS 0x000001a0 - (Optional) From the linker script from Linker Script to get a custom + * delay provided by an APP FW + * BOARD_TYPE 9 - Must match .prototype boad_id + * _FLASH_KBYTES (*(uint16_t *)0x1fff7a22) - Run time flash size detection + * BOARD_FLASH_SECTORS ((_FLASH_KBYTES == 0x400) ? 11 : 23) - Run time determine the physical last sector + * BOARD_FLASH_SECTORS 11 - Hard coded zero based last sector + * BOARD_FLASH_SIZE (_FLASH_KBYTES*1024)- Total Flash size of device, determined at run time. + * (1024 * 1024) - Hard coded Total Flash of device - The bootloader and app reserved will be deducted + * programmatically + * + * BOARD_FIRST_FLASH_SECTOR_TO_ERASE 2 - Optional sectors index in the flash_sectors table (F4 only), to begin erasing. + * This is to allow sectors to be reserved for app fw usage. That will NOT be erased + * during a FW upgrade. + * The default is 0, and selects the first sector to be erased, as the 0th entry in the + * flash_sectors table. Which is the second physical sector of FLASH in the device. + * The first physical sector of FLASH is used by the bootloader, and is not defined + * in the table. + * + * APP_RESERVATION_SIZE (BOARD_FIRST_FLASH_SECTOR_TO_ERASE * 16 * 1024) - Number of bytes reserved by the APP FW. This number plus + * BOOTLOADER_RESERVATION_SIZE will be deducted from + * BOARD_FLASH_SIZE to determine the size of the App FW + * and hence the address space of FLASH to erase and program. + * USBMFGSTRING "PX4 AP" - Optional USB MFG string (default is '3D Robotics' if not defined.) + * SERIAL_BREAK_DETECT_DISABLED - Optional prevent break selection on Serial port from entering or staying in BL + * + * * Other defines are somewhat self explanatory. + */ + +/* Boot device selection list*/ +#define USB0_DEV 0x01 +#define SERIAL0_DEV 0x02 +#define SERIAL1_DEV 0x04 + +#define APP_LOAD_ADDRESS 0x08020000 +#define BOOTLOADER_DELAY 5000 +#define INTERFACE_USB 1 +#define INTERFACE_USB_CONFIG "/dev/ttyACM0" +#define BOARD_VBUS MK_GPIO_INPUT(GPIO_OTGFS_VBUS) + +//#define USE_VBUS_PULL_DOWN +#define INTERFACE_USART 1 +#define INTERFACE_USART_CONFIG "/dev/ttyS0,115200" +#define BOOT_DELAY_ADDRESS 0x000001a0 +#define BOARD_TYPE 1202 +#define _FLASH_KBYTES (*(uint32_t *)0x1FF1E880) +#define BOARD_FLASH_SECTORS (15) +#define BOARD_FLASH_SIZE (_FLASH_KBYTES * 1024) + +#define OSC_FREQ 8 + +#define BOARD_PIN_LED_ACTIVITY GPIO_nLED_BLUE // BLUE +#define BOARD_PIN_LED_BOOTLOADER GPIO_nLED_GREEN // GREEN +#define BOARD_LED_ON 0 +#define BOARD_LED_OFF 1 + +#define SERIAL_BREAK_DETECT_DISABLED 1 + +#if !defined(ARCH_SN_MAX_LENGTH) +# define ARCH_SN_MAX_LENGTH 12 +#endif + +#if !defined(APP_RESERVATION_SIZE) +# define APP_RESERVATION_SIZE 0 +#endif + +#if !defined(BOARD_FIRST_FLASH_SECTOR_TO_ERASE) +# define BOARD_FIRST_FLASH_SECTOR_TO_ERASE 1 +#endif + +#if !defined(USB_DATA_ALIGN) +# define USB_DATA_ALIGN +#endif + +#ifndef BOOT_DEVICES_SELECTION +# define BOOT_DEVICES_SELECTION USB0_DEV|SERIAL0_DEV|SERIAL1_DEV +#endif + +#ifndef BOOT_DEVICES_FILTER_ONUSB +# define BOOT_DEVICES_FILTER_ONUSB USB0_DEV|SERIAL0_DEV|SERIAL1_DEV +#endif diff --git a/boards/micoair/h743-lite/src/i2c.cpp b/boards/micoair/h743-lite/src/i2c.cpp new file mode 100644 index 0000000000..bea7532cc3 --- /dev/null +++ b/boards/micoair/h743-lite/src/i2c.cpp @@ -0,0 +1,39 @@ +/**************************************************************************** + * + * Copyright (C) 2021 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 + +constexpr px4_i2c_bus_t px4_i2c_buses[I2C_BUS_MAX_BUS_ITEMS] = { + initI2CBusExternal(1), + initI2CBusExternal(2), +}; diff --git a/boards/micoair/h743-lite/src/init.c b/boards/micoair/h743-lite/src/init.c new file mode 100644 index 0000000000..c0e1f9776c --- /dev/null +++ b/boards/micoair/h743-lite/src/init.c @@ -0,0 +1,208 @@ +/**************************************************************************** + * + * Copyright (c) 2021 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 init.c + * + * FMU-specific early startup code. This file implements the + * board_app_initialize() function that is called early by nsh during startup. + * + * Code here is run before the rcS script is invoked; it should start required + * subsystems and perform board-specific initialisation. + */ + +#include "board_config.h" + +#include + +#include +#include +#include +#include +#include +#include "arm_internal.h" + +#include +#include +#include +#include +#include +#include +#include + +# if defined(FLASH_BASED_PARAMS) +# include +#endif + +__BEGIN_DECLS +extern void led_init(void); +extern void led_on(int led); +extern void led_off(int led); +__END_DECLS + +/************************************************************************************ + * Name: board_peripheral_reset + * + * Description: + * + ************************************************************************************/ +__EXPORT void board_peripheral_reset(int ms) +{ + UNUSED(ms); +} + +/************************************************************************************ + * Name: board_on_reset + * + * Description: + * Optionally provided function called on entry to board_system_reset + * It should perform any house keeping prior to the rest. + * + * status - 1 if resetting to boot loader + * 0 if just resetting + * + ************************************************************************************/ +__EXPORT void board_on_reset(int status) +{ + for (int i = 0; i < DIRECT_PWM_OUTPUT_CHANNELS; ++i) { + px4_arch_configgpio(PX4_MAKE_GPIO_INPUT(io_timer_channel_get_as_pwm_input(i))); + } + + /* + * On resets invoked from system (not boot) ensure we establish a low + * output state on PWM pins to disarm the ESC and prevent the reset from potentially + * spinning up the motors. + */ + if (status >= 0) { + up_mdelay(100); + } +} + +/************************************************************************************ + * Name: stm32_boardinitialize + * + * Description: + * All STM32 architectures must provide the following entry point. This entry point + * is called early in the initialization -- after all memory has been configured + * and mapped but before any devices have been initialized. + * + ************************************************************************************/ +__EXPORT void stm32_boardinitialize(void) +{ + /* Reset PWM first thing */ + board_on_reset(-1); + + /* configure LEDs */ + board_autoled_initialize(); + + /* configure pins */ + const uint32_t gpio[] = PX4_GPIO_INIT_LIST; + px4_gpio_init(gpio, arraySize(gpio)); + + /* configure SPI interfaces */ + stm32_spiinitialize(); + + /* configure USB interfaces */ + stm32_usbinitialize(); + +} + +/**************************************************************************** + * Name: board_app_initialize + * + * Description: + * Perform application specific initialization. This function is never + * called directly from application code, but only indirectly via the + * (non-standard) boardctl() interface using the command BOARDIOC_INIT. + * + * Input Parameters: + * arg - The boardctl() argument is passed to the board_app_initialize() + * implementation without modification. The argument has no + * meaning to NuttX; + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure to indicate the nature of the failure. + * + ****************************************************************************/ +__EXPORT int board_app_initialize(uintptr_t arg) +{ + /* Need hrt running before using the ADC */ + px4_platform_init(); + + /* configure the DMA allocator */ + if (board_dma_alloc_init() < 0) { + syslog(LOG_ERR, "[boot] DMA alloc FAILED\n"); + } + + /* initial LED state */ + drv_led_start(); + led_off(LED_RED); + led_off(LED_BLUE); + + if (board_hardfault_init(2, true) != 0) { + led_on(LED_BLUE); + } + +#ifdef CONFIG_MMCSD + int ret = stm32_sdio_initialize(); + + if (ret != OK) { + led_on(LED_BLUE); + return ret; + } + +#endif + +// TODO:internal flash store parameters +#if defined(FLASH_BASED_PARAMS) + static sector_descriptor_t params_sector_map[] = { + {15, 128 * 1024, 0x081E0000}, + {0, 0, 0}, + }; + + /* Initialize the flashfs layer to use heap allocated memory */ + int result = parameter_flashfs_init(params_sector_map, NULL, 0); + + if (result != OK) { + syslog(LOG_ERR, "[boot] FAILED to init params in FLASH %d\n", result); + led_on(LED_RED); + } + +#endif + + /* Configure the HW based on the manifest */ + px4_platform_configure(); + + return OK; +} diff --git a/boards/micoair/h743-lite/src/led.c b/boards/micoair/h743-lite/src/led.c new file mode 100644 index 0000000000..d7794392db --- /dev/null +++ b/boards/micoair/h743-lite/src/led.c @@ -0,0 +1,114 @@ +/**************************************************************************** + * + * Copyright (c) 2021 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 led.c + * + * LED backend. + */ + +#include + +#include + +#include "chip.h" +#include "stm32_gpio.h" +#include "board_config.h" + +#include +#include + +/* + * Ideally we'd be able to get these from arm_internal.h, + * but since we want to be able to disable the NuttX use + * of leds for system indication at will and there is no + * separate switch, we need to build independent of the + * CONFIG_ARCH_LEDS configuration switch. + */ +__BEGIN_DECLS +extern void led_init(void); +extern void led_on(int led); +extern void led_off(int led); +extern void led_toggle(int led); +__END_DECLS + +# define xlat(p) (p) +static uint32_t g_ledmap[] = { + GPIO_nLED_GREEN, // Indexed by BOARD_LED_GREEN + GPIO_nLED_BLUE, // Indexed by BOARD_LED_BLUE + GPIO_nLED_RED, // Indexed by BOARD_LED_RED +}; + +__EXPORT void led_init(void) +{ + /* Configure LED GPIOs for output */ + for (size_t l = 0; l < (sizeof(g_ledmap) / sizeof(g_ledmap[0])); l++) { + if (g_ledmap[l] != 0) { + stm32_configgpio(g_ledmap[l]); + } + } +} + +static void phy_set_led(int led, bool state) +{ + /* Drive Low to switch on */ + if (g_ledmap[led] != 0) { + stm32_gpiowrite(g_ledmap[led], !state); + } +} + +static bool phy_get_led(int led) +{ + /* If Low it is on */ + if (g_ledmap[led] != 0) { + return !stm32_gpioread(g_ledmap[led]); + } + + return false; +} + + +__EXPORT void led_on(int led) +{ + phy_set_led(xlat(led), true); +} + +__EXPORT void led_off(int led) +{ + phy_set_led(xlat(led), false); +} + +__EXPORT void led_toggle(int led) +{ + phy_set_led(xlat(led), !phy_get_led(xlat(led))); +} diff --git a/boards/micoair/h743-lite/src/sdio.c b/boards/micoair/h743-lite/src/sdio.c new file mode 100644 index 0000000000..869d757756 --- /dev/null +++ b/boards/micoair/h743-lite/src/sdio.c @@ -0,0 +1,177 @@ +/**************************************************************************** + * + * Copyright (C) 2014, 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "chip.h" +#include "board_config.h" +#include "stm32_gpio.h" +#include "stm32_sdmmc.h" + +#ifdef CONFIG_MMCSD + + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Card detections requires card support and a card detection GPIO */ + +#define HAVE_NCD 1 +#if !defined(GPIO_SDMMC1_NCD) +# undef HAVE_NCD +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static FAR struct sdio_dev_s *sdio_dev; +#ifdef HAVE_NCD +static bool g_sd_inserted = 0xff; /* Impossible value */ +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_ncd_interrupt + * + * Description: + * Card detect interrupt handler. + * + ****************************************************************************/ + +#ifdef HAVE_NCD +static int stm32_ncd_interrupt(int irq, FAR void *context) +{ + bool present; + + present = !stm32_gpioread(GPIO_SDMMC1_NCD); + + if (sdio_dev && present != g_sd_inserted) { + sdio_mediachange(sdio_dev, present); + g_sd_inserted = present; + } + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_sdio_initialize + * + * Description: + * Initialize SDIO-based MMC/SD card support + * + ****************************************************************************/ + +int stm32_sdio_initialize(void) +{ + int ret; + +#ifdef HAVE_NCD + /* Card detect */ + + bool cd_status; + + /* Configure the card detect GPIO */ + + stm32_configgpio(GPIO_SDMMC1_NCD); + + /* Register an interrupt handler for the card detect pin */ + + stm32_gpiosetevent(GPIO_SDMMC1_NCD, true, true, true, stm32_ncd_interrupt); +#endif + + /* Mount the SDIO-based MMC/SD block driver */ + /* First, get an instance of the SDIO interface */ + + finfo("Initializing SDIO slot %d\n", SDIO_SLOTNO); + + sdio_dev = sdio_initialize(SDIO_SLOTNO); + + if (!sdio_dev) { + syslog(LOG_ERR, "[boot] Failed to initialize SDIO slot %d\n", SDIO_SLOTNO); + return -ENODEV; + } + + /* Now bind the SDIO interface to the MMC/SD driver */ + + finfo("Bind SDIO to the MMC/SD driver, minor=%d\n", SDIO_MINOR); + + ret = mmcsd_slotinitialize(SDIO_MINOR, sdio_dev); + + if (ret != OK) { + syslog(LOG_ERR, "[boot] Failed to bind SDIO to the MMC/SD driver: %d\n", ret); + return ret; + } + + finfo("Successfully bound SDIO to the MMC/SD driver\n"); + +#ifdef HAVE_NCD + /* Use SD card detect pin to check if a card is g_sd_inserted */ + + cd_status = !stm32_gpioread(GPIO_SDMMC1_NCD); + finfo("Card detect : %d\n", cd_status); + + sdio_mediachange(sdio_dev, cd_status); +#else + /* Assume that the SD card is inserted. What choice do we have? */ + + sdio_mediachange(sdio_dev, true); +#endif + + return OK; +} + +#endif /* CONFIG_MMCSD */ diff --git a/boards/micoair/h743-lite/src/spi.cpp b/boards/micoair/h743-lite/src/spi.cpp new file mode 100644 index 0000000000..148534ff85 --- /dev/null +++ b/boards/micoair/h743-lite/src/spi.cpp @@ -0,0 +1,45 @@ +/**************************************************************************** + * + * Copyright (C) 2021 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include +#include +#include + + +constexpr px4_spi_bus_t px4_spi_buses[SPI_BUS_MAX_BUS_ITEMS] = { + initSPIBus(SPI::Bus::SPI3, { + initSPIDevice(DRV_IMU_DEVTYPE_ICM45686, SPI::CS{GPIO::PortD, GPIO::Pin4}, SPI::DRDY{GPIO::PortD, GPIO::Pin5}), + }), +}; + +static constexpr bool unused = validateSPIConfig(px4_spi_buses); diff --git a/boards/micoair/h743-lite/src/timer_config.cpp b/boards/micoair/h743-lite/src/timer_config.cpp new file mode 100644 index 0000000000..050d3b0dc4 --- /dev/null +++ b/boards/micoair/h743-lite/src/timer_config.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** + * + * Copyright (C) 2021 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 + +constexpr io_timers_t io_timers[MAX_IO_TIMERS] = { + initIOTimer(Timer::Timer1, DMA{DMA::Index1}), + initIOTimer(Timer::Timer3, DMA{DMA::Index1}), + initIOTimer(Timer::Timer4, DMA{DMA::Index1}), + initIOTimer(Timer::Timer12), + initIOTimer(Timer::Timer15), +}; + +constexpr timer_io_channels_t timer_io_channels[MAX_TIMER_IO_CHANNELS] = { + initIOTimerChannel(io_timers, {Timer::Timer1, Timer::Channel4}, {GPIO::PortE, GPIO::Pin14}), + initIOTimerChannel(io_timers, {Timer::Timer1, Timer::Channel3}, {GPIO::PortE, GPIO::Pin13}), + initIOTimerChannel(io_timers, {Timer::Timer1, Timer::Channel2}, {GPIO::PortE, GPIO::Pin11}), + initIOTimerChannel(io_timers, {Timer::Timer1, Timer::Channel1}, {GPIO::PortE, GPIO::Pin9}), + initIOTimerChannel(io_timers, {Timer::Timer3, Timer::Channel4}, {GPIO::PortB, GPIO::Pin1}), + initIOTimerChannel(io_timers, {Timer::Timer3, Timer::Channel3}, {GPIO::PortB, GPIO::Pin0}), + initIOTimerChannel(io_timers, {Timer::Timer3, Timer::Channel2}, {GPIO::PortA, GPIO::Pin7}), + initIOTimerChannel(io_timers, {Timer::Timer3, Timer::Channel1}, {GPIO::PortA, GPIO::Pin6}), + initIOTimerChannel(io_timers, {Timer::Timer15, Timer::Channel1}, {GPIO::PortE, GPIO::Pin5}), + initIOTimerChannel(io_timers, {Timer::Timer15, Timer::Channel2}, {GPIO::PortE, GPIO::Pin6}), + initIOTimerChannel(io_timers, {Timer::Timer4, Timer::Channel1}, {GPIO::PortD, GPIO::Pin12}), + initIOTimerChannel(io_timers, {Timer::Timer4, Timer::Channel2}, {GPIO::PortD, GPIO::Pin13}), + initIOTimerChannel(io_timers, {Timer::Timer12, Timer::Channel1}, {GPIO::PortB, GPIO::Pin14}), + initIOTimerChannel(io_timers, {Timer::Timer12, Timer::Channel2}, {GPIO::PortB, GPIO::Pin15}), + +}; + +constexpr io_timers_channel_mapping_t io_timers_channel_mapping = + initIOTimerChannelMapping(io_timers, timer_io_channels); diff --git a/boards/micoair/h743-lite/src/usb.c b/boards/micoair/h743-lite/src/usb.c new file mode 100644 index 0000000000..9591784866 --- /dev/null +++ b/boards/micoair/h743-lite/src/usb.c @@ -0,0 +1,78 @@ +/**************************************************************************** + * + * Copyright (C) 2021 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 usb.c + * + * Board-specific USB functions. + */ + +#include "board_config.h" +#include +#include +#include +#include + +/************************************************************************************ + * Name: stm32_usbinitialize + * + * Description: + * Called to setup USB-related GPIO pins for the board. + * + ************************************************************************************/ + +__EXPORT void stm32_usbinitialize(void) +{ + /* The OTG FS has an internal soft pull-up */ + + /* Configure the OTG FS VBUS sensing GPIO, Power On, and Overcurrent GPIOs */ + +#ifdef CONFIG_STM32H7_OTGFS + stm32_configgpio(GPIO_OTGFS_VBUS); +#endif +} + +/************************************************************************************ + * Name: stm32_usbsuspend + * + * Description: + * Board logic must provide the stm32_usbsuspend logic if the USBDEV driver is + * used. This function is called whenever the USB enters or leaves suspend mode. + * This is an opportunity for the board logic to shutdown clocks, power, etc. + * while the USB is suspended. + * + ************************************************************************************/ +__EXPORT void stm32_usbsuspend(FAR struct usbdev_s *dev, bool resume) +{ + uinfo("resume: %d\n", resume); +} From fb13b880cef55f653f08c71920ae3a4046cc5334 Mon Sep 17 00:00:00 2001 From: Phil-Engljaehringer Date: Tue, 4 Nov 2025 17:22:10 +0100 Subject: [PATCH 014/139] sensors: add ads7953 adc * sensors: add ads7953 adc * Update src/drivers/adc/ads7953/ADS7953.h Co-authored-by: Jacob Dahl <37091262+dakejahl@users.noreply.github.com> * Implemented changes suggested by review * Implemented suggested changes * removed unused variables and moved scope of ch_id * Activated distance sensor again * Update msg/AdcReport.msg Co-authored-by: Hamish Willee * Update ADC report message field comments * Update ADC msg - fix layout * update comments * changed group to Sensors in module.yaml * created new module subcategory "adc" * reverted group change in module.yaml * added module descrption to modules_driver.md * removed module description in modules_driver.md (autogenerated) * removed unused variable, changed board_adc publication method to "multi" * added static assert --------- Co-authored-by: Jacob Dahl <37091262+dakejahl@users.noreply.github.com> Co-authored-by: Hamish Willee --- ROMFS/px4fmu_common/init.d/rc.sensors | 6 ++ Tools/px4moduledoc/srcparser.py | 2 +- msg/AdcReport.msg | 16 +-- src/drivers/adc/ads7953/ADS7953.cpp | 122 +++++++++++++++++++++++ src/drivers/adc/ads7953/ADS7953.h | 43 ++++++++ src/drivers/adc/ads7953/CMakeLists.txt | 46 +++++++++ src/drivers/adc/ads7953/Kconfig | 5 + src/drivers/adc/ads7953/ads7953_main.cpp | 77 ++++++++++++++ src/drivers/adc/ads7953/module.yaml | 29 ++++++ src/drivers/adc/board_adc/ADC.hpp | 3 +- src/drivers/drv_sensor.h | 2 + 11 files changed, 343 insertions(+), 8 deletions(-) create mode 100644 src/drivers/adc/ads7953/ADS7953.cpp create mode 100644 src/drivers/adc/ads7953/ADS7953.h create mode 100644 src/drivers/adc/ads7953/CMakeLists.txt create mode 100644 src/drivers/adc/ads7953/Kconfig create mode 100644 src/drivers/adc/ads7953/ads7953_main.cpp create mode 100644 src/drivers/adc/ads7953/module.yaml diff --git a/ROMFS/px4fmu_common/init.d/rc.sensors b/ROMFS/px4fmu_common/init.d/rc.sensors index 759acb3b51..d558d381b1 100644 --- a/ROMFS/px4fmu_common/init.d/rc.sensors +++ b/ROMFS/px4fmu_common/init.d/rc.sensors @@ -219,6 +219,12 @@ then pcf8583 start -X -a 0x51 fi +# ADC sensor ADS7953 external SPI +if param compare -s ADC_ADS7953_EN 1 +then + ads7953 start -S +fi + # probe for optional external I2C devices if param compare SENS_EXT_I2C_PRB 1 then diff --git a/Tools/px4moduledoc/srcparser.py b/Tools/px4moduledoc/srcparser.py index 8b56e7bb08..749acef762 100644 --- a/Tools/px4moduledoc/srcparser.py +++ b/Tools/px4moduledoc/srcparser.py @@ -15,7 +15,7 @@ class ModuleDocumentation(object): # TOC in https://github.com/PX4/PX4-Autopilot/blob/main/docs/en/SUMMARY.md valid_categories = ['driver', 'estimator', 'controller', 'system', 'communication', 'command', 'template', 'simulation', 'autotune'] - valid_subcategories = ['', 'camera', 'distance_sensor', 'imu', 'ins', 'airspeed_sensor', + valid_subcategories = ['', 'adc', 'camera', 'distance_sensor', 'imu', 'ins', 'airspeed_sensor', 'magnetometer', 'baro', 'optical_flow', 'radio_control','rpm_sensor', 'transponder'] max_line_length = 80 # wrap lines that are longer than this diff --git a/msg/AdcReport.msg b/msg/AdcReport.msg index 1ae72b6d6c..4a56bc2875 100644 --- a/msg/AdcReport.msg +++ b/msg/AdcReport.msg @@ -1,6 +1,10 @@ -uint64 timestamp # time since system start (microseconds) -uint32 device_id # unique device ID for the sensor that does not change between power cycles -int16[12] channel_id # ADC channel IDs, negative for non-existent, TODO: should be kept same as array index -int32[12] raw_data # ADC channel raw value, accept negative value, valid if channel ID is positive -uint32 resolution # ADC channel resolution -float32 v_ref # ADC channel voltage reference, use to calculate LSB voltage(lsb=scale/resolution) +# ADC raw data. +# +# Communicates raw data from an analog-to-digital converter (ADC) to other modules, such as battery status. + +uint64 timestamp # [us] Time since system start +uint32 device_id # [-] unique device ID for the sensor that does not change between power cycles +int16[16] channel_id # [-] ADC channel IDs, negative for non-existent, TODO: should be kept same as array index +int32[16] raw_data # [-] ADC channel raw value, accept negative value, valid if channel ID is positive +uint32 resolution # [-] ADC channel resolution +float32 v_ref # [V] ADC channel voltage reference, use to calculate LSB voltage(lsb=scale/resolution) diff --git a/src/drivers/adc/ads7953/ADS7953.cpp b/src/drivers/adc/ads7953/ADS7953.cpp new file mode 100644 index 0000000000..e2076ef115 --- /dev/null +++ b/src/drivers/adc/ads7953/ADS7953.cpp @@ -0,0 +1,122 @@ + +#include "ADS7953.h" +#include +#include +#include +#include + +ADS7953::ADS7953(const I2CSPIDriverConfig &config) : + SPI(config), + I2CSPIDriver(config), + ModuleParams(nullptr) +{ + static_assert(arraySize(adc_report_s::channel_id) >= NUM_CHANNELS, "ADS7953 reports 16 channels"); +} + +int ADS7953::init() +{ + int ret = SPI::init(); + + if (ret != PX4_OK) { + PX4_DEBUG("SPI::init failed (%i)", ret); + return ret; + } + + _adc_report.device_id = this->get_device_id(); + _adc_report.v_ref = _adc_ads7953_refv.get(); + _adc_report.resolution = 4096; + + for (unsigned i = 0; i < PX4_MAX_ADC_CHANNELS; ++i) { + _adc_report.channel_id[i] = -1; + } + + ScheduleOnInterval(10_ms); + return PX4_OK; +} + +int ADS7953::probe() +{ + // The ADS7953 has no ID register which we can check, so we verify the device via the returned channel ID. + // We set the mode to "manual mode" and the channel to measure to 1. + // If the returned channel ID on the third message is 1, we assume the ADS7953 is connected. + uint8_t recv_data[2]; + + int ret = rw_msg(&recv_data[0], 1, true); + + if (ret != PX4_OK) { + PX4_DEBUG("ADS7953 probing failed (%i)", ret); + return ret; + } + + ret |= rw_msg(&recv_data[0], 0, false); + ret |= rw_msg(&recv_data[0], 0, true); + + if (ret != PX4_OK || (recv_data[0] >> 4) != 1U) { + PX4_DEBUG("ADS7953 probing failed (%i)", ret); + return PX4_ERROR; + } + + PX4_INFO("ADS7953 was found"); + return PX4_OK; +} + +int ADS7953::rw_msg(uint8_t *recv_data, uint8_t ch, bool change_channel) +{ + uint8_t send_data[2]; + + if (change_channel) { + send_data[0] = 0x10 | (ch >> 1); + send_data[1] = 0x00 | (ch << 7); + + } else { + send_data[0] = 0x00; + send_data[1] = 0x00; + } + + return transfer(&send_data[0], &recv_data[0], 2); +} + +int ADS7953::get_measurements() +{ + uint8_t recv_data[2]; + int count = 0; + uint16_t mask = 0x00; + uint8_t idx = 0; + + while (count < NUM_CHANNELS) { + if (rw_msg(&recv_data[0], idx, true) == PX4_OK) { + uint8_t ch_id = (recv_data[0] >> 4); + + //check if we already have a measurement for the returned channel + if (!(mask & (1U << ch_id))) { + mask |= (1U << ch_id); + count++; + _adc_report.channel_id[ch_id] = ch_id; + _adc_report.raw_data[ch_id] = ((((uint16_t) recv_data[0]) & 0x0F) << 8) | recv_data[1]; + } + } + + // Find index to measure next + for (int i = 1; i <= NUM_CHANNELS; i++) { + uint8_t candidate_id = (idx + i) % NUM_CHANNELS; + + if (!(mask & (1U << candidate_id))) { + idx = candidate_id; + break; + } + } + } + + return 0; +} + +void ADS7953::RunImpl() +{ + get_measurements(); + _adc_report.timestamp = hrt_absolute_time(); + _adc_report_pub.publish(_adc_report); + + for (unsigned i = 0; i < PX4_MAX_ADC_CHANNELS; ++i) { + _adc_report.channel_id[i] = -1; + } +} diff --git a/src/drivers/adc/ads7953/ADS7953.h b/src/drivers/adc/ads7953/ADS7953.h new file mode 100644 index 0000000000..03ffcb7b81 --- /dev/null +++ b/src/drivers/adc/ads7953/ADS7953.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace time_literals; + + +class ADS7953 : public device::SPI, public I2CSPIDriver, public ModuleParams +{ +public: + ADS7953(const I2CSPIDriverConfig &config); + virtual ~ADS7953() = default; + static void print_usage(); + + int init() override; + void RunImpl(); + int probe() override; + + +private: + static constexpr int NUM_CHANNELS = 16; + uORB::PublicationMulti _adc_report_pub{ORB_ID(adc_report)}; + + static const hrt_abstime SAMPLE_INTERVAL{50_ms}; + + DEFINE_PARAMETERS( + (ParamFloat) _adc_ads7953_refv + ) + adc_report_s _adc_report{}; + + int get_measurements(); + int rw_msg(uint8_t *recv_data, uint8_t ch, bool change_channel); +}; diff --git a/src/drivers/adc/ads7953/CMakeLists.txt b/src/drivers/adc/ads7953/CMakeLists.txt new file mode 100644 index 0000000000..fbb25e5f5d --- /dev/null +++ b/src/drivers/adc/ads7953/CMakeLists.txt @@ -0,0 +1,46 @@ +############################################################################ +# +# Copyright (c) 2025 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_module( + MODULE drivers__adc__ads7953 + MAIN ads7953 + COMPILE_FLAGS + SRCS + ADS7953.cpp + ADS7953.h + ads7953_main.cpp + MODULE_CONFIG + module.yaml + DEPENDS + px4_work_queue + ) diff --git a/src/drivers/adc/ads7953/Kconfig b/src/drivers/adc/ads7953/Kconfig new file mode 100644 index 0000000000..a50f4c8b26 --- /dev/null +++ b/src/drivers/adc/ads7953/Kconfig @@ -0,0 +1,5 @@ +menuconfig DRIVERS_ADC_ADS7953 + bool "ADS7953 driver" + default n + ---help--- + Enable support for ADS7953 diff --git a/src/drivers/adc/ads7953/ads7953_main.cpp b/src/drivers/adc/ads7953/ads7953_main.cpp new file mode 100644 index 0000000000..9c9de10faf --- /dev/null +++ b/src/drivers/adc/ads7953/ads7953_main.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** + * + * Copyright (c) 2025 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include +#include +#include "ADS7953.h" + +void ADS7953::print_usage() +{ + PRINT_MODULE_USAGE_NAME("ads7953", "driver"); + PRINT_MODULE_USAGE_SUBCATEGORY("adc"); + PRINT_MODULE_USAGE_COMMAND("start"); + PRINT_MODULE_USAGE_PARAMS_I2C_SPI_DRIVER(false, true); + PRINT_MODULE_USAGE_DEFAULT_COMMANDS(); +} + +extern "C" int ads7953_main(int argc, char *argv[]) +{ + using ThisDriver = ADS7953; + BusCLIArguments cli{false, true}; + cli.spi_mode = SPIDEV_MODE0; + cli.default_spi_frequency = 10 * 1000 * 1000; + const char *name = MODULE_NAME; + const char *verb = cli.parseDefaultArguments(argc, argv); + + if (!verb) { + ThisDriver::print_usage(); + return -1; + } + + BusInstanceIterator iterator(name, cli, DRV_ADC_DEVTYPE_ADS7953); + + if (!strcmp(verb, "start")) { + return ThisDriver::module_start(cli, iterator); + } + + if (!strcmp(verb, "stop")) { + return ThisDriver::module_stop(iterator); + } + + if (!strcmp(verb, "status")) { + return ThisDriver::module_status(iterator); + } + + ThisDriver::print_usage(); + return -1; +} diff --git a/src/drivers/adc/ads7953/module.yaml b/src/drivers/adc/ads7953/module.yaml new file mode 100644 index 0000000000..9097daeb08 --- /dev/null +++ b/src/drivers/adc/ads7953/module.yaml @@ -0,0 +1,29 @@ +__max_num_config_instances: &max_num_config_instances 1 + +module_name: ADS7953 + +parameters: + - group: ADC + definitions: + ADC_ADS7953_EN: + description: + short: Enable ADS7953 + long: | + Enable the driver for the ADS7953 board + type: boolean + reboot_required: true + default: 0 + + ADC_ADS7953_REFV: + description: + short: Applied reference Voltage. + long: | + The voltage applied to the ADS7953 board as reference + type: float + unit: V + min: 2.0 + max: 3.0 + decimal: 2 + increment: 0.01 + reboot_required: true + default: 2.5 diff --git a/src/drivers/adc/board_adc/ADC.hpp b/src/drivers/adc/board_adc/ADC.hpp index 47f9538814..c765d596b4 100644 --- a/src/drivers/adc/board_adc/ADC.hpp +++ b/src/drivers/adc/board_adc/ADC.hpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -110,7 +111,7 @@ private: const uint32_t _base_address; px4_adc_msg_t *_samples{nullptr}; /**< sample buffer */ - uORB::Publication _to_adc_report{ORB_ID(adc_report)}; + uORB::PublicationMulti _to_adc_report{ORB_ID(adc_report)}; uORB::Publication _to_system_power{ORB_ID(system_power)}; #ifdef BOARD_GPIO_VDD_5V_COMP_VALID diff --git a/src/drivers/drv_sensor.h b/src/drivers/drv_sensor.h index 1f74122014..eeafc722cf 100644 --- a/src/drivers/drv_sensor.h +++ b/src/drivers/drv_sensor.h @@ -260,6 +260,8 @@ #define DRV_INS_DEVTYPE_SBG 0xEC +#define DRV_ADC_DEVTYPE_ADS7953 0xED + #define DRV_DEVTYPE_UNUSED 0xff #endif /* _DRV_SENSOR_H */ From e7609ad5b5e98b2f582f9557455d4cc2734622bc Mon Sep 17 00:00:00 2001 From: PX4 Build Bot Date: Wed, 5 Nov 2025 17:10:09 +1100 Subject: [PATCH 015/139] New Crowdin translations - zh-CN (#25858) Co-authored-by: Crowdin Bot --- docs/zh/msg_docs/DifferentialPressure.md | 23 +++++++++++++++-------- docs/zh/msg_docs/SensorBaro.md | 23 +++++++++++++++-------- docs/zh/msg_docs/VehicleStatus.md | 14 +++++--------- docs/zh/msg_docs/index.md | 4 ++-- 4 files changed, 37 insertions(+), 27 deletions(-) diff --git a/docs/zh/msg_docs/DifferentialPressure.md b/docs/zh/msg_docs/DifferentialPressure.md index f5fd908df9..83adb2d03e 100644 --- a/docs/zh/msg_docs/DifferentialPressure.md +++ b/docs/zh/msg_docs/DifferentialPressure.md @@ -1,17 +1,24 @@ # DifferentialPressure (UORB message) +Differential-pressure (airspeed) sensor + +This is populated by airspeed sensor drivers and used by the sensor module to calculate airspeed. +The information is published in the `SCALED_PRESSURE_n` MAVLink messages (along with information from a corresponding `SensorBaro` instance). + [source file](https://github.com/PX4/PX4-Autopilot/blob/main/msg/DifferentialPressure.msg) ```c -uint64 timestamp # time since system start (microseconds) -uint64 timestamp_sample +# Differential-pressure (airspeed) sensor +# +# This is populated by airspeed sensor drivers and used by the sensor module to calculate airspeed. +# The information is published in the `SCALED_PRESSURE_n` MAVLink messages (along with information from a corresponding `SensorBaro` instance). -uint32 device_id # unique device ID for the sensor that does not change between power cycles +uint64 timestamp # [us] Time of publication (since system start) +uint64 timestamp_sample # [us] Time of raw data capture -float32 differential_pressure_pa # differential pressure reading in Pascals (may be negative) - -float32 temperature # Temperature provided by sensor in degrees Celsius, NAN if unknown - -uint32 error_count # Number of errors detected by driver +uint32 device_id # [-] Unique device ID for the sensor that does not change between power cycles +float32 differential_pressure_pa # [Pa] Differential pressure reading (may be negative) +float32 temperature # [degC] [@invalid NaN if unknown] Temperature +uint32 error_count # [-] Number of errors detected by driver ``` diff --git a/docs/zh/msg_docs/SensorBaro.md b/docs/zh/msg_docs/SensorBaro.md index cf834ccf36..ef4d7a8f28 100644 --- a/docs/zh/msg_docs/SensorBaro.md +++ b/docs/zh/msg_docs/SensorBaro.md @@ -1,18 +1,25 @@ # SensorBaro (UORB message) +Barometer sensor + +This is populated by barometer drivers and used by the EKF2 estimator. +The information is published in the `SCALED_PRESSURE_n` MAVLink messages (along with information from a corresponding `DifferentialPressure` instance). + [source file](https://github.com/PX4/PX4-Autopilot/blob/main/msg/SensorBaro.msg) ```c -uint64 timestamp # time since system start (microseconds) -uint64 timestamp_sample +# Barometer sensor +# +# This is populated by barometer drivers and used by the EKF2 estimator. +# The information is published in the `SCALED_PRESSURE_n` MAVLink messages (along with information from a corresponding `DifferentialPressure` instance). -uint32 device_id # unique device ID for the sensor that does not change between power cycles +uint64 timestamp # [us] Time of publication (since system start) +uint64 timestamp_sample # [us] Time of raw data capture -float32 pressure # static pressure measurement in Pascals - -float32 temperature # temperature in degrees Celsius - -uint32 error_count +uint32 device_id # [-] Unique device ID for the sensor that does not change between power cycles +float32 pressure # [Pa] Static pressure measurement +float32 temperature # [degC] Temperature. +uint32 error_count # [-] Number of errors detected by driver. uint8 ORB_QUEUE_LENGTH = 4 diff --git a/docs/zh/msg_docs/VehicleStatus.md b/docs/zh/msg_docs/VehicleStatus.md index 9d46e42cb3..05e3f98bbb 100644 --- a/docs/zh/msg_docs/VehicleStatus.md +++ b/docs/zh/msg_docs/VehicleStatus.md @@ -20,20 +20,16 @@ uint8 ARMING_STATE_ARMED = 2 uint8 latest_arming_reason uint8 latest_disarming_reason -uint8 ARM_DISARM_REASON_TRANSITION_TO_STANDBY = 0 uint8 ARM_DISARM_REASON_STICK_GESTURE = 1 uint8 ARM_DISARM_REASON_RC_SWITCH = 2 uint8 ARM_DISARM_REASON_COMMAND_INTERNAL = 3 uint8 ARM_DISARM_REASON_COMMAND_EXTERNAL = 4 uint8 ARM_DISARM_REASON_MISSION_START = 5 -uint8 ARM_DISARM_REASON_SAFETY_BUTTON = 6 -uint8 ARM_DISARM_REASON_AUTO_DISARM_LAND = 7 -uint8 ARM_DISARM_REASON_AUTO_DISARM_PREFLIGHT = 8 -uint8 ARM_DISARM_REASON_KILL_SWITCH = 9 -uint8 ARM_DISARM_REASON_LOCKDOWN = 10 -uint8 ARM_DISARM_REASON_FAILURE_DETECTOR = 11 -uint8 ARM_DISARM_REASON_SHUTDOWN = 12 -uint8 ARM_DISARM_REASON_UNIT_TEST = 13 +uint8 ARM_DISARM_REASON_LANDING = 6 +uint8 ARM_DISARM_REASON_PREFLIGHT_INACTION = 7 +uint8 ARM_DISARM_REASON_KILL_SWITCH = 8 +uint8 ARM_DISARM_REASON_RC_BUTTON = 13 +uint8 ARM_DISARM_REASON_FAILSAFE = 14 uint64 nav_state_timestamp # time when current nav_state activated diff --git a/docs/zh/msg_docs/index.md b/docs/zh/msg_docs/index.md index dfed09c171..2512c7058d 100644 --- a/docs/zh/msg_docs/index.md +++ b/docs/zh/msg_docs/index.md @@ -105,7 +105,7 @@ Graphs showing how these are used [can be found here](../middleware/uorb_graph.m - [DebugKeyValue](DebugKeyValue.md) - [DebugValue](DebugValue.md) - [DebugVect](DebugVect.md) -- [DifferentialPressure](DifferentialPressure.md) +- [DifferentialPressure](DifferentialPressure.md) — Differential-pressure (airspeed) sensor - [DistanceSensor](DistanceSensor.md) — DISTANCE_SENSOR message data - [DistanceSensorModeChangeRequest](DistanceSensorModeChangeRequest.md) - [DronecanNodeStatus](DronecanNodeStatus.md) @@ -240,7 +240,7 @@ Graphs showing how these are used [can be found here](../middleware/uorb_graph.m - [SensorAccel](SensorAccel.md) - [SensorAccelFifo](SensorAccelFifo.md) - [SensorAirflow](SensorAirflow.md) -- [SensorBaro](SensorBaro.md) +- [SensorBaro](SensorBaro.md) — Barometer sensor - [SensorCombined](SensorCombined.md) — Sensor readings in SI-unit form. These fields are scaled and offset-compensated where possible and do not change with board revisions and sensor updates. From ab1c880aadcee048dc3a29d9792bfdc9fcf77a9a Mon Sep 17 00:00:00 2001 From: Balduin Date: Wed, 5 Nov 2025 09:55:49 +0100 Subject: [PATCH 016/139] pusher_assist: keep pitch setpoint VT_PITCH_MIN (#25871) * pusher_assist: keep pitch setpoint VT_PITCH_MIN resetting the pitch setpoint to zero made little sense, because we lose the forward thrust component of the hover motors, while the pusher throttle was calculated to be applied in addition to the hover forward component * pusher assist: change default min pitches to 0 To make for a smoother transition for users who don't care much about pitch when pusher-assisting and were fine with it (mostly) being at zero --- src/modules/vtol_att_control/vtol_att_control_params.c | 4 ++-- src/modules/vtol_att_control/vtol_type.cpp | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/modules/vtol_att_control/vtol_att_control_params.c b/src/modules/vtol_att_control/vtol_att_control_params.c index 4b9452d3b6..af664bd632 100644 --- a/src/modules/vtol_att_control/vtol_att_control_params.c +++ b/src/modules/vtol_att_control/vtol_att_control_params.c @@ -365,7 +365,7 @@ PARAM_DEFINE_FLOAT(VT_B_DEC_I, 0.1f); * @decimal 1 * @group VTOL Attitude Control */ -PARAM_DEFINE_FLOAT(VT_PITCH_MIN, -5.0f); +PARAM_DEFINE_FLOAT(VT_PITCH_MIN, 0.0f); /** * Minimum pitch angle during hover landing. @@ -380,7 +380,7 @@ PARAM_DEFINE_FLOAT(VT_PITCH_MIN, -5.0f); * @decimal 1 * @group VTOL Attitude Control */ -PARAM_DEFINE_FLOAT(VT_LND_PITCH_MIN, -5.0f); +PARAM_DEFINE_FLOAT(VT_LND_PITCH_MIN, 0.0f); /** * Spoiler setting while landing (hover) diff --git a/src/modules/vtol_att_control/vtol_type.cpp b/src/modules/vtol_att_control/vtol_type.cpp index def70ece07..8195df5f8b 100644 --- a/src/modules/vtol_att_control/vtol_type.cpp +++ b/src/modules/vtol_att_control/vtol_type.cpp @@ -515,12 +515,8 @@ float VtolType::pusher_assist() // limit forward actuation to [0, 0.9] forward_thrust = math::constrain(forward_thrust, 0.0f, 0.9f); - // Set the pitch to 0 if the pitch limit is negative (pitch down), but allow a positive (pitch up) pitch. - // This can be used for tiltrotor to make them hover with a positive angle of attack - const float pitch_new = pitch_setpoint_min > 0.f ? pitch_setpoint_min : 0.f; - // create corrected desired body z axis in heading frame - const Dcmf R_tmp = Eulerf(roll_new, pitch_new, 0.0f); + const Dcmf R_tmp = Eulerf(roll_new, pitch_setpoint_min, 0.0f); Vector3f tilt_new(R_tmp(0, 2), R_tmp(1, 2), R_tmp(2, 2)); // rotate the vector into a new frame which is rotated in z by the desired heading From 84b5ce9010f110858fa670925d043a7974425705 Mon Sep 17 00:00:00 2001 From: Marco Hauswirth <58551738+haumarco@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:25:15 +0100 Subject: [PATCH 017/139] AirspeedSelector: enable changing ASPD_SCALE manually in-air mid-flight (#25817) Includes a reset in wind estimator states if changed --- src/lib/wind_estimator/WindEstimator.hpp | 8 ++++++++ .../airspeed_selector/AirspeedValidator.hpp | 1 + .../airspeed_selector/airspeed_selector_main.cpp | 14 ++++++++++++++ .../airspeed_selector/airspeed_selector_params.c | 3 --- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/lib/wind_estimator/WindEstimator.hpp b/src/lib/wind_estimator/WindEstimator.hpp index 462f88ff26..dbdf854da9 100644 --- a/src/lib/wind_estimator/WindEstimator.hpp +++ b/src/lib/wind_estimator/WindEstimator.hpp @@ -94,6 +94,14 @@ public: void set_beta_gate(uint8_t gate_size) {_beta_gate = gate_size; } void set_scale_init(float scale_init) {_scale_init = 1.f / math::constrain(scale_init, 0.1f, 10.f); } + void reset_scale_to_init() + { + _state(INDEX_TAS_SCALE) = _scale_init; + auto P_wind = _P.slice<2, 2>(0, 0); + _P.setZero(); + _P.slice<2, 2>(0, 0) = P_wind; + } + private: enum { INDEX_W_N = 0, diff --git a/src/modules/airspeed_selector/AirspeedValidator.hpp b/src/modules/airspeed_selector/AirspeedValidator.hpp index ec78b9ef8f..f902e8a9de 100644 --- a/src/modules/airspeed_selector/AirspeedValidator.hpp +++ b/src/modules/airspeed_selector/AirspeedValidator.hpp @@ -121,6 +121,7 @@ public: void set_tas_scale_apply(int tas_scale_apply) { _tas_scale_apply = tas_scale_apply; } void set_CAS_scale_validated(float scale) { _CAS_scale_validated = scale; } void set_scale_init(float scale) { _wind_estimator.set_scale_init(scale); } + void reset_scale_estimator() { _wind_estimator.reset_scale_to_init(); } void set_enable_data_stuck_check(bool enable) { _data_stuck_check_enabled = enable; } void set_enable_innovation_check(bool enable) { _innovation_check_enabled = enable; } diff --git a/src/modules/airspeed_selector/airspeed_selector_main.cpp b/src/modules/airspeed_selector/airspeed_selector_main.cpp index b3209e2f33..94a8b9cd8a 100644 --- a/src/modules/airspeed_selector/airspeed_selector_main.cpp +++ b/src/modules/airspeed_selector/airspeed_selector_main.cpp @@ -494,10 +494,24 @@ void AirspeedModule::update_params() param_get(_param_handle_fw_thr_max, &_param_fw_thr_max); } + const float prev_scale[MAX_NUM_AIRSPEED_SENSORS] = { + _param_airspeed_scale[0], + _param_airspeed_scale[1], + _param_airspeed_scale[2] + }; + _param_airspeed_scale[0] = _param_airspeed_scale_1.get(); _param_airspeed_scale[1] = _param_airspeed_scale_2.get(); _param_airspeed_scale[2] = _param_airspeed_scale_3.get(); + for (int i = 0; i < MAX_NUM_AIRSPEED_SENSORS; i++) { + if (fabsf(_param_airspeed_scale[i] - prev_scale[i]) > FLT_EPSILON) { + _airspeed_validator[i].set_scale_init(_param_airspeed_scale[i]); + _airspeed_validator[i].reset_scale_estimator(); + _airspeed_validator[i].set_CAS_scale_validated(_param_airspeed_scale[i]); + } + } + _wind_estimator_sideslip.set_wind_process_noise_spectral_density(_param_aspd_wind_nsd.get()); _wind_estimator_sideslip.set_tas_scale_process_noise_spectral_density(_param_aspd_scale_nsd.get()); _wind_estimator_sideslip.set_tas_noise(_param_west_tas_noise.get()); diff --git a/src/modules/airspeed_selector/airspeed_selector_params.c b/src/modules/airspeed_selector/airspeed_selector_params.c index a7db4cb30c..34d74cbfc5 100644 --- a/src/modules/airspeed_selector/airspeed_selector_params.c +++ b/src/modules/airspeed_selector/airspeed_selector_params.c @@ -95,7 +95,6 @@ PARAM_DEFINE_INT32(ASPD_SCALE_APPLY, 2); * @min 0.5 * @max 2.0 * @decimal 2 - * @reboot_required true * @group Airspeed Validator * @volatile */ @@ -109,7 +108,6 @@ PARAM_DEFINE_FLOAT(ASPD_SCALE_1, 1.0f); * @min 0.5 * @max 2.0 * @decimal 2 - * @reboot_required true * @group Airspeed Validator * @volatile */ @@ -123,7 +121,6 @@ PARAM_DEFINE_FLOAT(ASPD_SCALE_2, 1.0f); * @min 0.5 * @max 2.0 * @decimal 2 - * @reboot_required true * @group Airspeed Validator * @volatile */ From 5f0d222e1b699447a555063d16746f009f915dbd Mon Sep 17 00:00:00 2001 From: Minderring <1701213518@sz.edu.pku.cn> Date: Wed, 5 Nov 2025 17:45:19 +0800 Subject: [PATCH 018/139] update micoair boards config files: remove CONFIG_DRIVERS_RC_INPUT --- boards/micoair/h743-aio/default.px4board | 1 - boards/micoair/h743-lite/default.px4board | 1 - boards/micoair/h743-v2/default.px4board | 1 - boards/micoair/h743/default.px4board | 1 - 4 files changed, 4 deletions(-) diff --git a/boards/micoair/h743-aio/default.px4board b/boards/micoair/h743-aio/default.px4board index d6dd734283..11abe64a47 100644 --- a/boards/micoair/h743-aio/default.px4board +++ b/boards/micoair/h743-aio/default.px4board @@ -37,7 +37,6 @@ CONFIG_DRIVERS_POWER_MONITOR_VOXLPM=y CONFIG_DRIVERS_PPS_CAPTURE=y CONFIG_DRIVERS_PWM_OUT=y CONFIG_COMMON_RC=y -CONFIG_DRIVERS_RC_INPUT=y CONFIG_DRIVERS_ROBOCLAW=y CONFIG_COMMON_RPM=y CONFIG_DRIVERS_SMART_BATTERY_BATMON=y diff --git a/boards/micoair/h743-lite/default.px4board b/boards/micoair/h743-lite/default.px4board index 68a87e863c..f24ffc4fdb 100644 --- a/boards/micoair/h743-lite/default.px4board +++ b/boards/micoair/h743-lite/default.px4board @@ -34,7 +34,6 @@ CONFIG_DRIVERS_POWER_MONITOR_VOXLPM=y CONFIG_DRIVERS_PPS_CAPTURE=y CONFIG_DRIVERS_PWM_OUT=y CONFIG_COMMON_RC=y -CONFIG_DRIVERS_RC_INPUT=y CONFIG_COMMON_RPM=y CONFIG_DRIVERS_SMART_BATTERY_BATMON=y CONFIG_DRIVERS_TAP_ESC=y diff --git a/boards/micoair/h743-v2/default.px4board b/boards/micoair/h743-v2/default.px4board index 9f6d00a5d0..5276166e42 100644 --- a/boards/micoair/h743-v2/default.px4board +++ b/boards/micoair/h743-v2/default.px4board @@ -36,7 +36,6 @@ CONFIG_DRIVERS_POWER_MONITOR_VOXLPM=y CONFIG_DRIVERS_PPS_CAPTURE=y CONFIG_DRIVERS_PWM_OUT=y CONFIG_COMMON_RC=y -CONFIG_DRIVERS_RC_INPUT=y CONFIG_COMMON_RPM=y CONFIG_DRIVERS_SMART_BATTERY_BATMON=y CONFIG_DRIVERS_TAP_ESC=y diff --git a/boards/micoair/h743/default.px4board b/boards/micoair/h743/default.px4board index d6769fa1d8..abf1cfb4ff 100644 --- a/boards/micoair/h743/default.px4board +++ b/boards/micoair/h743/default.px4board @@ -38,7 +38,6 @@ CONFIG_DRIVERS_POWER_MONITOR_VOXLPM=y CONFIG_DRIVERS_PPS_CAPTURE=y CONFIG_DRIVERS_PWM_OUT=y CONFIG_COMMON_RC=y -CONFIG_DRIVERS_RC_INPUT=y CONFIG_COMMON_RPM=y CONFIG_DRIVERS_SMART_BATTERY_BATMON=y CONFIG_DRIVERS_TAP_ESC=y From 1250563ed1942b09adcd0e2701dfda3bb704e423 Mon Sep 17 00:00:00 2001 From: Peter van der Perk <57130844+PetervdPerk-NXP@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:48:26 +0100 Subject: [PATCH 019/139] Add support for NXP MR-VMU-Tropic board (#25845) * rt106x: Use platform SPI hal layer * rt106x: Add romapi support and reboot to isp/bootloader * bootloader: imxrt_common: Add rt106x support * NXP MR-Tropic initial commit * Add missing file for mr-tropic bootloader * nxp-mr-tropic:Bootloader Alow Assertion debugging & Keep Ram Vectors * nxp-mr-tropic: Firmware Boot from bootloader * nxp-mr-tropic:Add Bootloader bin file * mr-tropic: Update config and linker Fixes enet issues with write-back and some code cleanup. Furthermore increase NOR LittleFS to 256kB to reflect on linker * Update NuttX * mr-tropic: fix itcm apping and add mr-tropic to itcm check --------- Co-authored-by: David Sidrane --- .github/workflows/itcm_check.yml | 4 + .vscode/cmake-variants.yaml | 10 + boards/nxp/mr-tropic/bootloader.px4board | 3 + boards/nxp/mr-tropic/cmake/upload.cmake | 44 ++ boards/nxp/mr-tropic/default.px4board | 109 +++ .../extras/nxp_mr-tropic_bootloader.bin | Bin 0 -> 74376 bytes boards/nxp/mr-tropic/firmware.prototype | 13 + boards/nxp/mr-tropic/init/rc.board_defaults | 38 + boards/nxp/mr-tropic/init/rc.board_mavlink | 4 + boards/nxp/mr-tropic/init/rc.board_sensors | 68 ++ boards/nxp/mr-tropic/nuttx-config/Kconfig | 4 + .../nuttx-config/bootloader/defconfig | 107 +++ .../mr-tropic/nuttx-config/include/board.h | 416 ++++++++++ .../nxp/mr-tropic/nuttx-config/nsh/defconfig | 270 +++++++ .../nuttx-config/scripts/bootloader_script.ld | 177 +++++ .../scripts/itcm_functions_includes.ld | 719 ++++++++++++++++++ .../scripts/itcm_static_functions.ld | 163 ++++ .../mr-tropic/nuttx-config/scripts/script.ld | 187 +++++ boards/nxp/mr-tropic/src/CMakeLists.txt | 86 +++ boards/nxp/mr-tropic/src/board_config.h | 355 +++++++++ boards/nxp/mr-tropic/src/bootloader_main.c | 61 ++ boards/nxp/mr-tropic/src/hw_config.h | 130 ++++ boards/nxp/mr-tropic/src/hw_rev_ver_tropic.c | 165 ++++ boards/nxp/mr-tropic/src/i2c.cpp | 40 + .../mr-tropic/src/imxrt_flexspi_nor_boot.c | 55 ++ .../mr-tropic/src/imxrt_flexspi_nor_boot.h | 166 ++++ .../mr-tropic/src/imxrt_flexspi_nor_flash.c | 107 +++ .../mr-tropic/src/imxrt_flexspi_nor_flash.h | 349 +++++++++ .../nxp/mr-tropic/src/imxrt_flexspi_storage.c | 411 ++++++++++ .../mr-tropic/src/imxrt_ocram_initialize.c | 102 +++ boards/nxp/mr-tropic/src/init.c | 400 ++++++++++ boards/nxp/mr-tropic/src/manifest.c | 79 ++ boards/nxp/mr-tropic/src/sdhc.c | 128 ++++ boards/nxp/mr-tropic/src/spi.cpp | 95 +++ boards/nxp/mr-tropic/src/timer_config.cpp | 152 ++++ boards/nxp/mr-tropic/src/tropic_led_pwm.cpp | 182 +++++ boards/nxp/mr-tropic/src/usb.c | 129 ++++ .../px4_platform_common/board_common.h | 9 +- platforms/nuttx/CMakeLists.txt | 3 + platforms/nuttx/NuttX/nuttx | 2 +- platforms/nuttx/cmake/px4_impl_os.cmake | 3 + .../src/bootloader/nxp/imxrt_common/main.c | 112 ++- .../src/bootloader/nxp/rt106x/CMakeLists.txt | 34 + .../px4/nxp/imxrt/board_reset/CMakeLists.txt | 2 - .../px4/nxp/imxrt/board_reset/board_reset.cpp | 17 +- .../px4_arch/imxrt_flexspi_nor_flash.h | 17 +- .../nxp/imxrt/include/px4_arch/imxrt_romapi.h | 6 + .../src/px4/nxp/imxrt/romapi/imxrt_romapi.c | 79 +- .../px4/nxp/imxrt/version/board_mcu_version.c | 3 +- .../nuttx/src/px4/nxp/rt106x/CMakeLists.txt | 2 + .../rt106x/include/px4_arch/hw_description.h | 4 +- .../px4_arch/imxrt_flexspi_nor_flash.h | 36 + .../rt106x/include/px4_arch/imxrt_romapi.h | 36 + .../px4_arch/io_timer_hw_description.h | 4 +- .../include/px4_arch/spi_hw_description.h | 105 ++- 55 files changed, 5972 insertions(+), 30 deletions(-) create mode 100644 boards/nxp/mr-tropic/bootloader.px4board create mode 100644 boards/nxp/mr-tropic/cmake/upload.cmake create mode 100644 boards/nxp/mr-tropic/default.px4board create mode 100755 boards/nxp/mr-tropic/extras/nxp_mr-tropic_bootloader.bin create mode 100644 boards/nxp/mr-tropic/firmware.prototype create mode 100644 boards/nxp/mr-tropic/init/rc.board_defaults create mode 100644 boards/nxp/mr-tropic/init/rc.board_mavlink create mode 100644 boards/nxp/mr-tropic/init/rc.board_sensors create mode 100644 boards/nxp/mr-tropic/nuttx-config/Kconfig create mode 100644 boards/nxp/mr-tropic/nuttx-config/bootloader/defconfig create mode 100644 boards/nxp/mr-tropic/nuttx-config/include/board.h create mode 100644 boards/nxp/mr-tropic/nuttx-config/nsh/defconfig create mode 100644 boards/nxp/mr-tropic/nuttx-config/scripts/bootloader_script.ld create mode 100644 boards/nxp/mr-tropic/nuttx-config/scripts/itcm_functions_includes.ld create mode 100644 boards/nxp/mr-tropic/nuttx-config/scripts/itcm_static_functions.ld create mode 100644 boards/nxp/mr-tropic/nuttx-config/scripts/script.ld create mode 100644 boards/nxp/mr-tropic/src/CMakeLists.txt create mode 100644 boards/nxp/mr-tropic/src/board_config.h create mode 100644 boards/nxp/mr-tropic/src/bootloader_main.c create mode 100644 boards/nxp/mr-tropic/src/hw_config.h create mode 100644 boards/nxp/mr-tropic/src/hw_rev_ver_tropic.c create mode 100644 boards/nxp/mr-tropic/src/i2c.cpp create mode 100644 boards/nxp/mr-tropic/src/imxrt_flexspi_nor_boot.c create mode 100644 boards/nxp/mr-tropic/src/imxrt_flexspi_nor_boot.h create mode 100644 boards/nxp/mr-tropic/src/imxrt_flexspi_nor_flash.c create mode 100644 boards/nxp/mr-tropic/src/imxrt_flexspi_nor_flash.h create mode 100644 boards/nxp/mr-tropic/src/imxrt_flexspi_storage.c create mode 100644 boards/nxp/mr-tropic/src/imxrt_ocram_initialize.c create mode 100644 boards/nxp/mr-tropic/src/init.c create mode 100644 boards/nxp/mr-tropic/src/manifest.c create mode 100644 boards/nxp/mr-tropic/src/sdhc.c create mode 100644 boards/nxp/mr-tropic/src/spi.cpp create mode 100644 boards/nxp/mr-tropic/src/timer_config.cpp create mode 100644 boards/nxp/mr-tropic/src/tropic_led_pwm.cpp create mode 100644 boards/nxp/mr-tropic/src/usb.c create mode 100644 platforms/nuttx/src/bootloader/nxp/rt106x/CMakeLists.txt create mode 100644 platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/imxrt_flexspi_nor_flash.h create mode 100644 platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/imxrt_romapi.h diff --git a/.github/workflows/itcm_check.yml b/.github/workflows/itcm_check.yml index 5a1b0ecddc..767f69aa7c 100644 --- a/.github/workflows/itcm_check.yml +++ b/.github/workflows/itcm_check.yml @@ -41,6 +41,10 @@ jobs: scripts: > boards/nxp/tropic-community/nuttx-config/scripts/itcm_functions_includes.ld boards/nxp/tropic-community/nuttx-config/scripts/itcm_static_functions.ld + - target: nxp_mr-tropic + scripts: > + boards/nxp/mr-tropic/nuttx-config/scripts/itcm_functions_includes.ld + boards/nxp/mr-tropic/nuttx-config/scripts/itcm_static_functions.ld steps: - uses: actions/checkout@v4 with: diff --git a/.vscode/cmake-variants.yaml b/.vscode/cmake-variants.yaml index b80cdb73c8..71aec979d4 100644 --- a/.vscode/cmake-variants.yaml +++ b/.vscode/cmake-variants.yaml @@ -481,6 +481,16 @@ CONFIG: buildType: MinSizeRel settings: CONFIG: nxp_mr-canhubk3_fmu + nxp_mr-tropic_default: + short: nxp_mr-tropic_default + buildType: MinSizeRel + settings: + CONFIG: nxp_mr-tropic_default + nxp_mr-tropic_bootloader: + short: nxp_mr-tropic_bootloader + buildType: MinSizeRel + settings: + CONFIG: nxp_mr-tropic_bootloader nxp_tropic-community_default: short: nxp_tropic-community_default buildType: MinSizeRel diff --git a/boards/nxp/mr-tropic/bootloader.px4board b/boards/nxp/mr-tropic/bootloader.px4board new file mode 100644 index 0000000000..19b6e662be --- /dev/null +++ b/boards/nxp/mr-tropic/bootloader.px4board @@ -0,0 +1,3 @@ +CONFIG_BOARD_TOOLCHAIN="arm-none-eabi" +CONFIG_BOARD_ARCHITECTURE="cortex-m7" +CONFIG_BOARD_ROMFSROOT="" diff --git a/boards/nxp/mr-tropic/cmake/upload.cmake b/boards/nxp/mr-tropic/cmake/upload.cmake new file mode 100644 index 0000000000..79da5c60fd --- /dev/null +++ b/boards/nxp/mr-tropic/cmake/upload.cmake @@ -0,0 +1,44 @@ +############################################################################ +# +# Copyright (c) 2024 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. +# +############################################################################ + + +set(PX4_FW_NAME ${PX4_BINARY_DIR}/${PX4_BOARD_VENDOR}_${PX4_BOARD_MODEL}_${PX4_BOARD_LABEL}.hex) + +add_custom_target(upload_teensy + COMMAND ${PYTHON_EXECUTABLE} ${PX4_SOURCE_DIR}/Tools/teensy_uploader.py --port ${serial_ports} ${PX4_FW_NAME} --vendor-id 0x1FC9 --product-id 0x0024 + DEPENDS ${PX4_FW_NAME} + COMMENT "uploading px4" + VERBATIM + USES_TERMINAL + WORKING_DIRECTORY ${PX4_BINARY_DIR} +) diff --git a/boards/nxp/mr-tropic/default.px4board b/boards/nxp/mr-tropic/default.px4board new file mode 100644 index 0000000000..2d4888e1aa --- /dev/null +++ b/boards/nxp/mr-tropic/default.px4board @@ -0,0 +1,109 @@ +CONFIG_BOARD_TOOLCHAIN="arm-none-eabi" +CONFIG_BOARD_ARCHITECTURE="cortex-m7" +CONFIG_BOARD_ETHERNET=y +CONFIG_BOARD_SERIAL_GPS1="/dev/ttyS1" +CONFIG_BOARD_SERIAL_TEL1="/dev/ttyS2" +CONFIG_BOARD_SERIAL_TEL2="/dev/ttyS4" +CONFIG_BOARD_SERIAL_TEL3="/dev/ttyS3" +CONFIG_BOARD_SERIAL_RC="/dev/ttyS6" +CONFIG_BOARD_PARAM_FILE="/fs/nor/mtd_params" +CONFIG_DRIVERS_ADC_BOARD_ADC=y +CONFIG_DRIVERS_BAROMETER_BMP388=y +CONFIG_DRIVERS_BAROMETER_INVENSENSE_ICP201XX=y +CONFIG_DRIVERS_BAROMETER_MS5611=y +CONFIG_DRIVERS_CAMERA_CAPTURE=y +CONFIG_DRIVERS_CAMERA_TRIGGER=y +CONFIG_DRIVERS_CDCACM_AUTOSTART=y +CONFIG_COMMON_DIFFERENTIAL_PRESSURE=y +CONFIG_COMMON_DISTANCE_SENSOR=y +CONFIG_DRIVERS_DISTANCE_SENSOR_LIGHTWARE_SF45_SERIAL=y +CONFIG_DRIVERS_DSHOT=y +CONFIG_DRIVERS_GNSS_SEPTENTRIO=y +CONFIG_DRIVERS_GPS=y +CONFIG_DRIVERS_IMU_BOSCH_BMI088=y +CONFIG_DRIVERS_IMU_INVENSENSE_ICM20948=y +CONFIG_DRIVERS_IMU_INVENSENSE_ICM42688P=y +CONFIG_DRIVERS_IMU_INVENSENSE_ICM45686=y +CONFIG_COMMON_INS=y +CONFIG_COMMON_LIGHT=y +CONFIG_DRIVERS_LIGHTS_RGBLED_PWM=y +CONFIG_COMMON_MAGNETOMETER=y +CONFIG_DRIVERS_MAGNETOMETER_BOSCH_BMM350=y +CONFIG_COMMON_OPTICAL_FLOW=y +CONFIG_DRIVERS_OSD_MSP_OSD=y +CONFIG_DRIVERS_POWER_MONITOR_INA226=y +CONFIG_DRIVERS_POWER_MONITOR_INA228=y +CONFIG_DRIVERS_POWER_MONITOR_INA238=y +CONFIG_DRIVERS_PWM_OUT=y +CONFIG_COMMON_RC=y +CONFIG_DRIVERS_SAFETY_BUTTON=y +CONFIG_COMMON_TELEMETRY=y +CONFIG_DRIVERS_TONE_ALARM=y +CONFIG_DRIVERS_UAVCAN=y +CONFIG_BOARD_UAVCAN_INTERFACES=1 +CONFIG_COMMON_UWB=y +CONFIG_MODULES_AIRSPEED_SELECTOR=y +CONFIG_MODULES_BATTERY_STATUS=y +CONFIG_MODULES_CAMERA_FEEDBACK=y +CONFIG_MODULES_COMMANDER=y +CONFIG_MODULES_CONTROL_ALLOCATOR=y +CONFIG_MODULES_DATAMAN=y +CONFIG_MODULES_EKF2=y +CONFIG_MODULES_ESC_BATTERY=y +CONFIG_MODULES_EVENTS=y +CONFIG_MODULES_FLIGHT_MODE_MANAGER=y +CONFIG_MODULES_FW_ATT_CONTROL=y +CONFIG_MODULES_FW_AUTOTUNE_ATTITUDE_CONTROL=y +CONFIG_MODULES_FW_MODE_MANAGER=y +CONFIG_MODULES_FW_LATERAL_LONGITUDINAL_CONTROL=y +CONFIG_MODULES_FW_RATE_CONTROL=y +CONFIG_MODULES_GIMBAL=y +CONFIG_MODULES_GYRO_CALIBRATION=y +CONFIG_MODULES_GYRO_FFT=y +CONFIG_MODULES_LAND_DETECTOR=y +CONFIG_MODULES_LANDING_TARGET_ESTIMATOR=y +CONFIG_MODULES_LOAD_MON=y +CONFIG_MODULES_LOCAL_POSITION_ESTIMATOR=y +CONFIG_MODULES_LOGGER=y +CONFIG_MODULES_MAG_BIAS_ESTIMATOR=y +CONFIG_MODULES_MANUAL_CONTROL=y +CONFIG_MODULES_MAVLINK=y +CONFIG_MODULES_MC_ATT_CONTROL=y +CONFIG_MODULES_MC_AUTOTUNE_ATTITUDE_CONTROL=y +CONFIG_MODULES_MC_HOVER_THRUST_ESTIMATOR=y +CONFIG_MODULES_MC_POS_CONTROL=y +CONFIG_MODULES_MC_RATE_CONTROL=y +CONFIG_MODULES_NAVIGATOR=y +CONFIG_MODE_NAVIGATOR_VTOL_TAKEOFF=y +CONFIG_NUM_MISSION_ITMES_SUPPORTED=1000 +CONFIG_MODULES_RC_UPDATE=y +CONFIG_MODULES_ROVER_POS_CONTROL=y +CONFIG_MODULES_SENSORS=y +CONFIG_MODULES_TEMPERATURE_COMPENSATION=y +CONFIG_MODULES_UXRCE_DDS_CLIENT=y +CONFIG_MODULES_VTOL_ATT_CONTROL=y +CONFIG_MODULES_ZENOH=y +CONFIG_SYSTEMCMDS_ACTUATOR_TEST=y +CONFIG_SYSTEMCMDS_BSONDUMP=y +CONFIG_SYSTEMCMDS_DMESG=y +CONFIG_SYSTEMCMDS_DUMPFILE=y +CONFIG_SYSTEMCMDS_I2C_LAUNCHER=y +CONFIG_SYSTEMCMDS_I2CDETECT=y +CONFIG_SYSTEMCMDS_LED_CONTROL=y +CONFIG_SYSTEMCMDS_MFT=y +CONFIG_SYSTEMCMDS_NETMAN=y +CONFIG_SYSTEMCMDS_NSHTERM=y +CONFIG_SYSTEMCMDS_PARAM=y +CONFIG_SYSTEMCMDS_PERF=y +CONFIG_SYSTEMCMDS_REBOOT=y +CONFIG_SYSTEMCMDS_SD_BENCH=y +CONFIG_SYSTEMCMDS_SD_STRESS=y +CONFIG_SYSTEMCMDS_SERIAL_TEST=y +CONFIG_SYSTEMCMDS_SYSTEM_TIME=y +CONFIG_SYSTEMCMDS_TOP=y +CONFIG_SYSTEMCMDS_TOPIC_LISTENER=y +CONFIG_SYSTEMCMDS_TUNE_CONTROL=y +CONFIG_SYSTEMCMDS_UORB=y +CONFIG_SYSTEMCMDS_USB_CONNECTED=y +CONFIG_SYSTEMCMDS_VER=y +CONFIG_SYSTEMCMDS_WORK_QUEUE=y diff --git a/boards/nxp/mr-tropic/extras/nxp_mr-tropic_bootloader.bin b/boards/nxp/mr-tropic/extras/nxp_mr-tropic_bootloader.bin new file mode 100755 index 0000000000000000000000000000000000000000..c972de6405bf4a97c4292b4180ef567fb66b7346 GIT binary patch literal 74376 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 + * David Sidrane + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ + +#ifndef __NUTTX_CONFIG_NXP_TROPIC_INCLUDE_BOARD_H +#define __NUTTX_CONFIG_NXP_TROPIC_INCLUDE_BOARD_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +/* Clocking *************************************************************************/ + +/* Set VDD_SOC to 1.25V */ + +#define IMXRT_VDD_SOC (0x12) + +/* Set Arm PLL (PLL1) to fOut = (24Mhz * ARM_PLL_DIV_SELECT/2) / ARM_PODF_DIVISOR + * 576Mhz = (24Mhz * ARM_PLL_DIV_SELECT/2) / ARM_PODF_DIVISOR + * ARM_PLL_DIV_SELECT = 96 + * ARM_PODF_DIVISOR = 2 + * 576Mhz = (24Mhz * 96/2) / 2 + * + * AHB_CLOCK_ROOT = PLL1fOut / IMXRT_AHB_PODF_DIVIDER + * 1Hz to 600 Mhz = 576Mhz / IMXRT_ARM_CLOCK_DIVIDER + * IMXRT_ARM_CLOCK_DIVIDER = 1 + * 576Mhz = 576Mhz / 1 + * + * PRE_PERIPH_CLK_SEL = PRE_PERIPH_CLK_SEL_PLL1 + * PERIPH_CLK_SEL = 1 (0 select PERIPH_CLK2_PODF, 1 select PRE_PERIPH_CLK_SEL_PLL1) + * PERIPH_CLK = 576Mhz + * + * IPG_CLOCK_ROOT = AHB_CLOCK_ROOT / IMXRT_IPG_PODF_DIVIDER + * IMXRT_IPG_PODF_DIVIDER = 4 + * 144Mhz = 576Mhz / 4 + * + * PRECLK_CLOCK_ROOT = IPG_CLOCK_ROOT / IMXRT_PERCLK_PODF_DIVIDER + * IMXRT_PERCLK_PODF_DIVIDER = 1 + * 16Mhz = 144Mhz / 9 + * + * SEMC_CLK_ROOT = 576Mhz / IMXRT_SEMC_PODF_DIVIDER (labeled AIX_PODF in 18.2) + * IMXRT_SEMC_PODF_DIVIDER = 8 + * 72Mhz = 576Mhz / 8 + * + * Set Sys PLL (PLL2) to fOut = (24Mhz * (20+(2*(DIV_SELECT))) + * 528Mhz = (24Mhz * (20+(2*(1))) + * + * Set USB1 PLL (PLL3) to fOut = (24Mhz * 20) + * 480Mhz = (24Mhz * 20) + * + * Set LPSPI PLL3 PFD0 to fOut = (480Mhz / 12 * 18) + * 720Mhz = (480Mhz / 12 * 18) + * 90Mhz = (720Mhz / LSPI_PODF_DIVIDER) + * + * Set LPI2C PLL3 / 8 to fOut = (480Mhz / 8) + * 60Mhz = (480Mhz / 8) + * 12Mhz = (60Mhz / LSPI_PODF_DIVIDER) + * + * Set USDHC1 PLL2 PFD2 to fOut = (528Mhz / 24 * 18) + * 396Mhz = (528Mhz / 24 * 18) + * 198Mhz = (396Mhz / IMXRT_USDHC1_PODF_DIVIDER) + */ + +#define BOARD_XTAL_FREQUENCY 24000000 +#define IMXRT_PRE_PERIPH_CLK_SEL CCM_CBCMR_PRE_PERIPH_CLK_SEL_PLL1 +#define IMXRT_PERIPH_CLK_SEL CCM_CBCDR_PERIPH_CLK_SEL_PRE_PERIPH +#define IMXRT_ARM_PLL_DIV_SELECT 96 +#define IMXRT_ARM_PODF_DIVIDER 2 +#define IMXRT_AHB_PODF_DIVIDER 1 +#define IMXRT_IPG_PODF_DIVIDER 4 +#define IMXRT_PERCLK_CLK_SEL CCM_CSCMR1_PERCLK_CLK_SEL_IPG_CLK_ROOT +#define IMXRT_PERCLK_PODF_DIVIDER 9 +#define IMXRT_SEMC_PODF_DIVIDER 8 +#define IMXRT_CAN_CLK_SELECT CCM_CSCMR2_CAN_CLK_SEL_PLL3_SW_80 +#define IMXRT_CAN_PODF_DIVIDER 1 + +#define IMXRT_LPSPI_CLK_SELECT CCM_CBCMR_LPSPI_CLK_SEL_PLL3_PFD0 +#define IMXRT_LSPI_PODF_DIVIDER 8 + +#define IMXRT_LPI2C_CLK_SELECT CCM_CSCDR2_LPI2C_CLK_SEL_PLL3_60M +#define IMXRT_LSI2C_PODF_DIVIDER 5 + +#define IMXRT_USDHC1_CLK_SELECT CCM_CSCMR1_USDHC1_CLK_SEL_PLL2_PFD0 +#define IMXRT_USDHC1_PODF_DIVIDER 2 + +#define IMXRT_USB1_PLL_DIV_SELECT CCM_ANALOG_PLL_USB1_DIV_SELECT_20 + +#define IMXRT_SYS_PLL_SELECT CCM_ANALOG_PLL_SYS_DIV_SELECT_22 + +#define IMXRT_USB1_PLL_DIV_SELECT CCM_ANALOG_PLL_USB1_DIV_SELECT_20 + +#define BOARD_CPU_FREQUENCY \ + (BOARD_XTAL_FREQUENCY * (IMXRT_ARM_PLL_DIV_SELECT / 2)) / IMXRT_ARM_PODF_DIVIDER + +#define BOARD_GPT_FREQUENCY \ + (BOARD_CPU_FREQUENCY / IMXRT_IPG_PODF_DIVIDER) / IMXRT_PERCLK_PODF_DIVIDER + + +/* 108Mhz clock for FlexIO using PLL3 PFD2 @ 520 */ +#define CONFIG_FLEXIO1_CLK 1 +#define CONFIG_FLEXIO1_PRED_DIVIDER 5 +#define CONFIG_FLEXIO1_PODF_DIVIDER 1 +#define CONFIG_PLL3_PFD2_FRAC 16 +#define BOARD_FLEXIO_PREQ 108000000 + +/* Define this to enable tracing */ +#if CONFIG_USE_TRACE +# define IMXRT_TRACE_PODF_DIVIDER 1 +# define IMXRT_TRACE_CLK_SELECT CCM_CBCMR_TRACE_CLK_SEL_PLL2_PFD0 +#endif + +/* SDIO *****************************************************************************/ + +/* Pin drive characteristics */ + +#define USDHC1_DATAX_IOMUX (IOMUX_SLEW_FAST | IOMUX_DRIVE_130OHM | IOMUX_PULL_UP_47K | IOMUX_SCHMITT_TRIGGER) +#define USDHC1_CMD_IOMUX (IOMUX_SLEW_FAST | IOMUX_DRIVE_130OHM | IOMUX_PULL_UP_47K | IOMUX_SCHMITT_TRIGGER) +#define USDHC1_CLK_IOMUX (IOMUX_SLEW_FAST | IOMUX_DRIVE_130OHM | IOMUX_SPEED_MAX) +#define USDHC1_CD_IOMUX (IOMUX_PULL_UP_47K | IOMUX_SCHMITT_TRIGGER) + +#define PIN_USDHC1_D0 (GPIO_USDHC1_DATA0_1 | USDHC1_DATAX_IOMUX) /* GPIO_SD_B0_02 */ +#define PIN_USDHC1_D1 (GPIO_USDHC1_DATA1_1 | USDHC1_DATAX_IOMUX) /* GPIO_SD_B0_03 */ +#define PIN_USDHC1_D2 (GPIO_USDHC1_DATA2_1 | USDHC1_DATAX_IOMUX) /* GPIO_SD_B0_04 */ +#define PIN_USDHC1_D3 (GPIO_USDHC1_DATA3_1 | USDHC1_DATAX_IOMUX) /* GPIO_SD_B0_05 */ +#define PIN_USDHC1_DCLK (GPIO_USDHC1_CLK_1 | USDHC1_CLK_IOMUX) /* GPIO_SD_B0_01 */ +#define PIN_USDHC1_CMD (GPIO_USDHC1_CMD_1 | USDHC1_CMD_IOMUX) /* GPIO_SD_B0_00 */ +#define PIN_USDHC1_CD (PIN_USDHC1_D3) + +/* #define PIN_USDHC1_CD (GPIO_USDHC1_CD_3 | USDHC1_CD_IOMUX) + * CD_B Pin works fine but somehow the driver has a timing issue with + * Thus use D3 instead + */ + +/* Ideal 400Khz for initial inquiry. + * Given input clock 198 Mhz. + * 386.71875 KHz = 198 Mhz / (256 * 2) + */ + +#define BOARD_USDHC_IDMODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV256 +#define BOARD_USDHC_IDMODE_DIVISOR USDHC_SYSCTL_DVS_DIV(2) + +/* Ideal 25 Mhz for other modes + * Given input clock 198 Mhz. + * 24.75 MHz = 198 Mhz / (8 * 1) + */ + +#define BOARD_USDHC_MMCMODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV8 +#define BOARD_USDHC_MMCMODE_DIVISOR USDHC_SYSCTL_DVS_DIV(1) + +#define BOARD_USDHC_SD1MODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV8 +#define BOARD_USDHC_SD1MODE_DIVISOR USDHC_SYSCTL_DVS_DIV(1) + +#define BOARD_USDHC_SD4MODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV8 +#define BOARD_USDHC_SD4MODE_DIVISOR USDHC_SYSCTL_DVS_DIV(1) + +/* ETH Disambiguation *******************************************************/ + +/* Ethernet Interrupt: GPIO_B0_15 + * + * This pin has a week pull-up within the PHY, is open-drain, and requires + * an external 1k ohm pull-up resistor (present on the EVK). A falling + * edge then indicates a change in state of the PHY. + */ + +#define GPIO_ENET_INT (IOMUX_ENET_INT_DEFAULT | \ + GPIO_PORT2 | GPIO_PIN15) /* B0_15 */ +#define GPIO_ENET_IRQ IMXRT_IRQ_GPIO2_15 + +/* Ethernet Reset: GPIO_B0_14 + * + * The #RST uses inverted logic. The initial value of zero will put the + * PHY into the reset state. + */ + +#define GPIO_ENET_RST (GPIO_OUTPUT | GPIO_OUTPUT_ZERO | \ + GPIO_PORT2 | GPIO_PIN14 | IOMUX_ENET_RST_DEFAULT) /* B0_14 */ + +#define GPIO_ENET_TX_DATA00 (GPIO_ENET_TX_DATA00_1| \ + IOMUX_ENET_DATA_DEFAULT) /* GPIO_B1_07 */ +#define GPIO_ENET_TX_DATA01 (GPIO_ENET_TX_DATA01_1| \ + IOMUX_ENET_DATA_DEFAULT) /* GPIO_B1_08 */ +#define GPIO_ENET_RX_DATA00 (GPIO_ENET_RX_DATA00_1| \ + IOMUX_ENET_DATA_DEFAULT) /* GPIO_B1_04 */ +#define GPIO_ENET_RX_DATA01 (GPIO_ENET_RX_DATA01_1| \ + IOMUX_ENET_DATA_DEFAULT) /* GPIO_B1_05 */ +#define GPIO_ENET_MDIO (GPIO_ENET_MDIO_1|IOMUX_ENET_MDIO_DEFAULT) /* GPIO_B1_15 */ +#define GPIO_ENET_MDC (GPIO_ENET_MDC_1|IOMUX_ENET_MDC_DEFAULT) /* GPIO_B1_14 */ +#define GPIO_ENET_RX_EN (GPIO_ENET_RX_EN_1|IOMUX_ENET_EN_DEFAULT) /* GPIO_B1_06 */ +#define GPIO_ENET_RX_ER (GPIO_ENET_RX_ER_1|IOMUX_ENET_RXERR_DEFAULT) /* GPIO_B1_11 */ +#define GPIO_ENET_TX_CLK (GPIO_ENET_REF_CLK_2|\ + IOMUX_ENET_TX_CLK_DEFAULT) /* GPIO_B1_10 */ +#define GPIO_ENET_TX_EN (GPIO_ENET_TX_EN_1|IOMUX_ENET_EN_DEFAULT) /* GPIO_B1_09 */ + +/* LED definitions ******************************************************************/ +/* The nxp fmutr1062 board has numerous LEDs but only three, LED_GREEN a Green LED, + * LED_BLUE a Blue LED and LED_RED a Red LED, that can be controlled by software. + * + * If CONFIG_ARCH_LEDS is not defined, then the user can control the LEDs in any way. + * The following definitions are used to access individual LEDs. + */ + +/* LED index values for use with board_userled() */ + +#define BOARD_LED1 0 +#define BOARD_LED2 1 +#define BOARD_LED3 2 +#define BOARD_NLEDS 3 + +#define BOARD_LED_RED BOARD_LED1 +#define BOARD_LED_GREEN BOARD_LED2 +#define BOARD_LED_BLUE BOARD_LED3 + +/* LED bits for use with board_userled_all() */ + +#define BOARD_LED1_BIT (1 << BOARD_LED1) +#define BOARD_LED2_BIT (1 << BOARD_LED2) +#define BOARD_LED3_BIT (1 << BOARD_LED3) + +/* If CONFIG_ARCH_LEDS is defined, the usage by the board port is defined in + * include/board.h and src/stm32_leds.c. The LEDs are used to encode OS-related + * events as follows: + * + * + * SYMBOL Meaning LED state + * Red Green Blue + * ---------------------- -------------------------- ------ ------ ----*/ + +#define LED_STARTED 0 /* NuttX has been started OFF OFF OFF */ +#define LED_HEAPALLOCATE 1 /* Heap has been allocated OFF OFF ON */ +#define LED_IRQSENABLED 2 /* Interrupts enabled OFF ON OFF */ +#define LED_STACKCREATED 3 /* Idle stack created OFF ON ON */ +#define LED_INIRQ 4 /* In an interrupt N/C N/C GLOW */ +#define LED_SIGNAL 5 /* In a signal handler N/C GLOW N/C */ +#define LED_ASSERTION 6 /* An assertion failed GLOW N/C GLOW */ +#define LED_PANIC 7 /* The system has crashed Blink OFF N/C */ +#define LED_IDLE 8 /* MCU is is sleep mode ON OFF OFF */ + +/* Thus if the Green LED is statically on, NuttX has successfully booted and + * is, apparently, running normally. If the Red LED is flashing at + * approximately 2Hz, then a fatal error has been detected and the system + * has halted. + */ + +/* PIO Disambiguation ***************************************************************/ +/* LPUARTs + */ +#define LPUART_IOMUX (IOMUX_PULL_UP_22K | IOMUX_DRIVE_40OHM | IOMUX_SLEW_SLOW | IOMUX_SPEED_LOW | IOMUX_SCHMITT_TRIGGER) +#define IOMUX_UART_CTS_DEFAULT (IOMUX_PULL_DOWN_100K | IOMUX_DRIVE_40OHM | IOMUX_SLEW_SLOW) + +/* Debug */ + +#define GPIO_LPUART6_RX (GPIO_LPUART6_RX_2 | LPUART_IOMUX) /* GPIO_EMC_26 */ +#define GPIO_LPUART6_TX (GPIO_LPUART6_TX_2 | LPUART_IOMUX) /* GPIO_EMC_25 */ + + +/* Telem 2 */ + +#define GPIO_LPUART5_RX (GPIO_LPUART5_RX_1 | LPUART_IOMUX) /* GPIO_B1_13 */ +#define GPIO_LPUART5_TX (GPIO_LPUART5_TX_1 | LPUART_IOMUX) /* GPIO_B1_12 */ +#define GPIO_LPUART5_CTS (GPIO_LPUART5_CTS_1 | IOMUX_UART_CTS_DEFAULT | PADMUX_SION) /* GPIO_EMC_28 GPIO4_IO27 */ +#define GPIO_LPUART5_RTS (GPIO_PORT4 | GPIO_PIN27 | GPIO_OUTPUT | GPIO_OUTPUT_ZERO | IOMUX_UART_DEFAULT) /* GPIO_EMC_27 GPIO4_IO27 (GPIO only, no HW Flow control) */ + +/* AUX */ + +#define GPIO_LPUART4_RX (GPIO_LPUART4_RX_1 | LPUART_IOMUX) /* GPIO_B1_01 */ +#define GPIO_LPUART4_TX (GPIO_LPUART4_TX_1 | LPUART_IOMUX) /* GPIO_B1_00 */ +#define GPIO_LPUART4_CTS (GPIO_PORT1 | GPIO_PIN15 | GPIO_INPUT | PADMUX_SION | IOMUX_UART_CTS_DEFAULT) /* GPIO_AD_B0_15 GPIO1_IO14 (Fixme Add GPIO Flow support in LPUART) */ +#define GPIO_LPUART4_RTS (GPIO_PORT1 | GPIO_PIN14 | GPIO_OUTPUT | GPIO_OUTPUT_ZERO | IOMUX_UART_DEFAULT) /* GPIO_AD_B0_14 GPIO1_IO14 (GPIO only, no HW Flow control) */ + +/* GPS 1 */ + +#define GPIO_LPUART2_RX (GPIO_LPUART2_RX_1 | LPUART_IOMUX) /* GPIO_AD_B1_03 */ +#define GPIO_LPUART2_TX (GPIO_LPUART2_TX_1 | LPUART_IOMUX) /* GPIO_AD_B1_02 */ + +/* Telem 1 */ + +#define GPIO_LPUART3_RX (GPIO_LPUART3_RX_1 | LPUART_IOMUX) /* GPIO_AD_B1_07 */ +#define GPIO_LPUART3_TX (GPIO_LPUART3_TX_1 | LPUART_IOMUX) /* GPIO_AD_B1_06 */ +#define GPIO_LPUART3_CTS (GPIO_LPUART3_CTS_1 | IOMUX_UART_CTS_DEFAULT | PADMUX_SION) /* GPIO_AD_B1_04 GPIO1_IO20 */ +#define GPIO_LPUART3_RTS (GPIO_PORT1 | GPIO_PIN21 | GPIO_OUTPUT | GPIO_OUTPUT_ZERO | IOMUX_UART_DEFAULT) /* GPIO_AD_B1_05 GPIO1_IO21 (GPIO only, no HW Flow control) */ +//TODO check RT7 partial HW handshake + +/* ESC ONEWIRE */ +#define GPIO_LPUART7_RX (GPIO_LPUART7_TX_1 | LPUART_IOMUX) /* GPIO_EMC_31 */ +#define GPIO_LPUART7_TX (GPIO_LPUART7_TX_1 | LPUART_IOMUX) /* GPIO_EMC_31 */ + + +/* RC INPUT single wire mode on Input on TX, for CRSF use TX and RX */ + +#define GPIO_LPUART8_RX (GPIO_LPUART8_RX_1 | LPUART_IOMUX) /* GPIO_AD_B1_11 */ +#define GPIO_LPUART8_TX (GPIO_LPUART8_TX_1 | LPUART_IOMUX) /* GPIO_AD_B1_10 */ + +/* CAN + * + * CAN1 is routed to transceiver. + * CAN2 is routed to transceiver. + * CAN3 is routed to transceiver. + */ +#define FLEXCAN_IOMUX (IOMUX_PULL_UP_100K | IOMUX_DRIVE_40OHM | IOMUX_SLEW_FAST | IOMUX_SPEED_MEDIUM) + +#define GPIO_FLEXCAN3_RX (GPIO_FLEXCAN3_RX_3 | FLEXCAN_IOMUX) /* GPIO_EMC_37 */ +#define GPIO_FLEXCAN3_TX (GPIO_FLEXCAN3_TX_3 | FLEXCAN_IOMUX) /* GPIO_EMC_36 */ + +/* LPSPI */ +#define LPSPI_IOMUX (IOMUX_PULL_UP_100K | IOMUX_DRIVE_33OHM | IOMUX_SLEW_FAST | IOMUX_SPEED_MAX) + + +#define GPIO_LPSPI3_SCK (GPIO_LPSPI3_SCK_1 | LPSPI_IOMUX) /* GPIO_AD_B1_15 */ +#define GPIO_LPSPI3_MISO (GPIO_LPSPI3_SDI_1 | LPSPI_IOMUX) /* GPIO_AD_B1_13 */ +#define GPIO_LPSPI3_MOSI (GPIO_LPSPI3_SDO_1 | LPSPI_IOMUX) /* GPIO_AD_B1_14 */ + +#define GPIO_LPSPI4_SCK (GPIO_LPSPI4_SCK_2 | LPSPI_IOMUX) /* GPIO_B0_03 */ +#define GPIO_LPSPI4_MISO (GPIO_LPSPI4_SDI_2 | LPSPI_IOMUX) /* GPIO_B0_01 */ +#define GPIO_LPSPI4_MOSI (GPIO_LPSPI4_SDO_2 | LPSPI_IOMUX) /* GPIO_B0_02 */ + +#define BOARD_SPI_BUS_MAX_BUS_ITEMS 2 + +/* LPI2Cs */ + +#define LPI2C_IOMUX (IOMUX_SPEED_MEDIUM | IOMUX_DRIVE_33OHM | IOMUX_OPENDRAIN | GPIO_SION_ENABLE) +#define LPI2C_IO_IOMUX (IOMUX_SPEED_MAX | IOMUX_SLEW_FAST | IOMUX_DRIVE_33OHM | IOMUX_OPENDRAIN | IOMUX_PULL_NONE) + +#define GPIO_LPI2C1_SDA (GPIO_LPI2C1_SDA_2 | LPI2C_IOMUX) /* EVK J24-9 R276 */ /* GPIO_AD_B1_01 */ +#define GPIO_LPI2C1_SCL (GPIO_LPI2C1_SCL_2 | LPI2C_IOMUX) /* EVK J24-10 R277 */ /* GPIO_AD_B1_00 */ + +#define GPIO_LPI2C1_SDA_RESET (GPIO_PORT1 | GPIO_PIN17 | GPIO_OUTPUT | GPIO_OUTPUT_ONE | LPI2C_IO_IOMUX) /* GPIO_AD_B1_01 GPIO1_IO17 */ +#define GPIO_LPI2C1_SCL_RESET (GPIO_PORT1 | GPIO_PIN16 | GPIO_OUTPUT | GPIO_OUTPUT_ONE | LPI2C_IO_IOMUX) /* GPIO_AD_B1_00 GPIO1_IO16 */ + +#define GPIO_LPI2C3_SDA (GPIO_LPI2C3_SDA_2 | LPI2C_IOMUX) /* GPIO_EMC_21 */ +#define GPIO_LPI2C3_SCL (GPIO_LPI2C3_SCL_2 | LPI2C_IOMUX) /* GPIO_EMC_22 */ + +#define GPIO_LPI2C3_SDA_RESET (GPIO_PORT4 | GPIO_PIN21 | GPIO_OUTPUT | GPIO_OUTPUT_ONE | LPI2C_IO_IOMUX) /* GPIO_EMC_21 */ +#define GPIO_LPI2C3_SCL_RESET (GPIO_PORT4 | GPIO_PIN22 | GPIO_OUTPUT | GPIO_OUTPUT_ONE | LPI2C_IO_IOMUX) /* GPIO_EMC_22 */ + +#define GPIO_LPI2C4_SDA (GPIO_LPI2C4_SDA_1 | LPI2C_IOMUX) /* GPIO_AD_B0_13 */ +#define GPIO_LPI2C4_SCL (GPIO_LPI2C4_SCL_1 | LPI2C_IOMUX) /* GPIO_AD_B0_12 */ + +#define GPIO_LPI2C4_SDA_RESET (GPIO_PORT1 | GPIO_PIN13 | GPIO_OUTPUT | GPIO_OUTPUT_ONE | LPI2C_IO_IOMUX) /* GPIO_AD_B0_13 */ +#define GPIO_LPI2C4_SCL_RESET (GPIO_PORT1 | GPIO_PIN12 | GPIO_OUTPUT | GPIO_OUTPUT_ONE | LPI2C_IO_IOMUX) /* GPIO_AD_B0_12 */ + +#define BOARD_PHY_ADDR (18) + +/* Board doesn't provide GPIO or other Hardware for signaling to timing analyzer */ + +#define PROBE_INIT(mask) +#define PROBE(n,s) +#define PROBE_MARK(n) + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +/************************************************************************************ + * Public Data + ************************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __NUTTX_CONFIG_NXP_TROPIC_INCLUDE_BOARD_H */ diff --git a/boards/nxp/mr-tropic/nuttx-config/nsh/defconfig b/boards/nxp/mr-tropic/nuttx-config/nsh/defconfig new file mode 100644 index 0000000000..1811763a82 --- /dev/null +++ b/boards/nxp/mr-tropic/nuttx-config/nsh/defconfig @@ -0,0 +1,270 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_NSH_DISABLE_MB is not set +# CONFIG_NSH_DISABLE_MH is not set +# CONFIG_NSH_DISABLE_MW is not set +# CONFIG_SPI_CALLBACK is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD_CUSTOM=y +CONFIG_ARCH_BOARD_CUSTOM_DIR="../../../../boards/nxp/mr-tropic/nuttx-config" +CONFIG_ARCH_BOARD_CUSTOM_DIR_RELPATH=y +CONFIG_ARCH_BOARD_CUSTOM_NAME="px4" +CONFIG_ARCH_CHIP="imxrt" +CONFIG_ARCH_CHIP_IMXRT=y +CONFIG_ARCH_CHIP_MIMXRT1064DVL6A=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_RAMVECTORS=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARMV7M_DCACHE=y +CONFIG_ARMV7M_DTCM=y +CONFIG_ARMV7M_ICACHE=y +CONFIG_ARMV7M_ITCM=y +CONFIG_ARMV7M_MEMCPY=y +CONFIG_ARMV7M_USEBASEPRI=y +CONFIG_ARM_MPU=y +CONFIG_ARM_MPU_RESET=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_ASSERT_RESET_VALUE=0 +CONFIG_BOARD_LOOPSPERMSEC=115000 +CONFIG_BOARD_RESET_ON_ASSERT=2 +CONFIG_BUILTIN=y +CONFIG_CDCACM=y +CONFIG_CDCACM_BULKIN_REQLEN=96 +CONFIG_CDCACM_PRODUCTID=0x0025 +CONFIG_CDCACM_PRODUCTSTR="PX4 MR-TROPIC" +CONFIG_CDCACM_RXBUFSIZE=600 +CONFIG_CDCACM_TXBUFSIZE=12000 +CONFIG_CDCACM_VENDORID=0x1FC9 +CONFIG_CDCACM_VENDORSTR="NXP SEMICONDUCTORS" +CONFIG_DEBUG_ERROR=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_HARDFAULT_ALERT=y +CONFIG_DEBUG_MEMFAULT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEBUG_TCBINFO=y +CONFIG_DEV_FIFO_SIZE=0 +CONFIG_DEV_PIPE_SIZE=70 +CONFIG_DEV_URANDOM=y +CONFIG_ETH0_PHY_TJA1103=y +CONFIG_FAT_DMAMEMORY=y +CONFIG_FAT_LCNAMES=y +CONFIG_FAT_LFN=y +CONFIG_FAT_LFN_ALIAS_HASH=y +CONFIG_FDCLONE_STDIO=y +CONFIG_FSUTILS_IPCFG=y +CONFIG_FS_BINFS=y +CONFIG_FS_CROMFS=y +CONFIG_FS_FAT=y +CONFIG_FS_FATTIME=y +CONFIG_FS_LITTLEFS=y +CONFIG_FS_LITTLEFS_CACHE_SIZE_FACTOR=2 +CONFIG_FS_LITTLEFS_LOOKAHEAD_SIZE=64 +CONFIG_FS_LITTLEFS_PROGRAM_SIZE_FACTOR=1 +CONFIG_FS_PROCFS=y +CONFIG_FS_PROCFS_MAX_TASKS=64 +CONFIG_FS_PROCFS_REGISTER=y +CONFIG_FS_ROMFS=y +CONFIG_GRAN=y +CONFIG_GRAN_INTR=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_I2C=y +CONFIG_I2C_RESET=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_IMXRT_DTCM_HEAP=y +CONFIG_IMXRT_DTCM_HEAP_SIZE=127 +CONFIG_IMXRT_EDMA=y +CONFIG_IMXRT_EDMA_EDBG=y +CONFIG_IMXRT_EDMA_ELINK=y +CONFIG_IMXRT_EDMA_NTCD=64 +CONFIG_IMXRT_ENET=y +CONFIG_IMXRT_ENET_NTXBUFFERS=8 +CONFIG_IMXRT_ENET_PHYINIT=y +CONFIG_IMXRT_FLEXCAN3=y +CONFIG_IMXRT_FLEXCAN_TXMB=1 +CONFIG_IMXRT_GPIO1_0_15_IRQ=y +CONFIG_IMXRT_GPIO1_16_31_IRQ=y +CONFIG_IMXRT_GPIO2_0_15_IRQ=y +CONFIG_IMXRT_GPIO2_16_31_IRQ=y +CONFIG_IMXRT_GPIO_IRQ=y +CONFIG_IMXRT_INIT_FLEXRAM=y +CONFIG_IMXRT_ITCM=384 +CONFIG_IMXRT_LPI2C1=y +CONFIG_IMXRT_LPI2C3=y +CONFIG_IMXRT_LPI2C4=y +CONFIG_IMXRT_LPI2C_DMA=y +CONFIG_IMXRT_LPI2C_DMA_MAXMSG=16 +CONFIG_IMXRT_LPI2C_DYNTIMEO=y +CONFIG_IMXRT_LPI2C_DYNTIMEO_STARTSTOP=10 +CONFIG_IMXRT_LPSPI3=y +CONFIG_IMXRT_LPSPI3_DMA=y +CONFIG_IMXRT_LPSPI4=y +CONFIG_IMXRT_LPSPI4_DMA=y +CONFIG_IMXRT_LPSPI_DMA=y +CONFIG_IMXRT_LPUART2=y +CONFIG_IMXRT_LPUART3=y +CONFIG_IMXRT_LPUART4=y +CONFIG_IMXRT_LPUART5=y +CONFIG_IMXRT_LPUART6=y +CONFIG_IMXRT_LPUART7=y +CONFIG_IMXRT_LPUART8=y +CONFIG_IMXRT_LPUART_INVERT=y +CONFIG_IMXRT_LPUART_SINGLEWIRE=y +CONFIG_IMXRT_PHY_POLLING=y +CONFIG_IMXRT_SNVS_LPSRTC=y +CONFIG_IMXRT_USBDEV=y +CONFIG_IMXRT_USDHC1=y +CONFIG_IMXRT_USDHC1_INVERT_CD=y +CONFIG_IMXRT_USDHC1_WIDTH_D1_D4=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=2944 +CONFIG_IOB_NBUFFERS=24 +CONFIG_IOB_THROTTLE=0 +CONFIG_IPCFG_BINARY=y +CONFIG_IPCFG_PATH="/fs/nor" +CONFIG_LIBC_MAX_EXITFUNS=1 +CONFIG_LIBC_STRERROR=y +CONFIG_LPI2C1_DMA=y +CONFIG_LPI2C3_DMA=y +CONFIG_LPI2C4_DMA=y +CONFIG_LPUART2_RXDMA=y +CONFIG_LPUART2_TXDMA=y +CONFIG_LPUART3_BAUD=57600 +CONFIG_LPUART3_IFLOWCONTROL=y +CONFIG_LPUART3_OFLOWCONTROL=y +CONFIG_LPUART3_RXBUFSIZE=600 +CONFIG_LPUART3_RXDMA=y +CONFIG_LPUART3_TXBUFSIZE=3000 +CONFIG_LPUART3_TXDMA=y +CONFIG_LPUART4_BAUD=57600 +CONFIG_LPUART4_IFLOWCONTROL=y +CONFIG_LPUART4_RXBUFSIZE=600 +CONFIG_LPUART4_RXDMA=y +CONFIG_LPUART4_TXBUFSIZE=3000 +CONFIG_LPUART4_TXDMA=y +CONFIG_LPUART5_BAUD=57600 +CONFIG_LPUART5_IFLOWCONTROL=y +CONFIG_LPUART5_OFLOWCONTROL=y +CONFIG_LPUART5_RXBUFSIZE=600 +CONFIG_LPUART5_RXDMA=y +CONFIG_LPUART5_TXBUFSIZE=3000 +CONFIG_LPUART5_TXDMA=y +CONFIG_LPUART6_BAUD=57600 +CONFIG_LPUART6_SERIAL_CONSOLE=y +CONFIG_LPUART7_RXDMA=y +CONFIG_LPUART7_TXBUFSIZE=128 +CONFIG_LPUART8_BAUD=420000 +CONFIG_LPUART8_RXBUFSIZE=600 +CONFIG_LPUART8_RXDMA=y +CONFIG_LPUART8_TXDMA=y +CONFIG_MEMSET_64BIT=y +CONFIG_MEMSET_OPTSPEED=y +CONFIG_MMCSD=y +CONFIG_MMCSD_SDIO=y +CONFIG_MM_REGIONS=2 +CONFIG_MTD=y +CONFIG_MTD_BYTE_WRITE=y +CONFIG_MTD_PARTITION=y +CONFIG_NAME_MAX=40 +CONFIG_NET=y +CONFIG_NETDB_DNSCLIENT=y +CONFIG_NETDB_DNSSERVER_NOADDR=y +CONFIG_NETDEV_CAN_BITRATE_IOCTL=y +CONFIG_NETDEV_CAN_FILTER_IOCTL=y +CONFIG_NETDEV_LATEINIT=y +CONFIG_NETDEV_PHY_IOCTL=y +CONFIG_NETINIT_DHCPC=y +CONFIG_NETINIT_DNS=y +CONFIG_NETINIT_DNSIPADDR=0XC0A800FE +CONFIG_NETINIT_DRIPADDR=0XC0A800FE +CONFIG_NETINIT_MONITOR=y +CONFIG_NETINIT_RETRY_MOUNTPATH=10 +CONFIG_NETINIT_THREAD=y +CONFIG_NETINIT_THREAD_PRIORITY=49 +CONFIG_NETUTILS_TELNETD=y +CONFIG_NET_ARP_IPIN=y +CONFIG_NET_ARP_SEND=y +CONFIG_NET_BROADCAST=y +CONFIG_NET_CAN=y +CONFIG_NET_CAN_EXTID=y +CONFIG_NET_CAN_NOTIFIER=y +CONFIG_NET_CAN_RAW_TX_DEADLINE=y +CONFIG_NET_CAN_SOCK_OPTS=y +CONFIG_NET_ETH_PKTSIZE=1518 +CONFIG_NET_ICMP=y +CONFIG_NET_ICMP_SOCKET=y +CONFIG_NET_IGMP=y +CONFIG_NET_SOLINGER=y +CONFIG_NET_TCP=y +CONFIG_NET_TCPBACKLOG=y +CONFIG_NET_TCP_DELAYED_ACK=y +CONFIG_NET_TCP_KEEPALIVE=y +CONFIG_NET_TCP_WRITE_BUFFERS=y +CONFIG_NET_TIMESTAMP=y +CONFIG_NET_UDP=y +CONFIG_NET_UDP_CHECKSUMS=y +CONFIG_NET_UDP_WRITE_BUFFERS=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_CROMFSETC=y +CONFIG_NSH_LINELEN=128 +CONFIG_NSH_MAXARGUMENTS=15 +CONFIG_NSH_NESTDEPTH=8 +CONFIG_NSH_READLINE=y +CONFIG_NSH_ROMFSETC=y +CONFIG_NSH_ROMFSSECTSIZE=128 +CONFIG_NSH_STRERROR=y +CONFIG_NSH_TELNET_LOGIN=y +CONFIG_NSH_VARS=y +CONFIG_PIPES=y +CONFIG_PREALLOC_TIMERS=50 +CONFIG_PRIORITY_INHERITANCE=y +CONFIG_PTHREAD_MUTEX_TYPES=y +CONFIG_PTHREAD_STACK_MIN=512 +CONFIG_RAM_SIZE=1048576 +CONFIG_RAM_START=0x20200000 +CONFIG_RAW_BINARY=y +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_READLINE_TABCOMPLETION=y +CONFIG_RTC=y +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_HPWORKPRIORITY=249 +CONFIG_SCHED_HPWORKSTACKSIZE=1800 +CONFIG_SCHED_INSTRUMENTATION=y +CONFIG_SCHED_INSTRUMENTATION_EXTERNAL=y +CONFIG_SCHED_INSTRUMENTATION_SWITCH=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_LPWORKPRIORITY=50 +CONFIG_SCHED_LPWORKSTACKSIZE=2032 +CONFIG_SDIO_BLOCKSETUP=y +CONFIG_SEM_PREALLOCHOLDERS=32 +CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS=y +CONFIG_SERIAL_TERMIOS=y +CONFIG_SIG_DEFAULT=y +CONFIG_SIG_SIGALRM_ACTION=y +CONFIG_SIG_SIGUSR1_ACTION=y +CONFIG_SIG_SIGUSR2_ACTION=y +CONFIG_SIG_SIGWORK=4 +CONFIG_SPI=y +CONFIG_STACK_COLORATION=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=11 +CONFIG_STDIO_BUFFER_SIZE=256 +CONFIG_SYSTEM_CDCACM=y +CONFIG_SYSTEM_CLE=y +CONFIG_SYSTEM_DHCPC_RENEW=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_PING=y +CONFIG_SYSTEM_SYSTEM=y +CONFIG_TASK_NAME_SIZE=24 +CONFIG_USBDEV=y +CONFIG_USBDEV_BUSPOWERED=y +CONFIG_USBDEV_DUALSPEED=y +CONFIG_USBDEV_MAXPOWER=500 +CONFIG_USEC_PER_TICK=1000 +CONFIG_WATCHDOG=y diff --git a/boards/nxp/mr-tropic/nuttx-config/scripts/bootloader_script.ld b/boards/nxp/mr-tropic/nuttx-config/scripts/bootloader_script.ld new file mode 100644 index 0000000000..81fb1e0c40 --- /dev/null +++ b/boards/nxp/mr-tropic/nuttx-config/scripts/bootloader_script.ld @@ -0,0 +1,177 @@ +/**************************************************************************** + * boards/nxp/mr-tropic/nuttx-config/scripts/bootloader_script.ld + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Specify the memory areas */ + +MEMORY +{ + flash (rx) : ORIGIN = 0x70000000, LENGTH = 128K + sram (rwx) : ORIGIN = 0x20200000, LENGTH = 512K + itcm (rwx) : ORIGIN = 0x00000000, LENGTH = 384K + dtcm (rwx) : ORIGIN = 0x20000000, LENGTH = 128K +} + +OUTPUT_ARCH(arm) +EXTERN(_vectors) +EXTERN(g_flash_config) +EXTERN(g_image_vector_table) +EXTERN(g_boot_data) +EXTERN(board_get_manifest) +EXTERN(_bootdelay_signature) + +ENTRY(_stext) + +SECTIONS +{ + /* Image Vector Table and Boot Data for booting from external flash */ + + .boot_hdr : ALIGN(4) + { + FILL(0xff) + __boot_hdr_start__ = ABSOLUTE(.) ; + KEEP(*(.boot_hdr.conf)) + . = 0x1000 ; + KEEP(*(.boot_hdr.ivt)) + . = 0x1020 ; + KEEP(*(.boot_hdr.boot_data)) + . = 0x1030 ; + KEEP(*(.boot_hdr.dcd_data)) + __boot_hdr_end__ = ABSOLUTE(.) ; + . = 0x2000 ; + } >flash + + .vectors : + { + KEEP(*(.vectors)) + *(.text .text.__start) + } >flash + + .itcmfunc : + { + . = ALIGN(8); + _sitcmfuncs = ABSOLUTE(.); + FILL(0xFF) + . = 0x40 ; + *(.ram_vectors) + . = ALIGN(8); + _eitcmfuncs = ABSOLUTE(.); + } > itcm AT > flash + + _fitcmfuncs = LOADADDR(.itcmfunc); + + .text : ALIGN(4) + { + _stext = ABSOLUTE(.); + *(.vectors) + . = ALIGN(32); + /* + This signature provides the bootloader with a way to delay booting + */ + _bootdelay_signature = ABSOLUTE(.); + FILL(0xffecc2925d7d05c5) + . += 8; + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.gnu.linkonce.t.*) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + . = ALIGN(4096); + _etext = ABSOLUTE(.); + _srodata = ABSOLUTE(.); + *(.rodata .rodata.*) + . = ALIGN(4096); + _erodata = ABSOLUTE(.); + } > flash + + .init_section : + { + _sinit = ABSOLUTE(.); + KEEP(*(.init_array .init_array.*)) + _einit = ABSOLUTE(.); + } > flash + + .ARM.extab : + { + *(.ARM.extab*) + } > flash + + .ARM.exidx : + { + __exidx_start = ABSOLUTE(.); + *(.ARM.exidx*) + __exidx_end = ABSOLUTE(.); + } > flash + + _eronly = ABSOLUTE(.); + + .data : + { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + . = ALIGN(4); + _edata = ABSOLUTE(.); + } > sram AT > flash + + .ramfunc ALIGN(4): + { + _sramfuncs = ABSOLUTE(.); + *(.ramfunc .ramfunc.*) + _eramfuncs = ABSOLUTE(.); + } > sram AT > flash + + _framfuncs = LOADADDR(.ramfunc); + + .bss : + { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = ABSOLUTE(.); + } > sram + + /* Stabs debugging sections. */ + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } + + _boot_loadaddr = ORIGIN(flash); + _boot_size = LENGTH(flash); + _ram_size = LENGTH(sram); + _sdtcm = ORIGIN(dtcm); + _edtcm = ORIGIN(dtcm) + LENGTH(dtcm); +} diff --git a/boards/nxp/mr-tropic/nuttx-config/scripts/itcm_functions_includes.ld b/boards/nxp/mr-tropic/nuttx-config/scripts/itcm_functions_includes.ld new file mode 100644 index 0000000000..36330c1e85 --- /dev/null +++ b/boards/nxp/mr-tropic/nuttx-config/scripts/itcm_functions_includes.ld @@ -0,0 +1,719 @@ +*(.text._ZN4uORB7Manager27orb_add_internal_subscriberE6ORB_IDhPj) +*(.text._ZN13MavlinkStream6updateERKy) +*(.text._ZN7Mavlink16update_rate_multEv) +*(.text._ZN3sym17PredictCovarianceIfEEN6matrix6MatrixIT_Lj23ELj23EEERKNS2_IS3_Lj24ELj1EEERKS4_RKNS2_IS3_Lj3ELj1EEES3_SC_SC_S3_S3_) /* itcm-check-ignore */ +*(.text._ZN13MavlinkStream12get_size_avgEv) +*(.text._ZN16ControlAllocator3RunEv) +*(.text._ZN22MulticopterRateControl3RunEv.part.0) +*(.text._ZN7Mavlink9task_mainEiPPc) +*(.text._ZN7sensors22VehicleAngularVelocity3RunEv) +*(.text._ZN4uORB12Subscription9subscribeEv.part.0) +*(.text._ZN4uORB7Manager13orb_data_copyEPvS1_Rjb) +*(.text._ZN4uORB10DeviceNode5writeEP4filePKcj) +*(.text._ZN4uORB10DeviceNode7publishEPK12orb_metadataPvPKv) +*(.text._ZN4uORB12DeviceMaster19getDeviceNodeLockedEPK12orb_metadatah) +*(.text._Z12get_orb_meta6ORB_ID) +*(.text._ZN9ICM42688P12ProcessAccelERKyPKN20InvenSense_ICM42688P4FIFO4DATAEh) +*(.text._ZN3px49WorkQueue3RunEv) +*(.text._ZN9ICM42688P11ProcessGyroERKyPKN20InvenSense_ICM42688P4FIFO4DATAEh) +*(.text._ZN4EKF23RunEv) +*(.text._ZN7sensors10VehicleIMU7PublishEv) +*(.text._ZN4math17WelfordMeanVectorIfLj3EE6updateERKN6matrix6VectorIfLj3EEE) +*(.text._ZN7sensors10VehicleIMU10UpdateGyroEv) +*(.text._ZN9ICM42688P8FIFOReadERKyh) +*(.text._ZN3Ekf20controlGravityFusionERKN9estimator9imuSampleE) +*(.text._ZN16PX4Accelerometer10updateFIFOER19sensor_accel_fifo_s) +*(.text._ZN7sensors22VehicleAngularVelocity19CalibrateAndPublishERKyRKN6matrix7Vector3IfEES7_) +*(.text._ZN4uORB12Subscription10advertisedEv) +*(.text._ZNK15AttitudeControl6updateERKN6matrix10QuaternionIfEE) +*(.text._ZN7sensors10VehicleIMU11UpdateAccelEv) +*(.text.perf_set_elapsed.part.0) +*(.text._ZN4uORB12Subscription6updateEPv) +*(.text._ZN12PX4Gyroscope10updateFIFOER18sensor_gyro_fifo_s) +*(.text._ZN7sensors10VehicleIMU3RunEv) +*(.text.__aeabi_l2f) +*(.text._ZN39ControlAllocationSequentialDesaturation23computeDesaturationGainERKN6matrix6VectorIfLj16EEES4_) +*(.text.pthread_mutex_timedlock) +*(.text._ZN7sensors22VehicleAngularVelocity21FilterAngularVelocityEiPfi) +*(.text._ZN26MulticopterAttitudeControl3RunEv.part.0) +*(.text._ZN6device3SPI9_transferEPhS1_j) +*(.text._ZN15OutputPredictor21calculateOutputStatesEyRKN6matrix7Vector3IfEEfS4_f) +*(.text._ZN7sensors18VotedSensorsUpdate7imuPollER17sensor_combined_s) +*(.text._Z9rotate_3i8RotationRsS0_S0_) +*(.text.fs_getfilep) +*(.text.MEM_DataCopy0_1) +*(.text._ZN7sensors19VehicleAcceleration3RunEv) +*(.text.uart_ioctl) +*(.text._ZN26MulticopterPositionControl3RunEv.part.0) +*(.text.pthread_mutex_take) +*(.text._ZN14ImuDownSampler6updateERKN9estimator9imuSampleE) +*(.text._ZN39ControlAllocationSequentialDesaturation6mixYawEv) +*(.text._ZN16ControlAllocator25publish_actuator_controlsEv.part.0) +*(.text._ZN9ICM42688P7RunImplEv) +*(.text._ZN4uORB12Subscription9subscribeEv) +*(.text.param_get) +*(.text._ZN7sensors22VehicleAngularVelocity21SensorSelectionUpdateERKyb) +*(.text._ZN3px49WorkQueue3AddEPNS_8WorkItemE) +*(.text._ZN4EKF220PublishLocalPositionERKy) +*(.text._mav_finalize_message_chan_send) +*(.text._ZN7sensors22VehicleAngularVelocity16ParametersUpdateEb) +*(.text._ZN6events12SendProtocol6updateERKy) +*(.text._ZN6device3SPI8transferEPhS1_j) +*(.text._ZN27MavlinkStreamDistanceSensor4sendEv) +*(.text.hrt_call_internal) +*(.text._ZN39ControlAllocationSequentialDesaturation18mixAirmodeDisabledEv) +*(.text._ZN7Mavlink15get_free_tx_bufEv) +*(.text.nx_poll) +*(.text._ZN15MavlinkReceiver3runEv) +*(.text._ZN9ICM42688P18ProcessTemperatureEPKN20InvenSense_ICM42688P4FIFO4DATAEh) +*(.text._ZN15OutputPredictor19correctOutputStatesEyRKN6matrix10QuaternionIfEERKNS0_7Vector3IfEERK9LatLonAltS8_S8_) +*(.text._ZN3Ekf12predictStateERKN9estimator9imuSampleE) +*(.text._ZN3px46logger6Logger3runEv) +*(.text._ZN4uORB20SubscriptionInterval7updatedEv) +*(.text._ZN24MavlinkStreamCommandLong4sendEv) +*(.text._ZN9Commander3runEv) +*(.text._ZN3Ekf17predictCovarianceERKN9estimator9imuSampleE) +*(.text.wd_cancel) +*(.text._ZN7Sensors3RunEv) +*(.text.perf_end) +*(.text._ZN4uORB12Subscription7updatedEv) +*(.text._ZN13land_detector12LandDetector3RunEv) +*(.text.sched_idletask) +*(.text.atanf) +*(.text.uart_write) +*(.text.pthread_mutex_unlock) +*(.text.__ieee754_asinf) +*(.text.MEM_DataCopy0_2) +*(.text._ZN20MavlinkCommandSender13check_timeoutE17mavlink_channel_t) +*(.text._ZN16ControlAllocator32publish_control_allocator_statusEi) +*(.text.__ieee754_atan2f) +*(.text._ZNK18DynamicSparseLayer3getEt) +*(.text.__udivmoddi4) +*(.text._ZN8Failsafe17checkStateAndModeERKyRKN12FailsafeBase5StateERK16failsafe_flags_s) +*(.text._ZN29MavlinkStreamHygrometerSensor4sendEv) +*(.text.pthread_mutex_give) +*(.text._ZN3Ekf18controlFusionModesERKN9estimator9imuSampleE) +*(.text._ZN4cdev4CDev11poll_notifyEm) +*(.text.file_vioctl) +*(.text._ZN7sensors18VotedSensorsUpdate11sensorsPollER17sensor_combined_s) +*(.text.nxsig_nanosleep) +*(.text.sem_wait) +*(.text.perf_count_interval.part.0) +*(.text._ZN16ControlAllocator37update_effectiveness_matrix_if_neededE25EffectivenessUpdateReason) +*(.text.MEM_LongCopyJump) +*(.text.px4_arch_adc_sample) +*(.text._ZN31MulticopterHoverThrustEstimator3RunEv) +*(.text._ZNK17ControlAllocation20clipActuatorSetpointERN6matrix6VectorIfLj16EEE) +*(.text._ZN4uORB7Manager17get_device_masterEv) +*(.text._ZN13DataValidator3putEyPKfmh) +*(.text.cdcuart_ioctl) +*(.text.cdcacm_sndpacket) +*(.text._ZN7sensors22VehicleAngularVelocity16SensorBiasUpdateEb) +*(.text._ZN13MavlinkStream11update_dataEv) +*(.text._ZN7sensors18VotedSensorsUpdate21calcGyroInconsistencyEv) +*(.text.param_set_used) +*(.text._ZN18EstimatorInterface10setIMUDataERKN9estimator9imuSampleE) +*(.text._ZN18DataValidatorGroup8get_bestEyPi) +*(.text._ZN4EKF218PublishInnovationsERKy) +*(.text._ZN21MavlinkMissionManager4sendEv) +*(.text._ZN22MulticopterRateControl28updateActuatorControlsStatusERK25vehicle_torque_setpoint_sf) +*(.text._ZN11RateControl6updateERKN6matrix7Vector3IfEES4_S4_fb) +*(.text._ZN39ControlAllocationSequentialDesaturation19desaturateActuatorsERN6matrix6VectorIfLj16EEERKS2_b) +*(.text.imxrt_lpi2c_transfer) +*(.text.uart_putxmitchar) +*(.text.clock_nanosleep) +*(.text.up_release_pending) +*(.text.MEM_DataCopy0) +*(.text._ZN22MavlinkStreamGPSRawInt4sendEv) +*(.text.dq_rem) +*(.text._ZN15GyroCalibration3RunEv.part.0) +*(.text._ZN7sensors18VotedSensorsUpdate22calcAccelInconsistencyEv) +*(.text._ZN24MavlinkStreamADSBVehicle4sendEv) +*(.text.sinf) +*(.text.hrt_call_after) +*(.text._ZN39ControlAllocationSequentialDesaturation8allocateEv) +*(.text.up_invalidate_dcache) +*(.text._ZN15PositionControl16_velocityControlEf) +*(.text._ZN4EKF222PublishAidSourceStatusERKy) +*(.text._ZN4ListIP13MavlinkStreamE8IteratorppEv) +*(.text._ZN20MavlinkStreamESCInfo4sendEv) +*(.text.sem_post) +*(.text._ZN3px417ScheduledWorkItem15ScheduleDelayedEm) +*(.text._ZN10FlightTaskC1Ev) +*(.text.usleep) +*(.text._ZN14FlightTaskAutoC1Ev) +*(.text.sem_getvalue) +*(.text._ZN23MavlinkStreamHighresIMU4sendEv) +*(.text.imxrt_gpio_write) +*(.text._ZN3Ekf6updateEv) +*(.text.__ieee754_acosf) +*(.text._ZN3Ekf20updateIMUBiasInhibitERKN9estimator9imuSampleE) +*(.text._ZN9Commander13dataLinkCheckEv) +*(.text._ZN17FlightModeManager10switchTaskE15FlightTaskIndex) +*(.text._ZN12PX4Gyroscope9set_scaleEf) +*(.text._ZN12FailsafeBase6updateERKyRKNS_5StateEbbRK16failsafe_flags_s) +*(.text._ZN18MavlinkStreamDebug4sendEv) +*(.text._ZN27MavlinkStreamServoOutputRawILi0EE4sendEv) +*(.text.asinf) +*(.text._ZN6matrix5EulerIfEC1ERKNS_3DcmIfEE) +*(.text._ZN4EKF227PublishInnovationTestRatiosERKy) +*(.text._ZN4EKF213PublishStatusERKy) +*(.text._ZN4EKF226PublishInnovationVariancesERKy) +*(.text._ZN13land_detector23MulticopterLandDetector25_get_ground_contact_stateEv) +*(.text.imxrt_dmach_start) +*(.text._ZN3ADC19update_system_powerEy) +*(.text._ZNK3Ekf19get_ekf_soln_statusEv) +*(.text._ZN3px46logger15watchdog_updateERNS0_15watchdog_data_tEb) +*(.text.imxrt_gpio_read) +*(.text._ZN32MavlinkStreamNavControllerOutput4sendEv) +*(.text._ZN39MavlinkStreamGimbalDeviceAttitudeStatus4sendEv) +*(.text._ZNK10ConstLayer3getEt) +*(.text.__aeabi_uldivmod) +*(.text.up_udelay) +*(.text.up_idle) +*(.text._ZN20MavlinkStreamGPS2Raw4sendEv) +*(.text._ZN4EKF217UpdateCalibrationERKyRNS_19InFlightCalibrationERKN6matrix7Vector3IfEES8_fbb) +*(.text._ZN28MavlinkStreamGpsGlobalOrigin4sendEv) +*(.text._ZN11ControlMath15bodyzToAttitudeEN6matrix7Vector3IfEEfR27vehicle_attitude_setpoint_s) +*(.text._ZN4EKF217UpdateRangeSampleER17ekf2_timestamps_s) +*(.text._ZN3Ekf24controlOpticalFlowFusionERKN9estimator9imuSampleE) +*(.text._ZN19MavlinkStreamRawRpm4sendEv) +*(.text._ZN13MavlinkStream10const_rateEv) +*(.text._ZN4EKF215PublishOdometryERKyRKN9estimator9imuSampleE) +*(.text._ZN15FailureDetector20updateAttitudeStatusERK16vehicle_status_s) +*(.text._ZN7Mavlink19configure_sik_radioEv) +*(.text._ZN13BatteryStatus8adc_pollEv) +*(.text.getpid) +*(.text._ZN13DataValidator10confidenceEy) +*(.text._ZN22MavlinkStreamGPSStatus4sendEv) +*(.text._ZN4EKF220UpdateAirspeedSampleER17ekf2_timestamps_s) +*(.text._ZN23MavlinkStreamStatustext4sendEv) +*(.text.uart_poll) +*(.text._ZN24MavlinkParametersManager4sendEv) +*(.text._ZN26MulticopterPositionControl18set_vehicle_statesERK24vehicle_local_position_sf) +*(.text.file_poll) +*(.text.hrt_elapsed_time) +*(.text._ZN7Mavlink11send_finishEv) +*(.text._ZNK3Ekf36estimateInertialNavFallingLikelihoodEv) +*(.text._ZN15PositionControl16_positionControlEv) +*(.text._ZN28MavlinkStreamDebugFloatArray4sendEv) +*(.text._ZN11ControlMath9limitTiltERN6matrix7Vector3IfEERKS2_f) +*(.text.pthread_mutex_lock) +*(.text._ZN21MavlinkStreamAltitude8get_sizeEv) +*(.text._ZN7Mavlink29check_requested_subscriptionsEv) +*(.text.imxrt_lpspi_setmode) +*(.text._ZN3Ekf34controlZeroInnovationHeadingUpdateEv) +*(.text.perf_begin) +*(.text.imxrt_lpspi_setfrequency) +*(.text._ZN17FlightModeManager9_initTaskE15FlightTaskIndex) +*(.text._ZN22MulticopterRateControl3RunEv) +*(.text.cosf) +*(.text._ZN22MavlinkStreamESCStatus4sendEv) +*(.text._ZN26MavlinkStreamCameraTrigger4sendEv) +*(.text._ZN36MavlinkStreamPositionTargetGlobalInt4sendEv) +*(.text._ZN4uORB12Subscription4copyEPv) +*(.text._ZN7sensors19VehicleAcceleration21SensorSelectionUpdateEb) +*(.text.crc_accumulate) +*(.text._ZN3px46logger6Logger13update_paramsEv) +*(.text._ZN11calibration14DeviceExternalEm) +*(.text._ZN25MavlinkStreamHomePosition8get_sizeEv) +*(.text.imxrt_lpspi_modifyreg32) +*(.text._ZN7sensors19VehicleAcceleration16SensorBiasUpdateEb) +*(.text.modifyreg32) +*(.text._ZNK6matrix6MatrixIfLj3ELj1EEmlEf) +*(.text._ZN6matrix5EulerIfEC1ERKNS_10QuaternionIfEE) +*(.text.imxrt_queuedtd) +*(.text._ZN27MavlinkStreamDistanceSensor8get_sizeEv) +*(.text._ZN3Ekf23controlBaroHeightFusionERKN9estimator9imuSampleE) +*(.text._ZN16PX4Accelerometer9set_scaleEf) +*(.text._ZN11ControlMath11constrainXYERKN6matrix7Vector2IfEES4_RKf) +*(.text._ZN22MavlinkStreamEfiStatus4sendEv) +*(.text._ZN22MavlinkStreamDebugVect4sendEv) +*(.text._ZN4EKF217PublishSensorBiasERKy) +*(.text._ZN17FlightModeManager3RunEv) +*(.text._ZN15PositionControl11_inputValidEv) +*(.text._ZN7sensors14VehicleAirData3RunEv) +*(.text.perf_count) +*(.text._ZN3Ekf16controlMagFusionERKN9estimator9imuSampleE) +*(.text.pthread_sem_give) +*(.text._ZN7sensors10VehicleIMU16ParametersUpdateEb) +*(.text._ZN4uORB20SubscriptionInterval4copyEPv) +*(.text._ZN12I2CSPIDriverI9ICM42688PE3RunEv) +*(.text.imxrt_epcomplete.constprop.0) +*(.text._ZNK6matrix6MatrixIfLj3ELj1EEmiERKS1_) +*(.text._ZN9Commander30handleModeIntentionAndFailsafeEv) +*(.text.perf_event_count) +*(.text._ZN4EKF215PublishAttitudeERKy) +*(.text._ZN19MavlinkStreamRawRpm8get_sizeEv) +*(.text._ZNK3px46atomicIbE4loadEv) +*(.text._ZN29MavlinkStreamHygrometerSensor8get_sizeEv) +*(.text.pthread_mutex_add) +*(.text._ZN12HomePosition6updateEbb) +*(.text.poll_fdsetup) +*(.text._ZN15PositionControl20_accelerationControlEv) +*(.text._ZN3Ekf19controlHeightFusionERKN9estimator9imuSampleE) +*(.text._ZN9Commander19control_status_ledsEbh) +*(.text._ZN6device3I2C8transferEPKhjPhj) +*(.text.orb_publish) +*(.text._ZN7sensors19VehicleAcceleration16ParametersUpdateEb) +*(.text._ZN22MavlinkStreamVibration8get_sizeEv) +*(.text._ZN15MavlinkReceiver15CheckHeartbeatsERKyb) +*(.text._ZNK6matrix7Vector3IfEmiES1_) +*(.text.__aeabi_f2ulz) +*(.text._ZN9ICM42688P26DataReadyInterruptCallbackEiPvS0_) +*(.text._ZN13land_detector23MulticopterLandDetector23_get_maybe_landed_stateEv) +*(.text.acosf) +*(.text._ZN14ImuDownSampler5resetEv) +*(.text._ZN3Ekf31checkVerticalAccelerationHealthERKN9estimator9imuSampleE) +*(.text._ZN6matrix6MatrixIfLj3ELj1EEC1ERKS1_) +*(.text.udp_pollsetup) +*(.text._ZL14timer_callbackPv) +*(.text._ZN3Ekf4fuseERKN6matrix6VectorIfLj24EEEf) +*(.text._ZN13land_detector23MulticopterLandDetector22_set_hysteresis_factorEi) +*(.text.nxsem_wait_irq) +*(.text._ZN20MavlinkCommandSender4lockEv) +*(.text.MEM_LongCopyEnd) +*(.text._ZThn24_N16ControlAllocator3RunEv) +*(.text._ZN15TimestampedListIN20MavlinkCommandSender14command_item_sELi3EE8get_nextEv) +*(.text._ZNK3Ekf21get_ekf_lpos_accuracyEPfS0_) +*(.text._ZN17FlightModeManager17start_flight_taskEv) +*(.text.MEM_DataCopyBytes) +*(.text._ZN29MavlinkStreamLocalPositionNED8get_sizeEv) +*(.text._ZN6SticksC1EP12ModuleParams) +*(.text._ZN27MavlinkStreamServoOutputRawILi1EE4sendEv) +*(.text._ZN3Ekf35updateHorizontalDeadReckoningstatusEv) +*(.text._ZN3Ekf20controlAirDataFusionERKN9estimator9imuSampleE) +*(.text._ZN24FlightTaskManualAltitudeC1Ev) +*(.text._ZN25MavlinkStreamHomePosition4sendEv) +*(.text._ZN24MavlinkParametersManager8send_oneEv) +*(.text._ZN15OutputPredictor29applyCorrectionToOutputBufferERKN6matrix7Vector3IfEES4_) +*(.text._ZN21HealthAndArmingChecks6updateEbb) +*(.text._ZThn24_N22MulticopterRateControl3RunEv) +*(.text._ZN26MavlinkStreamManualControl4sendEv) +*(.text._ZN27MavlinkStreamOpticalFlowRad4sendEv) +*(.text._ZN18mag_bias_estimator16MagBiasEstimator3RunEv) +*(.text._ZN4uORB7Manager11orb_publishEPK12orb_metadataPvPKv) +*(.text._ZN24MavlinkParametersManager18send_untransmittedEv) +*(.text._ZN10MavlinkFTP4sendEv) +*(.text._ZN3Ekf27controlExternalVisionFusionERKN9estimator9imuSampleE) +*(.text.clock_gettime) +*(.text._ZN3ADC17update_adc_reportEy) +*(.text._ZN32MavlinkStreamGimbalManagerStatus4sendEv) +*(.text._ZN9LockGuardD1Ev) /* itcm-check-ignore */ +*(.text._ZN4EKF213PublishStatesERKy) +*(.text._ZN3ADC3RunEv) +*(.text._ZN6BMP38815compensate_dataEhPK16bmp3_uncomp_dataP9bmp3_data) +*(.text._ZN3Ekf20controlFakePosFusionEv) +*(.text._ZN11calibration9Gyroscope13set_device_idEm) +*(.text._ZN24MavlinkStreamOrbitStatus8get_sizeEv) +*(.text.imxrt_progressep) +*(.text.imxrt_gpio_configinput) +*(.text._ZN17FlightModeManager26generateTrajectorySetpointEfRK24vehicle_local_position_s) +*(.text._ZN7Sensors14diff_pres_pollEv) +*(.text._ZN21MavlinkStreamAttitude4sendEv) +*(.text._ZN4EKF220UpdateMagCalibrationERKy) +*(.text._ZN22MavlinkStreamEfiStatus8get_sizeEv) +*(.text._ZN9ICM42688P9DataReadyEv) +*(.text._ZN21MavlinkMissionManager20check_active_missionEv) +*(.text._ZNK3Ekf20get_ekf_vel_accuracyEPfS0_) +*(.text._ZN4EKF216UpdateBaroSampleER17ekf2_timestamps_s) +*(.text._ZN4EKF223UpdateSystemFlagsSampleER17ekf2_timestamps_s) +*(.text._ZThn16_N7sensors22VehicleAngularVelocity3RunEv) +*(.text._ZN29MavlinkStreamObstacleDistance4sendEv) +*(.text._ZN24MavlinkStreamOrbitStatus4sendEv) +*(.text._ZN9Navigator3runEv) +*(.text._ZN24MavlinkParametersManager11send_paramsEv) +*(.text._ZN17MavlinkLogHandler4sendEv) +*(.text._ZN7control10SuperBlock5setDtEf) +*(.text._ZN29MavlinkStreamMountOrientation8get_sizeEv) +*(.text._ZN26MulticopterAttitudeControl3RunEv) +*(.text._ZThn16_N31ActuatorEffectivenessMultirotor22getEffectivenessMatrixERN21ActuatorEffectiveness13ConfigurationE25EffectivenessUpdateReason) +*(.text._ZN4EKF218PublishStatusFlagsERKy) +*(.text._ZN11WeatherVaneC1EP12ModuleParams) +*(.text._ZN15FailureDetector6updateERK16vehicle_status_sRK22vehicle_control_mode_s) +*(.text._ZN7Mavlink10send_startEi) +*(.text.imxrt_lpspi_setbits) +*(.text._ZN15OutputPredictor37applyCorrectionToVerticalOutputBufferEff) +*(.text._ZN4EKF222UpdateAccelCalibrationERKy) +*(.text._ZN7sensors19VehicleMagnetometer3RunEv) +*(.text._ZN29MavlinkStreamMountOrientation4sendEv) +*(.text._ZN13land_detector12LandDetector19UpdateVehicleAtRestEv) +*(.text._ZN10FlightTask29_evaluateVehicleLocalPositionEv) +*(.text.__aeabi_f2lz) +*(.text._ZN32MavlinkStreamCameraImageCaptured4sendEv) +*(.text._ZN21MavlinkStreamOdometry8get_sizeEv) +*(.text._ZN28MavlinkStreamNamedValueFloat4sendEv) +*(.text.__aeabi_ul2f) +*(.text.poll) +*(.text._ZN14FlightTaskAutoD1Ev) +*(.text._ZN4uORB10DeviceNode22get_initial_generationEv) +*(.text._ZN3Ekf23controlGnssHeightFusionERKN9estimator10gnssSampleE) +*(.text._ZN3Ekf40updateOnGroundMotionForOpticalFlowChecksEv) +*(.text._ZN6matrix6MatrixIfLj3ELj1EEC1Ev) +*(.text._ZN14ZeroGyroUpdate6updateER3EkfRKN9estimator9imuSampleE) +*(.text._ZN30MavlinkStreamOpenDroneIdSystem4sendEv) +*(.text._ZN22MavlinkStreamScaledIMU4sendEv) +*(.text.imxrt_ioctl) +*(.text._ZN36MavlinkStreamGimbalDeviceSetAttitude4sendEv) +*(.text._ZN4math13expo_deadzoneIfEEKT_RS2_S3_S3_.isra.0) +*(.text._ZN19StickAccelerationXYC1EP12ModuleParams) +*(.text.imxrt_epsubmit) +*(.text._ZN15PositionControl6updateEf) +*(.text._ZN23MavlinkStreamScaledIMU24sendEv) +*(.text.imxrt_dma_send) +*(.text._ZN20MavlinkStreamWindCov4sendEv) +*(.text._ZN7sensors18VotedSensorsUpdate13checkFailoverERNS0_10SensorDataEPKcN6events3px45enums13sensor_type_tE) +*(.text._ZN21MavlinkStreamOdometry4sendEv) +*(.text.vsprintf_internal.constprop.0) +*(.text.udp_pollteardown) +*(.text._ZN12MixingOutput6updateEv) +*(.text.clock_abstime2ticks) +*(.text._ZN13BatteryStatus3RunEv) +*(.text._ZN32MavlinkStreamGimbalManagerStatus8get_sizeEv) +*(.text._ZN10FlightTask15_resetSetpointsEv) +*(.text._ZN9systemlib10Hysteresis20set_state_and_updateEbRKy) +*(.text.devif_callback_free.part.0) +*(.text._ZN6Sticks25checkAndUpdateStickInputsEv) +*(.text.atan2f) +*(.text._ZN23MavlinkStreamRCChannels4sendEv) +*(.text._ZN4EKF221UpdateExtVisionSampleER17ekf2_timestamps_s) +*(.text.imxrt_dmach_stop) +*(.text._ZN9Commander16handleAutoDisarmEv) +*(.text._ZN9Commander11updateTunesEv) +*(.text._ZN4EKF215UpdateMagSampleER17ekf2_timestamps_s) +*(.text._ZN18DataValidatorGroup3putEjyPKfmh) +*(.text._ZNK3Ekf19get_ekf_ctrl_limitsEPfS0_S0_S0_S0_) +*(.text._ZN12FailsafeBase13checkFailsafeEibbRKNS_13ActionOptionsE) +*(.text._ZN17FlightTaskDescendD1Ev) +*(.text._ZN30MavlinkStreamOpenDroneIdSystem8get_sizeEv) +*(.text._ZNK3px46logger9LogWriter10is_startedENS0_7LogTypeE) +*(.text._ZN24FlightTaskManualAltitudeD1Ev) +*(.text._Z35px4_indicate_external_reset_lockout16LockoutComponentb) +*(.text.uart_pollnotify) +*(.text._ZN4EKF215PublishBaroBiasERKy) +*(.text._ZN4EKF221UpdateGyroCalibrationERKy) +*(.text._ZN6matrix9constrainIfLj3ELj1EEENS_6MatrixIT_XT0_EXT1_EEERKS3_S2_S2_) +*(.text._ZN4uORB22SubscriptionMultiArrayI16battery_status_sLh3EE16advertised_countEv) +*(.text._ZN23MavlinkStreamScaledIMU34sendEv) +*(.text.__aeabi_ldivmod) +*(.text._ZN15PositionControl16setInputSetpointERK21trajectory_setpoint_s) +*(.text.nxsig_pendingset) +*(.text.psock_poll) +*(.text._ZN15FailureInjector6updateEv) +*(.text.imxrt_writedtd) +*(.text.cdcacm_wrcomplete) +*(.text.cdcuart_txint) +*(.text._ZN3Ekf33updateVerticalDeadReckoningStatusEv) +*(.text._ZN33FlightTaskManualAltitudeSmoothVelC1Ev) +*(.text.powf) +*(.text._ZN4EKF217PublishEventFlagsERKy) +*(.text._ZN17FlightTaskDescend6updateEv) +*(.text.imxrt_iomux_configure) +*(.text.hrt_store_absolute_time) +*(.text.nxsem_set_protocol) +*(.text.write) +*(.text._ZN22MavlinkStreamSysStatus4sendEv) +*(.text._ZN4EKF216UpdateFlowSampleER17ekf2_timestamps_s) +*(.text._ZN4cdevL10cdev_ioctlEP4fileim) +*(.text._ZN7Mavlink10send_bytesEPKhj) +*(.text._ZNK8Failsafe17checkModeFallbackERK16failsafe_flags_sh) +*(.text.clock_systime_timespec) +*(.text._ZN4uORB10DeviceNode26remove_internal_subscriberEv) +*(.text._ZThn16_N4EKF23RunEv) +*(.text._ZNK3Ekf22computeYawInnovVarAndHEfRfRN6matrix6VectorIfLj24EEE) +*(.text._ZN12ActuatorTest6updateEif) +*(.text._ZN17VelocitySmoothingC1Efff) +*(.text._ZN13AnalogBattery19get_voltage_channelEv) +*(.text._ZN10FlightTask37_evaluateVehicleLocalPositionSetpointEv) +*(.text._ZN4uORB12Subscription11unsubscribeEv) +*(.text.net_lock) +*(.text.clock_time2ticks) +*(.text._ZN12FailsafeBase16updateStartDelayERKyb) +*(.text._ZN23MavlinkStreamStatustext8get_sizeEv) +*(.text._ZN11calibration13Accelerometer13set_device_idEm) +*(.text._ZN3px46logger6Logger18start_stop_loggingEv) +*(.text._ZN14FlightTaskAuto17_evaluateTripletsEv) +*(.text._ZN11calibration9Gyroscope23SensorCorrectionsUpdateEb) +*(.text._ZN25MavlinkStreamMagCalReport4sendEv) +*(.text.imxrt_config_gpio) +*(.text.nxsig_timeout) +*(.text._ZN11RateControl19setSaturationStatusERKN6matrix7Vector3IbEES4_) +*(.text._ZN3Ekf17measurementUpdateERN6matrix6VectorIfLj24EEERKS2_ff) +*(.text.dq_addlast) +*(.text._ZN19MavlinkStreamVFRHUD4sendEv) +*(.text.hrt_call_reschedule) +*(.text.nxsem_boost_priority) +*(.text._ZN4EKF215UpdateGpsSampleER17ekf2_timestamps_s) +*(.text._ZN8StickYawC1EP12ModuleParams) +*(.text._ZN7control12BlockLowPass6updateEf) +*(.text._ZN15FailureDetector26updateImbalancedPropStatusEv) +*(.text._ZN9systemlib10Hysteresis6updateERKy) +*(.text.nxsem_tickwait_uninterruptible) +*(.text._ZN12HomePosition31hasMovedFromCurrentHomeLocationEv) +*(.text.devif_callback_alloc) +*(.text._ZN28MavlinkStreamNamedValueFloat8get_sizeEv) +*(.text._ZN24MavlinkStreamADSBVehicle8get_sizeEv) +*(.text._ZN26MavlinkStreamBatteryStatus8get_sizeEv) +*(.text._ZN26MulticopterPositionControl17parameters_updateEb) +*(.text._ZN3px46logger6Logger29handle_vehicle_command_updateEv) +*(.text.imxrt_lpspi_send) +*(.text._ZN4uORB10DeviceNode23add_internal_subscriberEv) +*(.text._ZN6matrix6MatrixIfLj3ELj1EEaSERKS1_) +*(.text._ZNK6matrix6MatrixIfLj3ELj1EE5emultERKS1_) +*(.text.mallinfo_handler) +*(.text._ZN13land_detector23MulticopterLandDetector14_update_topicsEv) +*(.text._ZN24ManualVelocitySmoothingZC1Ev) /* itcm-check-ignore */ +*(.text._ZN3ADC6sampleEj) +*(.text._ZNK3Ekf22isTerrainEstimateValidEv) +*(.text._ZN15EstimatorChecks23setModeRequirementFlagsERK7ContextbbbRK24vehicle_local_position_sRK12sensor_gps_sR16failsafe_flags_sR6Report) +*(.text._ZN11ControlMath11addIfNotNanERff) +*(.text._ZN9Commander21checkForMissionUpdateEv) +*(.text._Z8set_tunei) +*(.text._ZNK6matrix7Vector3IfE5crossERKNS_6MatrixIfLj3ELj1EEE) +*(.text._ZN10FlightTask22_checkEkfResetCountersEv) +*(.text._ZNK6matrix6MatrixIfLj3ELj1EE11isAllFiniteEv) +*(.text._ZN14FlightTaskAuto24_evaluateGlobalReferenceEv) +*(.text._ZN6matrix9constrainIfLj2ELj1EEENS_6MatrixIT_XT0_EXT1_EEERKS3_S2_S2_) +*(.text._ZN3px46logger6Logger23handle_file_write_errorEv) +*(.text._ZN10FlightTask16updateInitializeEv) +*(.text._ZN11calibration9Gyroscope10set_offsetERKN6matrix7Vector3IfEE) +*(.text._ZNK6matrix6VectorIfLj3EE4normEv) +*(.text._ZN14FlightTaskAuto16updateInitializeEv) +*(.text.fabsf) +*(.text._ZN27MavlinkStreamAttitudeTarget8get_sizeEv) +*(.text.nxsem_get_value) +*(.text._ZN13AnalogBattery8is_validEv) +*(.text._ZN4uORB16SubscriptionDataI15home_position_sEC1EPK12orb_metadatah) +*(.text._ZN22MavlinkStreamGPSStatus8get_sizeEv) +*(.text.nxsem_destroyholder) +*(.text.psock_udp_cansend) +*(.text.MEM_DataCopy2_2) +*(.text._ZN10FlightTask8activateERK21trajectory_setpoint_s) +*(.text.sock_file_poll) +*(.text._ZN10Ringbuffer9pop_frontEPhj) +*(.text.nx_write) +*(.text._ZN9Commander18manualControlCheckEv) +*(.text._ZN31MavlinkStreamAttitudeQuaternion4sendEv) +*(.text.nxsem_canceled) +*(.text._ZN10FlightTask21getTrajectorySetpointEv) +*(.text.imxrt_dmach_getcount) +*(.text.sem_clockwait) +*(.text.inet_poll) +*(.text._ZN6BMP3887collectEv) +*(.text._ZNK15PositionControl24getLocalPositionSetpointER33vehicle_local_position_setpoint_s) +*(.text._ZN3Ekf16controlGpsFusionERKN9estimator9imuSampleE) +*(.text._ZN23MavlinkStreamRCChannels8get_sizeEv) +*(.text._ZN20MavlinkStreamESCInfo8get_sizeEv) +*(.text._ZNK6matrix6VectorIfLj2EE4normEv) +*(.text._Z15arm_auth_updateyb) +*(.text._ZN3LED5ioctlEP4fileim) /* itcm-check-ignore */ +*(.text._ZNK3px46logger9LogWriter20had_file_write_errorEv) +*(.text._ZN29MavlinkStreamLocalPositionNED4sendEv) +*(.text._ZNK6matrix6VectorIfLj3EE3dotERKNS_6MatrixIfLj3ELj1EEE) +*(.text.imxrt_lpi2c_setclock) +*(.text._ZN6matrix12typeFunction9constrainIfEET_S2_S2_S2_.part.0) +*(.text._ZN13MapProjection13initReferenceEddy) +*(.text._ZN11calibration13Accelerometer23SensorCorrectionsUpdateEb) +*(.text._ZN31MavlinkStreamAttitudeQuaternion8get_sizeEv) +*(.text._ZN30MavlinkStreamGlobalPositionInt4sendEv) +*(.text._ZN6SticksD1Ev) +*(.text._ZN13NavigatorMode3runEb) +*(.text._ZL19param_find_internalPKcb) +*(.text.uart_datasent) +*(.text._ZN4EKF221PublishOpticalFlowVelERKy) +*(.text.nxsem_destroy) +*(.text.file_write) +*(.text._ZN21MavlinkStreamAltitude4sendEv) +*(.text._ZN7sensors14VehicleAirData12UpdateStatusEv) +*(.text.imxrt_padmux_map) +*(.text._ZN6BMP38815get_sensor_dataEhP9bmp3_data) +*(.text._ZN18MavlinkRateLimiter5checkERKy) +*(.text._ZThn24_N26MulticopterAttitudeControl3RunEv) +*(.text.imxrt_periphclk_configure) +*(.text._ZN4EKF218UpdateAuxVelSampleER17ekf2_timestamps_s) +*(.text._ZN3RTL11on_inactiveEv) +*(.text._ZN12FailsafeBase10modeCanRunERK16failsafe_flags_sh) +*(.text._ZN4EKF216PublishEvPosBiasERKy) +*(.text._ZN21MavlinkStreamAttitude8get_sizeEv) +*(.text._ZThn16_N7sensors19VehicleAcceleration3RunEv) +*(.text._ZN33MavlinkStreamTimeEstimateToTarget4sendEv) +*(.text._ZN6matrix6MatrixIfLj3ELj1EE6setAllEf) +*(.text._ZN12ModuleParamsD1Ev) +*(.text._ZN3Ekf20controlFakeHgtFusionEv) +*(.text.imxrt_reqcomplete) +*(.text._ZNK6matrix7Vector3IfEmlEf) +*(.text._ZN18ZeroVelocityUpdate6updateER3EkfRKN9estimator9imuSampleE) +*(.text._ZN11ControlMath19addIfNotNanVector3fERN6matrix7Vector3IfEERKS2_) +*(.text._ZN11ControlMath16thrustToAttitudeERKN6matrix7Vector3IfEEfR27vehicle_attitude_setpoint_s) +*(.text.cos) +*(.text.net_unlock) +*(.text._ZN7sensors18VotedSensorsUpdate21setRelativeTimestampsER17sensor_combined_s) +*(.text._ZN12FailsafeBase13ActionOptionsC1ENS_6ActionE) +*(.text._ZN24FlightTaskManualAltitude16updateInitializeEv) +*(.text._ZN26MulticopterPositionControl3RunEv) +*(.text._ZN8Failsafe21fromQuadchuteActParamEi) +*(.text._ZN24VariableLengthRingbuffer9pop_frontEPhj) +*(.text._ZN7control15BlockDerivative6updateEf) /* itcm-check-ignore */ +*(.text._ZN9Commander18safetyButtonUpdateEv) +*(.text._ZN13BatteryChecks14checkAndReportERK7ContextR6Report) +*(.text._ZN18DataValidatorGroup16get_sensor_stateEj) +*(.text.uart_xmitchars_done) +*(.text._ZN4EKF225PublishYawEstimatorStatusERKy) +*(.text.sin) +*(.text._ZN6Safety19safetyButtonHandlerEv) +*(.text._ZN3Ekf19controlAuxVelFusionERKN9estimator9imuSampleE) +*(.text._ZNK6matrix6MatrixIfLj2ELj1EEplERKS1_) +*(.text._ZThn24_N7Sensors3RunEv) +*(.text._ZN6matrix6MatrixIfLj2ELj1EEC1ERKS1_) +*(.text._ZN10FlightTask10reActivateEv) +*(.text._ZNK15PositionControl19getAttitudeSetpointER27vehicle_attitude_setpoint_s) +*(.text._ZN4cdev4CDev4pollEP4fileP6pollfdb) +*(.text._ZN9Commander20offboardControlCheckEv) +*(.text._ZN4EKF216PublishGpsStatusERKy) +*(.text._ZN4uORB12SubscriptionaSEOS0_) +*(.text._ZN15TakeoffHandling18updateTakeoffStateEbbbfbRKy) +*(.text._ZN10ModeChecks14checkAndReportERK7ContextR6Report) +*(.text._ZN14FlightTaskAuto24_updateInternalWaypointsEv) +*(.text._ZN8Failsafe17updateArmingStateERKybRK16failsafe_flags_s) +*(.text.imxrt_lpi2c_modifyreg) +*(.text.up_flush_dcache) +*(.text._ZN15GyroCalibration3RunEv) +*(.text.mavlink_start_uart_send) +*(.text.MEM_DataCopy2) +*(.text._ZNK9Commander14getPrearmStateEv) +*(.text._ZN15EstimatorChecks14checkAndReportERK7ContextR6Report) +*(.text._ZN28FlightTaskManualAccelerationD1Ev) +*(.text._ZN11RateControl20getRateControlStatusER18rate_ctrl_status_s) +*(.text._ZN4uORB10DeviceNode15poll_notify_oneEP6pollfdm) +*(.text._ZN3GPS21handleInjectDataTopicEv.part.0) +*(.text._ZN9Commander17systemPowerUpdateEv) +*(.text._ZN4EKF221PublishGlobalPositionERKy) +*(.text._ZNK12FailsafeBase17getSelectedActionERKNS_5StateERK16failsafe_flags_sbbRNS_19SelectedActionStateE) +*(.text.imxrt_padctl_address) +*(.text._ZNK6matrix6VectorIfLj2EE4unitEv) +*(.text._ZN19RcCalibrationChecks14checkAndReportERK7ContextR6Report) +*(.text.devif_conn_callback_free) +*(.text._ZN13InnovationLpf6updateEfff.isra.0) +*(.text._ZN9Commander18landDetectorUpdateEv) +*(.text._ZN3Ekf18updateGroundEffectEv) +*(.text.nxsem_init) +*(.text._ZN9Commander16vtolStatusUpdateEv) +*(.text._ZN6matrix6MatrixIfLj4ELj1EEC1EPKf) +*(.text._ZN11ControlMath20setZeroIfNanVector3fERN6matrix7Vector3IfEE) +*(.text._ZThn8_N3ADC3RunEv) +*(.text._ZN11StickTiltXYC1EP12ModuleParams) +*(.text._ZN12SafetyButton3RunEv) +*(.text._ZN6BMP38811set_op_modeEh) +*(.text._ZN3GPS8callbackE15GPSCallbackTypePviS1_) +*(.text._ZN13AnalogBattery19get_current_channelEv) +*(.text._ZN15EstimatorChecks20checkEstimatorStatusERK7ContextR6ReportRK18estimator_status_s8NavModes) +*(.text._ZN12FailsafeBase11updateDelayERKy) +*(.text._ZN10FlightTask25_evaluateDistanceToGroundEv) +*(.text._ZN4EKF218PublishGnssHgtBiasERKy) +*(.text._ZN6matrix6VectorIfLj3EE9normalizeEv) +*(.text._ZThn16_N7sensors10VehicleIMU3RunEv) +*(.text.__kernel_cos) +*(.text._ZN12SafetyButton19CheckPairingRequestEb) +*(.text.imxrt_dma_txavailable) +*(.text.perf_set_elapsed) +*(.text.pthread_sem_take) +*(.text._ZN8StickYawD1Ev) +*(.text._Z15blink_msg_statev) +*(.text._ZN19AccelerometerChecks14checkAndReportERK7ContextR6Report) +*(.text._ZN8Failsafe14fromGfActParamEi) +*(.text._ZN3Ekf17controlBetaFusionERKN9estimator9imuSampleE) +*(.text._ZN36do_not_explicitly_use_this_namespace5ParamIfLN3px46paramsE919EEC1Ev) /* itcm-check-ignore */ +*(.text._ZN22MavlinkStreamHeartbeat8get_sizeEv) +*(.text._ZN6matrix6MatrixIfLj3ELj1EEdVEf) +*(.text._ZN17FlightTaskDescendC1Ev) +*(.text._ZN26MavlinkStreamCameraTrigger8get_sizeEv) +*(.text.iob_navail) +*(.text._ZN12FailsafeBase25removeNonActivatedActionsEv) +*(.text._ZN15TakeoffHandling10updateRampEff) +*(.text._Z7led_offi) +*(.text.led_off) +*(.text.udp_wrbuffer_test) +*(.text._ZNK4math17WelfordMeanVectorIfLj3EE8varianceEv) +*(.text._ZN27MavlinkStreamAttitudeTarget4sendEv) +*(.text._ZN12MixingOutput19updateSubscriptionsEb) +*(.text._ZN10FlightTaskD1Ev) +*(.text._ZThn24_N13land_detector12LandDetector3RunEv) +*(.text._ZN18MavlinkStreamDebug8get_sizeEv) +*(.text._ZN12GPSDriverUBX7receiveEj) +*(.text._ZN13BatteryStatus21parameter_update_pollEb) +*(.text._ZN3RTL18updateDatamanCacheEv) +*(.text.__ieee754_sqrtf) +*(.text._ZThn24_N18mag_bias_estimator16MagBiasEstimator3RunEv) +*(.text.__kernel_sin) +*(.text._ZN11MissionBase17parameters_updateEv) +*(.text.nx_start) +*(.text._ZN3Ekf17controlDragFusionERKN9estimator9imuSampleE) +*(.text._ZNK8Failsafe22modifyUserIntendedModeEN12FailsafeBase6ActionES1_h) +*(.text._ZN3px417ScheduledWorkItem19schedule_trampolineEPv) +*(.text.uart_xmitchars_dma) +*(.text._ZN13land_detector23MulticopterLandDetector19_get_freefall_stateEv) +*(.text._ZThn24_N31MulticopterHoverThrustEstimator3RunEv) +*(.text._ZN11MissionBase11on_inactiveEv) +*(.text._ZN21FailureDetectorChecks14checkAndReportERK7ContextR6Report) +*(.text._ZN12SystemChecks14checkAndReportERK7ContextR6Report) +*(.text._ZN6matrix6MatrixIfLj3ELj1EEC1EPKf) +*(.text.imxrt_padmux_address) +*(.text._ZN19MavlinkStreamVFRHUD8get_sizeEv) +*(.text._ZN15EstimatorChecks15checkSensorBiasERK7ContextR6Report8NavModes) +*(.text._ZN20ImuConsistencyChecks14checkAndReportERK7ContextR6Report) +*(.text._ZN28MavlinkStreamGpsGlobalOrigin8get_sizeEv) +*(.text.MEM_DataCopy2_1) +*(.text._ZN6BMP3887measureEv) +*(.text._ZN4EKF217PublishRngHgtBiasERKy) +*(.text._ZN36MavlinkStreamPositionTargetGlobalInt8get_sizeEv) +*(.text._ZN28MavlinkStreamEstimatorStatus8get_sizeEv) +*(.text.up_clean_dcache) +*(.text._ZThn24_N26MulticopterPositionControl3RunEv) +*(.text._ZN16FlightTimeChecks14checkAndReportERK7ContextR6Report) +*(.text._ZN13ManualControl12processInputEy) +*(.text._ZN17CpuResourceChecks14checkAndReportERK7ContextR6Report) +*(.text._ZN10GyroChecks14checkAndReportERK7ContextR6Report) +*(.text._ZN8Failsafe26fromImbalancedPropActParamEi) +*(.text._ZThn24_N13BatteryStatus3RunEv) +*(.text.mm_foreach) +*(.text._ZN35MavlinkStreamPositionTargetLocalNed8get_sizeEv) +*(.text._ZN32MavlinkStreamNavControllerOutput8get_sizeEv) +*(.text._ZN6matrix8wrap_2piIfEET_S1_) +*(.text._ZN4uORB7Manager30orb_remove_internal_subscriberEPv) +*(.text._ZN10BMP388_I2C7get_regEhPh) +*(.text._ZN4math17WelfordMeanVectorIfLj3EE5resetEv) +*(.text._ZN27MavlinkStreamScaledPressure8get_sizeEv) +*(.text._ZN3RTL17parameters_updateEv) +*(.text._ZN18EstimatorInterface11setBaroDataERKN9estimator10baroSampleE.part.0) +*(.text._ZN32MavlinkStreamOpenDroneIdLocation8get_sizeEv) +*(.text._ZN21MavlinkStreamTimesync4sendEv) +*(.text._ZN9Navigator23reset_position_setpointER19position_setpoint_s) +*(.text._ZN19RcAndDataLinkChecks14checkAndReportERK7ContextR6Report) +*(.text.imxrt_dma_txcallback) +*(.text._ZN24MavlinkParametersManager11send_uavcanEv) +*(.text._ZN4uORB10DeviceNode4readEP4filePcj) +*(.text._ZN4uORB10DeviceNode10poll_stateEP4file) +*(.text._ZN4uORB7Manager8orb_copyEPK12orb_metadataiPv) +*(.text._ZN27MavlinkStreamServoOutputRawILi0EE8get_sizeEv) +*(.text._ZN8Geofence3runEv) +*(.text._ZN15EstimatorChecks25checkEstimatorStatusFlagsERK7ContextR6ReportRK18estimator_status_sRK24vehicle_local_position_s) +*(.text._ZN18MagnetometerChecks14checkAndReportERK7ContextR6Report) +*(.text._ZN6events9SendEvent3RunEv) +*(.text._ZN30MavlinkStreamGlobalPositionInt8get_sizeEv) +*(.text._ZN22MavlinkStreamESCStatus8get_sizeEv) +*(.text._Z20px4_spi_bus_externalRK13px4_spi_bus_t) +*(.text.read) +*(.text._ZN4uORB15PublicationBaseD1Ev) +*(.text._ZN22MavlinkStreamDebugVect8get_sizeEv) +*(.text._ZN7Mission11on_inactiveEv) +*(.text._ZN7sensors19VehicleMagnetometer20UpdateMagCalibrationEv) +*(.text._ZN11calibration27FindCurrentCalibrationIndexEPKcm) +*(.text._ZN4cdevL9cdev_readEP4filePcj) +*(.text.sem_timedwait) +*(.text.snprintf) +*(.text._ZN27MavlinkStreamOpticalFlowRad8get_sizeEv) +*(.text._ZNK6matrix6MatrixIfLj3ELj1EE6copyToEPf) +*(.text._ZN6Report13healthFailureIJhEEEv8NavModes20HealthComponentIndexmRKN6events9LogLevelsEPKcDpT_.isra.0.constprop.0) +*(.text._ZN13BatteryChecks16rtlEstimateCheckERK7ContextR6Reportf) +*(.text.sigemptyset) +*(.text.nx_read) diff --git a/boards/nxp/mr-tropic/nuttx-config/scripts/itcm_static_functions.ld b/boards/nxp/mr-tropic/nuttx-config/scripts/itcm_static_functions.ld new file mode 100644 index 0000000000..bc0b57099c --- /dev/null +++ b/boards/nxp/mr-tropic/nuttx-config/scripts/itcm_static_functions.ld @@ -0,0 +1,163 @@ +/* Static */ +*(.text.arm_ack_irq) +*(.text.arm_doirq) +*(.text.arm_svcall) +*(.text.arm_switchcontext) +*(.text.clock_timer) +*(.text.exception_common) +*(.text.flexio_irq_handler) +*(.text.hrt_absolute_time) +*(.text.hrt_call_enter) +*(.text.hrt_tim_isr) +*(.text.imxrt_configwaitints) +*(.text.imxrt_dma_callback) +*(.text.imxrt_dmach_interrupt) +*(.text.imxrt_dmach_xfrsetup) +*(.text.imxrt_dmaterminate) +*(.text.imxrt_dispatch) +*(.text.imxrt_edma_interrupt) +*(.text.imxrt_endwait) +*(.text.imxrt_enet_interrupt) +*(.text.imxrt_enet_interrupt_work) +*(.text.imxrt_interrupt) +*(.text.imxrt_gpio1_16_31_interrupt) +*(.text.imxrt_gpio2_0_15_interrupt) +*(.text.imxrt_lpi2c_isr) +*(.text.imxrt_lpspi3select) +*(.text.imxrt_lpspi4select) +*(.text.imxrt_lpspi_exchange) +*(.text.imxrt_recvdma) +*(.text.imxrt_tcd_free) +*(.text.imxrt_timerisr) +*(.text.imxrt_transmit) +*(.text.imxrt_txdone) +*(.text.imxrt_txtimeout_work) +*(.text.imxrt_txtimeout_expiry) +*(.text.imxrt_txpoll) +*(.text.imxrt_txringfull) +*(.text.imxrt_txavail_work) +*(.text.imxrt_txavail) +*(.text.imxrt_usbinterrupt) +*(.text.irq_dispatch) +*(.text.ioctl) +*(.text.memcpy) +*(.text.memset) +*(.text.nxsched_add_blocked) +*(.text.nxsched_add_prioritized) +*(.text.nxsched_add_readytorun) +*(.text.nxsched_get_files) +*(.text.nxsched_get_tcb) +*(.text.nxsched_merge_pending) +*(.text.nxsched_process_timer) +*(.text.nxsched_remove_blocked) +*(.text.nxsched_remove_readytorun) +*(.text.nxsched_resume_scheduler) +*(.text.nxsched_suspend_scheduler) +*(.text.nxsem_add_holder) +*(.text.nxsem_add_holder_tcb) +*(.text.nxsem_clockwait) +*(.text.nxsem_foreachholder) +*(.text.nxsem_freecount0holder) +*(.text.nxsem_freeholder) +*(.text.nxsem_post) +*(.text.nxsem_release_holder) +*(.text.nxsem_restore_baseprio) +*(.text.nxsem_tickwait) +*(.text.nxsem_timeout) +*(.text.nxsem_trywait) +*(.text.nxsem_wait) +*(.text.nxsem_wait_uninterruptible) +*(.text.nxsig_timedwait) +*(.text.sched_lock) +*(.text.sched_note_resume) +*(.text.sched_note_suspend) +*(.text.sched_unlock) +*(.text.strcmp) +*(.text.sq_addafter) +*(.text.sq_addlast) +*(.text.sq_rem) +*(.text.sq_remafter) +*(.text.sq_remfirst) +*(.text.uart_connected) +*(.text.up_block_task) +*(.text.up_unblock_task) +*(.text.wd_timer) +*(.text.wd_start) +*(.text.work_thread) +*(.text.work_queue) +*(.text._do_memcpy) + +/* Tropic Eth tune */ +*(.text.devif_poll) +*(.text.devif_poll_tcp_connections) +*(.text.tcp_poll) +*(.text.devif_poll_udp_connections) +*(.text.udp_nextconn) +*(.text.udp_poll) +*(.text.udp_ipv4_select) +*(.text.udp_callback) +*(.text.udp_datahandler) +*(.text.udp_send) +*(.text.udp_active) +*(.text.udp_ipv4_active) +*(.text.psock_udp_sendto) +*(.text.sendto_eventhandler) +*(.text.net_dataevent) +*(.text.devif_conn_event) +*(.text.devif_event_trigger) +*(.text.devif_poll_icmp) +*(.text.icmp_poll) +*(.text.arp_out) +*(.text.arp_find) +*(.text.arp_format) +*(.text.net_ipv4addr_hdrcmp) /* itcm-check-ignore */ +*(.text.net_ipv4addr_copy) /* itcm-check-ignore */ +*(.text.net_ipv4addr_broadcast) /* itcm-check-ignore */ +*(.text.wd_start) +*(.text.arp_arpin) +*(.text.ipv4_input) +*(.text.work_thread) +*(.text.work_queue) + +/* ICM45686 */ +*(.text._ZN8ICM4568612ProcessAccelERKyPKN19InvenSense_ICM456864FIFO4DATAEh) +*(.text._ZN8ICM4568611ProcessGyroERKyPKN19InvenSense_ICM456864FIFO4DATAEh) +*(.text._ZN8ICM456868FIFOReadERKy) +*(.text._ZN8ICM456867RunImplEv) +*(.text._ZN8ICM4568618ProcessTemperatureEPKN19InvenSense_ICM456864FIFO4DATAEh) +*(.text._ZN12I2CSPIDriverI8ICM45686E3RunEv) +*(.text._ZN8ICM4568613FIFOReadCountEv) + +/* BMI088 */ +*(.text._ZN5Bosch6BMI08813Accelerometer20BMI088_Accelerometer12RegisterReadENS1_8RegisterE) +*(.text._ZN5Bosch6BMI08813Accelerometer20BMI088_Accelerometer13FIFOReadCountEv) +*(.text._ZN5Bosch6BMI08813Accelerometer20BMI088_Accelerometer8FIFOReadERKyh) +*(.text._ZN5Bosch6BMI08813Accelerometer20BMI088_Accelerometer13RegisterCheckERKNS2_17register_config_tE) +*(.text._ZN5Bosch6BMI08813Accelerometer20BMI088_Accelerometer13RegisterWriteENS1_8RegisterEh) +*(.text._ZN5Bosch6BMI08813Accelerometer20BMI088_Accelerometer17UpdateTemperatureEv) +*(.text._ZN5Bosch6BMI08813Accelerometer20BMI088_Accelerometer23RegisterSetAndClearBitsENS1_8RegisterEhh) +*(.text._ZN5Bosch6BMI08813Accelerometer20BMI088_Accelerometer26DataReadyInterruptCallbackEiPvS3_) +*(.text._ZN5Bosch6BMI08813Accelerometer20BMI088_Accelerometer7RunImplEv) +*(.text._ZN5Bosch6BMI08813Accelerometer20BMI088_Accelerometer9DataReadyEv) +*(.text._ZN5Bosch6BMI08813Accelerometer20BMI088_AccelerometerD0Ev) +*(.text._ZN5Bosch6BMI08813Accelerometer20BMI088_AccelerometerD1Ev) +*(.text._ZN5Bosch6BMI08813Accelerometer20BMI088_AccelerometerD2Ev) +*(.text._ZN5Bosch6BMI0889Gyroscope16BMI088_Gyroscope12RegisterReadENS1_8RegisterE) +*(.text._ZN5Bosch6BMI0889Gyroscope16BMI088_Gyroscope13RegisterCheckERKNS2_17register_config_tE) +*(.text._ZN5Bosch6BMI0889Gyroscope16BMI088_Gyroscope13RegisterWriteENS1_8RegisterEh) +*(.text._ZN5Bosch6BMI0889Gyroscope16BMI088_Gyroscope23RegisterSetAndClearBitsENS1_8RegisterEhh) +*(.text._ZN5Bosch6BMI0889Gyroscope16BMI088_Gyroscope26DataReadyInterruptCallbackEiPvS3_) +*(.text._ZN5Bosch6BMI0889Gyroscope16BMI088_Gyroscope7RunImplEv) +*(.text._ZN5Bosch6BMI0889Gyroscope16BMI088_Gyroscope8FIFOReadERKyh) +*(.text._ZN5Bosch6BMI0889Gyroscope16BMI088_Gyroscope9DataReadyEv) +*(.text._ZN5Bosch6BMI0889Gyroscope16BMI088_GyroscopeD0Ev) +*(.text._ZN5Bosch6BMI0889Gyroscope16BMI088_GyroscopeD1Ev) +*(.text._ZN5Bosch6BMI0889Gyroscope16BMI088_GyroscopeD2Ev) +*(.text._ZN12I2CSPIDriverI6BMI088E3RunEv) + +/* BMM350 */ +*(.text._ZN12I2CSPIDriverI6BMM350E3RunEv) +*(.text._ZN6BMM3507RunImplEv) +*(.text._ZN6BMM35013RegisterWriteEN12Bosch_BMM3508RegisterEh) +*(.text._ZN6BMM35012RegisterReadEN12Bosch_BMM3508RegisterEPh) +*(.text._ZN6BMM35014ReadOutRawDataEPf) diff --git a/boards/nxp/mr-tropic/nuttx-config/scripts/script.ld b/boards/nxp/mr-tropic/nuttx-config/scripts/script.ld new file mode 100644 index 0000000000..8e5f852a82 --- /dev/null +++ b/boards/nxp/mr-tropic/nuttx-config/scripts/script.ld @@ -0,0 +1,187 @@ +/**************************************************************************** + * boards/nxp/mr-tropic/nuttx-config/scripts/script.ld + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Specify the memory areas */ + +MEMORY +{ + flash (rx) : ORIGIN = 0x70020000, LENGTH = 4194304 - 256K + sram (rwx) : ORIGIN = 0x20200000, LENGTH = 512K + itcm (rwx) : ORIGIN = 0x00000000, LENGTH = 384K + dtcm (rwx) : ORIGIN = 0x20000000, LENGTH = 127K + dtcm_nocache (rwx) : ORIGIN = 0x2001FC00, LENGTH = 1K +} + +OUTPUT_ARCH(arm) +EXTERN(_vectors) +EXTERN(g_flash_config) +EXTERN(g_image_vector_table) +EXTERN(g_boot_data) +EXTERN(board_get_manifest) +EXTERN(_bootdelay_signature) + +ENTRY(_stext) + +SECTIONS +{ + /* Image Vector Table and Boot Data for booting from external flash */ + + .boot_hdr : ALIGN(4) + { + FILL(0xff) + __boot_hdr_start__ = ABSOLUTE(.) ; + KEEP(*(.boot_hdr.conf)) + . = 0x1000 ; + KEEP(*(.boot_hdr.ivt)) + . = 0x1020 ; + KEEP(*(.boot_hdr.boot_data)) + . = 0x1030 ; + KEEP(*(.boot_hdr.dcd_data)) + __boot_hdr_end__ = ABSOLUTE(.) ; + . = 0x2000 ; + } >flash + + /* Workaround for ethernet issue, by placing g_desc_pool into DTCM, + which effectively puts it into a no-cache region */ + .dtcm_nocache : { + *(.bss.g_desc_pool) + } > dtcm_nocache + + .vectors : + { + KEEP(*(.vectors)) + *(.text .text.__start) + } >flash + + .itcmfunc : + { + . = ALIGN(8); + _sitcmfuncs = ABSOLUTE(.); + FILL(0xFF) + . = 0x40 ; + *(.ram_vectors) + INCLUDE "itcm_static_functions.ld" + INCLUDE "itcm_functions_includes.ld" + . = ALIGN(8); + _eitcmfuncs = ABSOLUTE(.); + } > itcm AT > flash + + _fitcmfuncs = LOADADDR(.itcmfunc); + + .text : + { + _stext = ABSOLUTE(.); + *(.vectors) + . = ALIGN(32); + /* + This signature provides the bootloader with a way to delay booting + */ + _bootdelay_signature = ABSOLUTE(.); + FILL(0xffecc2925d7d05c5) + . += 8; + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.gnu.linkonce.t.*) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + . = ALIGN(4096); + _etext = ABSOLUTE(.); + _srodata = ABSOLUTE(.); + *(.rodata .rodata.*) + . = ALIGN(4096); + _erodata = ABSOLUTE(.); + } > flash + + .init_section : + { + _sinit = ABSOLUTE(.); + KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP(*(.init_array .ctors)) + _einit = ABSOLUTE(.); + } > flash + + .ARM.extab : + { + *(.ARM.extab*) + } > flash + + .ARM.exidx : + { + __exidx_start = ABSOLUTE(.); + *(.ARM.exidx*) + __exidx_end = ABSOLUTE(.); + } > flash + + _eronly = ABSOLUTE(.); + + .data : + { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + . = ALIGN(4); + _edata = ABSOLUTE(.); + } > sram AT > flash + + .ramfunc ALIGN(4): + { + _sramfuncs = ABSOLUTE(.); + *(.ramfunc .ramfunc.*) + _eramfuncs = ABSOLUTE(.); + } > sram AT > flash + + _framfuncs = LOADADDR(.ramfunc); + + .bss : + { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = ABSOLUTE(.); + } > sram + + /* Stabs debugging sections. */ + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } + + _boot_loadaddr = ORIGIN(flash); + _boot_size = LENGTH(flash); + _ram_size = LENGTH(sram); + _sdtcm = ORIGIN(dtcm); + _edtcm = ORIGIN(dtcm) + LENGTH(dtcm); +} diff --git a/boards/nxp/mr-tropic/src/CMakeLists.txt b/boards/nxp/mr-tropic/src/CMakeLists.txt new file mode 100644 index 0000000000..4f0710f546 --- /dev/null +++ b/boards/nxp/mr-tropic/src/CMakeLists.txt @@ -0,0 +1,86 @@ +############################################################################ +# +# Copyright (c) 2024 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. +# +############################################################################ +if("${PX4_BOARD_LABEL}" STREQUAL "bootloader") + add_compile_definitions(BOOTLOADER) + add_library(drivers_board + bootloader_main.c + init.c + usb.c + imxrt_flexspi_nor_boot.c + imxrt_flexspi_nor_flash.c + timer_config.cpp + ) + target_link_libraries(drivers_board + PRIVATE + nuttx_arch # sdio + nuttx_drivers # sdio + px4_layer #gpio + arch_io_pins # iotimer + arch_board_romapi + bootloader + ) + target_include_directories(drivers_board PRIVATE ${PX4_SOURCE_DIR}/platforms/nuttx/src/bootloader/common) + +else() + + px4_add_library(drivers_board + i2c.cpp + init.c + sdhc.c + spi.cpp + timer_config.cpp + tropic_led_pwm.cpp + usb.c + imxrt_flexspi_nor_boot.c + imxrt_flexspi_nor_flash.c + imxrt_flexspi_storage.c + imxrt_ocram_initialize.c + hw_rev_ver_tropic.c + manifest.c + ) + + + # Force compiler not to use builtin functions (like memcpy) + # to optimize for loops in init.c (imxrt_ocram_initialize) + set_source_files_properties(imxrt_ocram_initialize.c PROPERTIES COMPILE_FLAGS -fno-builtin) + + target_link_libraries(drivers_board + PRIVATE + arch_board_romapi + arch_spi + nuttx_arch # sdio + nuttx_drivers # sdio + px4_layer + ) + +endif() diff --git a/boards/nxp/mr-tropic/src/board_config.h b/boards/nxp/mr-tropic/src/board_config.h new file mode 100644 index 0000000000..45e6eecd54 --- /dev/null +++ b/boards/nxp/mr-tropic/src/board_config.h @@ -0,0 +1,355 @@ +/**************************************************************************** + * + * Copyright (c) 2024 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 board_config.h + * + * Tropic Community internal definitions + */ + +#pragma once + +/**************************************************************************************************** + * Included Files + ****************************************************************************************************/ + +#include +#include +#include +#include + +#include "imxrt_gpio.h" +#include "imxrt_iomuxc.h" +#include "hardware/imxrt_pinmux.h" +#include "hardware/imxrt_usb_analog.h" + +#include +#include + +/**************************************************************************************************** + * Definitions + ****************************************************************************************************/ + +/* Configuration ************************************************************************************/ + +/* FMURT1062 GPIOs ***********************************************************************************/ +/* LEDs */ +/* An RGB LED is connected through GPIO as shown below: + */ +#define LED_IOMUX (IOMUX_OPENDRAIN | IOMUX_PULL_NONE | IOMUX_DRIVE_33OHM | IOMUX_SPEED_MEDIUM | IOMUX_SLEW_SLOW) +#define GPIO_nLED_RED /* GPIO_EMC_33 GPIO3_IO19 */ (GPIO_PORT3 | GPIO_PIN19 | GPIO_OUTPUT | GPIO_OUTPUT_ONE | LED_IOMUX) +#define GPIO_nLED_BLUE /* GPIO_EMC_34 GPIO3_IO20 */ (GPIO_PORT3 | GPIO_PIN20 | GPIO_OUTPUT | GPIO_OUTPUT_ONE | LED_IOMUX) +#define GPIO_nLED_GREEN /* GPIO_EMC_38 GPIO3_IO24 */ (GPIO_PORT3 | GPIO_PIN24 | GPIO_OUTPUT | GPIO_OUTPUT_ONE | LED_IOMUX) + +#define BOARD_HAS_CONTROL_STATUS_LEDS 1 +#define BOARD_OVERLOAD_LED LED_RED +#define BOARD_ARMED_STATE_LED LED_BLUE + +/* + * Define the ability to shut off off the sensor signals + * by changing the signals to inputs + */ + +#define _PIN_OFF(def) (((def) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | (GPIO_INPUT | IOMUX_PULL_DOWN_100K | IOMUX_CMOS_INPUT)) + +/* Define the Chip Selects, Data Ready and Control signals per SPI bus */ + +#define CS_IOMUX (IOMUX_CMOS_OUTPUT | IOMUX_PULL_UP_100K | IOMUX_DRIVE_33OHM | IOMUX_SPEED_LOW | IOMUX_SLEW_FAST) +#define OUT_IOMUX (IOMUX_CMOS_OUTPUT | IOMUX_PULL_UP_100K | IOMUX_DRIVE_50OHM | IOMUX_SPEED_MEDIUM | IOMUX_SLEW_FAST) + + +/* SPI1 off */ + +#define _GPIO_LPSPI1_SCK /* GPIO_EMC_27 GPIO4_IO27 */ (GPIO_PORT4 | GPIO_PIN27 | CS_IOMUX) +#define _GPIO_LPSPI1_MISO /* GPIO_EMC_29 GPIO4_IO29 */ (GPIO_PORT4 | GPIO_PIN29 | CS_IOMUX) +#define _GPIO_LPSPI1_MOSI /* GPIO_EMC_28 GPIO4_IO28 */ (GPIO_PORT4 | GPIO_PIN28 | CS_IOMUX) + +#define GPIO_SPI1_SCK_OFF _PIN_OFF(_GPIO_LPSPI1_SCK) +#define GPIO_SPI1_MISO_OFF _PIN_OFF(_GPIO_LPSPI1_MISO) +#define GPIO_SPI1_MOSI_OFF _PIN_OFF(_GPIO_LPSPI1_MOSI) + +#define _GPIO_LPSPI3_SCK /* GPIO_AD_B1_15 GPIO1_IO27 */ (GPIO_PORT1 | GPIO_PIN31 | CS_IOMUX) +#define _GPIO_LPSPI3_MISO /* GPIO_AD_B1_13 GPIO1_IO27 */ (GPIO_PORT1 | GPIO_PIN29 | CS_IOMUX) +#define _GPIO_LPSPI3_MOSI /* GPIO_AD_B1_14 GPIO1_IO27 */ (GPIO_PORT1 | GPIO_PIN30 | CS_IOMUX) + +#define GPIO_SPI3_SCK_OFF _PIN_OFF(_GPIO_LPSPI3_SCK) +#define GPIO_SPI3_MISO_OFF _PIN_OFF(_GPIO_LPSPI3_MISO) +#define GPIO_SPI3_MOSI_OFF _PIN_OFF(_GPIO_LPSPI3_MOSI) + +/* Define the SPI4 Data Ready and Control signals */ + +#define GPIO_SPI4_DRDY7_EXTERNAL1 /* GPIO_EMC_35 GPIO3_IO21*/ (GPIO_PORT3 | GPIO_PIN21 | GPIO_INPUT | DRDY_IOMUX) + +#define GPIO_DRDY_OFF_SPI4_DRDY7_EXTERNAL1 _PIN_OFF(GPIO_SPI4_DRDY7_EXTERNAL1) + +#define ADC_IOMUX (IOMUX_CMOS_INPUT | IOMUX_PULL_NONE | IOMUX_DRIVE_HIZ) + +#define ADC1_CH(n) (n) +#define ADC1_GPIO(n, p) (GPIO_PORT1 | GPIO_PIN##p | ADC_IOMUX) // + +/* Define GPIO pins used as ADC N.B. Channel numbers are for reference, */ + +#define PX4_ADC_GPIO \ + /* ADC_5V_RAIL_SENSE GPIO_AD_B1_08 GPIO1 Pin 24 */ ADC1_GPIO(0, 24) + +/* Define Channel numbers must match above GPIO pin IN(n)*/ + +#define ADC_5V_RAIL_SENSE /* GPIO_AD_B1_08 GPIO1 Pin 24 */ ADC1_CH(13) + +#define ADC_CHANNELS (1 << ADC_5V_RAIL_SENSE) + +/* Power supply control and monitoring GPIOs */ + +#define GENERAL_INPUT_IOMUX (IOMUX_CMOS_INPUT | 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) + + +/* PWM + */ + +#define DIRECT_PWM_OUTPUT_CHANNELS 8 +#define BOARD_NUM_IO_TIMERS 4 + +// Input Capture not supported on MVP + +#define BOARD_HAS_NO_CAPTURE + +//#define BOARD_HAS_UI_LED_PWM 1 Not ported yet (Still Kinetis driver) +#define BOARD_HAS_LED_PWM 1 +#define BOARD_LED_PWM_DRIVE_ACTIVE_LOW 1 +#define BOARD_HAS_CUSTOM_LED_PWM 1 + +#define PWM_LED_RED /* GPIO_EMC_33 */ (GPIO_FLEXPWM3_PWMA02_1 | GENERAL_OUTPUT_IOMUX) +#define PWM_LED_BLUE /* GPIO_EMC_34 */ (GPIO_FLEXPWM3_PWMB02_1 | GENERAL_OUTPUT_IOMUX) +#define PWM_LED_GREEN /* GPIO_EMC_38 */ (GPIO_FLEXPWM1_PWMA03_2 | GENERAL_OUTPUT_IOMUX) + + +/* ETHERNET GPIO */ + +#define GPIO_ENET_RX_ER_CONFIG1 /* GPIO_B1_11 GPIO2_IO27 PHYAD18 Open */ (GPIO_PORT2 | GPIO_PIN27 | GPIO_INPUT | IOMUX_PULL_NONE) +#define GPIO_ENET_RX_DATA01_CONFIG4 /* GPIO_B1_05 GPIO2_IO21 (RMII-clkmode) High */ (GPIO_PORT2 | GPIO_PIN21 | GPIO_OUTPUT | GPIO_OUTPUT_ONE | GENERAL_OUTPUT_IOMUX) +#define GPIO_ENET_RX_DATA00_CONFIG5 /* GPIO_B1_04 GPIO2_IO20 SLAVE:Auto Open */ (GPIO_PORT2 | GPIO_PIN20 | GPIO_INPUT | IOMUX_PULL_NONE) +#define GPIO_ENET_CRS_DV_CONFIG6 /* GPIO_B1_06 GPIO4_IO22 SLAVE:POl Corr Low */ (GPIO_PORT2 | GPIO_PIN22 | GPIO_OUTPUT | GPIO_OUTPUT_ZERO | GENERAL_OUTPUT_IOMUX) + +/* Tone alarm output */ + +//FIXME FlexPWM TONE DRIVER +#define TONE_ALARM_FLEXPWM PWMA_VAL +#define TONE_ALARM_TIMER 1 /* FlexPWM 3 */ +#define TONE_ALARM_CHANNEL 0 /* GPIO_EMC_23 PWM1_PWMA00 */ + +#define GPIO_BUZZER_1 /* GPIO_EMC_23 GPIO4_IO23 */ (GPIO_PORT4 | GPIO_PIN23 | GPIO_OUTPUT | GPIO_OUTPUT_ZERO | GENERAL_OUTPUT_IOMUX) + +#define GPIO_TONE_ALARM_IDLE GPIO_BUZZER_1 +#define GPIO_TONE_ALARM (GPIO_FLEXPWM1_PWMA00_1 | GENERAL_OUTPUT_IOMUX) + +/* USB OTG FS + * + * VBUS_VALID is detected in USB_ANALOG_USB1_VBUS_DETECT_STAT + */ + +/* High-resolution timer */ +#define HRT_TIMER 1 /* use GPT1 for the HRT */ +#define HRT_TIMER_CHANNEL 1 /* use capture/compare channel 1 */ + +#define RC_SERIAL_PORT "/dev/ttyS6" +//#define RC_SERIAL_SINGLEWIRE 1 // Suport Single wire wiring +//#define RC_SERIAL_SWAP_RXTX 1 // Set Swap (but not supported in HW) to use Single wire +//#define RC_SERIAL_SWAP_USING_SINGLEWIRE 1 // Set to use Single wire swap as HW does not support swap +#define BOARD_SUPPORTS_RC_SERIAL_PORT_OUTPUT + +/* Safety Switch is HW version dependent on having an PX4IO + * So we init to a benign state with the _INIT definition + * and provide the the non _INIT one for the driver to make a run time + * decision to use it. + */ +#define SAFETY_INIT_IOMUX (IOMUX_CMOS_INPUT | IOMUX_PULL_NONE | IOMUX_DRIVE_HIZ) +#define SAFETY_IOMUX (IOMUX_CMOS_OUTPUT | IOMUX_PULL_NONE | IOMUX_DRIVE_33OHM | IOMUX_SPEED_MEDIUM | IOMUX_SLEW_SLOW) +#define SAFETY_SW_IOMUX (IOMUX_CMOS_INPUT | IOMUX_PULL_UP_22K | IOMUX_DRIVE_HIZ) + +/* Safety Switch is HW version dependent on having an PX4IO + * So we init to a benign state with the _INIT definition + * and provide the the non _INIT one for the driver to make a run time + * decision to use it. + */ +#define GPIO_nSAFETY_SWITCH_LED_OUT_INIT /* EMC_39 */ (GPIO_PORT3 | GPIO_PIN25 | GPIO_INPUT | SAFETY_INIT_IOMUX) +#define GPIO_nSAFETY_SWITCH_LED_OUT /* EMC_39 */ (GPIO_PORT3 | GPIO_PIN25 | GPIO_OUTPUT | GPIO_OUTPUT_ONE | SAFETY_IOMUX) + +/* Enable the FMU to control it if there is no px4io fixme:This should be BOARD_SAFETY_LED(__ontrue) */ +#define GPIO_LED_SAFETY GPIO_nSAFETY_SWITCH_LED_OUT + +#define GPIO_SAFETY_SWITCH_IN /* GPIO_B0_12 GPIO2_IO12 */ (GPIO_PORT2 | GPIO_PIN12 | GPIO_INPUT | SAFETY_SW_IOMUX) +/* Enable the FMU to use the switch it if there is no px4io fixme:This should be BOARD_SAFTY_BUTTON() */ +#define GPIO_BTN_SAFETY GPIO_SAFETY_SWITCH_IN /* Enable the FMU to control it if there is no px4io */ + +#define SDIO_SLOTNO 0 /* Only one slot */ +#define SDIO_MINOR 0 + +/* SD card bringup does not work if performed on the IDLE thread because it + * will cause waiting. Use either: + * + * CONFIG_BOARDCTL=y, OR + * CONFIG_BOARD_INITIALIZE=y && CONFIG_BOARD_INITTHREAD=y + */ + +#if defined(CONFIG_BOARD_INITIALIZE) && !defined(CONFIG_BOARDCTL) && \ + !defined(CONFIG_BOARD_INITTHREAD) +# warning SDIO initialization cannot be perfomed on the IDLE thread +#endif + +/* By Providing BOARD_ADC_USB_CONNECTED (using the px4_arch abstraction) + * this board support the ADC system_power interface, and therefore + * provides the true logic GPIO BOARD_ADC_xxxx macros. + */ + +#define BOARD_NUMBER_BRICKS 1 +#define BOARD_NUMBER_DIGITAL_BRICKS 1 + +#define BOARD_ADC_BRICK_VALID 1 + +#define BOARD_ADC_USB_CONNECTED (board_read_VBUS_state() == 0) + +/* FMUv5 never powers odd the Servo rail */ + +#define BOARD_ADC_SERVO_VALID (1) + + +/* This board provides a DMA pool and APIs */ +#define BOARD_DMA_ALLOC_POOL_SIZE 5120 + +/* This board provides the board_on_reset interface */ + +#define BOARD_HAS_ON_RESET 1 +#define BOARD_HAS_ISP_BOOTLOADER 1 + +#define PX4_GPIO_INIT_LIST { \ + GPIO_FLEXCAN3_TX, \ + GPIO_FLEXCAN3_RX, \ + GPIO_TONE_ALARM_IDLE, \ + GPIO_SAFETY_SWITCH_IN, \ + GPIO_ENET_RX_ER_CONFIG1, \ + GPIO_ENET_RX_DATA01_CONFIG4, \ + GPIO_ENET_RX_DATA00_CONFIG5, \ + GPIO_ENET_CRS_DV_CONFIG6, \ + GPIO_ENET_RST \ + } + +#define BOARD_ENABLE_CONSOLE_BUFFER + +/* To detect IMU */ +#define BOARD_HAS_HW_VERSIONING 1 +#define BOARD_HAS_HW_SPLIT_VERSIONING 1 +#define HW_INFO_INIT_PREFIX "TROPIC" + +#define BOARD_NUM_SPI_CFG_HW_VERSIONS 3 +// Base/FMUM +#define TROPIC_0 HW_FMUM_ID(0x0) // ICM45686 +#define TROPIC_1 HW_FMUM_ID(0x1) // ICM42688 +#define TROPIC_2 HW_FMUM_ID(0x2) // ICM42686 + +/* Flash instance for storage */ +#define NOR_INSTANCE 1 + +__BEGIN_DECLS + +/**************************************************************************************************** + * Public Types + ****************************************************************************************************/ + +/**************************************************************************************************** + * Public data + ****************************************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************************************** + * Public Functions + ****************************************************************************************************/ + +/**************************************************************************** + * Name: fmurt1062_usdhc_initialize + * + * Description: + * Initialize SDIO-based MMC/SD card support + * + ****************************************************************************/ + +int fmurt1062_usdhc_initialize(void); + +/**************************************************************************************************** + * Name: imxrt_spidev_initialize + * + * Description: + * Called to configure SPI chip select GPIO pins for the PX4FMU board. + * + ****************************************************************************************************/ + +extern void imxrt_spidev_initialize(void); + +/************************************************************************************ + * Name: imxrt_spi_bus_initialize + * + * Description: + * Called to configure SPI Buses. + * + ************************************************************************************/ + +extern int imxrt1062_spi_bus_initialize(void); + +/************************************************************************************ + * Name: imxrt_usb_initialize + * + * Description: + * Called to configure USB. + * + ************************************************************************************/ + +extern void imxrt_spiinitialize(void); + +extern int imxrt_usb_initialize(void); + +extern void imxrt_usbinitialize(void); + +extern void board_peripheral_reset(int ms); + +extern void fmurt1062_timer_initialize(void); + +#include + +void imxrt_flash_romapi_initialize(void); + +int imxrt_flexspi_storage_initialize(void); + +#endif /* __ASSEMBLY__ */ + +__END_DECLS diff --git a/boards/nxp/mr-tropic/src/bootloader_main.c b/boards/nxp/mr-tropic/src/bootloader_main.c new file mode 100644 index 0000000000..04008aa2ff --- /dev/null +++ b/boards/nxp/mr-tropic/src/bootloader_main.c @@ -0,0 +1,61 @@ +/**************************************************************************** + * + * 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 bootloader_main.c + * + * FMU-specific early startup code for bootloader +*/ + +#include "board_config.h" +#include "bl.h" + +#include +#include +#include +#include +#include "arm_internal.h" +#include + +extern int sercon_main(int c, char **argv); + +void board_late_initialize(void) +{ + sercon_main(0, NULL); +} + +extern void sys_tick_handler(void); +void board_timerhook(void) +{ + sys_tick_handler(); +} diff --git a/boards/nxp/mr-tropic/src/hw_config.h b/boards/nxp/mr-tropic/src/hw_config.h new file mode 100644 index 0000000000..22e0680203 --- /dev/null +++ b/boards/nxp/mr-tropic/src/hw_config.h @@ -0,0 +1,130 @@ +/* + * hw_config.h + * + * Created on: May 17, 2015 + * Author: david_s5 + */ + +#ifndef HW_CONFIG_H_ +#define HW_CONFIG_H_ + +/**************************************************************************** + * 10-8--2016: + * To simplify the ripple effect on the tools, we will be using + * /dev/serial/by-id/PX4 to locate PX4 devices. Therefore + * moving forward all Bootloaders must contain the prefix "PX4 BL " + * in the USBDEVICESTRING + * This Change will be made in an upcoming BL release + ****************************************************************************/ +/* + * Define usage to configure a bootloader + * + * + * Constant example Usage + * APP_LOAD_ADDRESS 0x08004000 - The address in Linker Script, where the app fw is org-ed + * BOOTLOADER_DELAY 5000 - Ms to wait while under USB pwr or bootloader request + * BOARD_FMUV2 + * INTERFACE_USB 1 - (Optional) Scan and use the USB interface for bootloading + * INTERFACE_USART 1 - (Optional) Scan and use the Serial interface for bootloading + * USBDEVICESTRING "PX4 BL FMU v2.x" - USB id string + * USBPRODUCTID 0x0011 - PID Should match defconfig + * BOOT_DELAY_ADDRESS 0x000001a0 - (Optional) From the linker script from Linker Script to get a custom + * delay provided by an APP FW + * BOARD_TYPE 9 - Must match .prototype boad_id + * _FLASH_KBYTES (*(uint16_t *)0x1fff7a22) - Run time flash size detection + * BOARD_FLASH_SECTORS ((_FLASH_KBYTES == 0x400) ? 11 : 23) - Run time determine the physical last sector + * BOARD_FLASH_SECTORS 11 - Hard coded zero based last sector + * BOARD_FLASH_SIZE (_FLASH_KBYTES*1024)- Total Flash size of device, determined at run time. + * (1024 * 1024) - Hard coded Total Flash of device - The bootloader and app reserved will be deducted + * programmatically + * + * BOARD_FIRST_FLASH_SECTOR_TO_ERASE 2 - Optional sectors index in the flash_sectors table (F4 only), to begin erasing. + * This is to allow sectors to be reserved for app fw usage. That will NOT be erased + * during a FW upgrade. + * The default is 0, and selects the first sector to be erased, as the 0th entry in the + * flash_sectors table. Which is the second physical sector of FLASH in the device. + * The first physical sector of FLASH is used by the bootloader, and is not defined + * in the table. + * + * APP_RESERVATION_SIZE (BOARD_FIRST_FLASH_SECTOR_TO_ERASE * 16 * 1024) - Number of bytes reserved by the APP FW. This number plus + * BOOTLOADER_RESERVATION_SIZE will be deducted from + * BOARD_FLASH_SIZE to determine the size of the App FW + * and hence the address space of FLASH to erase and program. + * USBMFGSTRING "PX4 AP" - Optional USB MFG string (default is '3D Robotics' if not defined.) + * SERIAL_BREAK_DETECT_DISABLED - Optional prevent break selection on Serial port from entering or staying in BL + * + * * Other defines are somewhat self explanatory. + */ + +/* Boot device selection list*/ +#define USB0_DEV 0x01 +#define SERIAL0_DEV 0x02 +#define SERIAL1_DEV 0x04 + +#define APP_LOAD_ADDRESS 0x70020000 +#define APP_VECTOR_OFFSET 0x2000 +#define BOOTLOADER_DELAY 5000 +#define INTERFACE_USB 1 +#define INTERFACE_USB_CONFIG "/dev/ttyACM0" + +//#define USE_VBUS_PULL_DOWN +#define INTERFACE_USART 1 +#define INTERFACE_USART_CONFIG "/dev/ttyS0,1500000" +#define BOOT_DELAY_ADDRESS 0x00039FA0 +#define BOARD_TYPE 37 +// The board has a 64 Mb part with 16384, 4K secors, but we artificialy limit it to 4 Mb +// as 1024, 4K sectors +#define BOARD_FLASH_SECTORS 960 // 1024 * 4k sectors, 128k for bootloader, 128k for storage +#define BOARD_FIRST_FLASH_SECTOR_TO_ERASE 32 // We resreve 128K for the bootloader +#define BOARD_FLASH_SIZE (BOARD_FLASH_SECTORS * 4096) + +#define OSC_FREQ 24 + +#define BOARD_PIN_LED_ACTIVITY GPIO_nLED_BLUE // BLUE +#define BOARD_PIN_LED_BOOTLOADER GPIO_nLED_GREEN // GREEN +#define BOARD_LED_ON 0 +#define BOARD_LED_OFF 1 + +#define SERIAL_BREAK_DETECT_DISABLED 1 + +/* + * Uncommenting this allows to force the bootloader through + * a PWM output pin. As this can accidentally initialize + * an ESC prematurely, it is not recommended. This feature + * has not been used and hence defaults now to off. + * + * # define BOARD_FORCE_BL_PIN_OUT (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN14) + * # define BOARD_FORCE_BL_PIN_IN (GPIO_INPUT|GPIO_PULLUP|GPIO_PORTE|GPIO_PIN11) + * + * # define BOARD_POWER_PIN_OUT (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_SET|GPIO_PORTA|GPIO_PIN4) + * # define BOARD_POWER_ON 1 + * # define BOARD_POWER_OFF 0 + * # undef BOARD_POWER_PIN_RELEASE // Leave pin enabling Power - un comment to release (disable power) + * +*/ + +#if !defined(ARCH_SN_MAX_LENGTH) +# define ARCH_SN_MAX_LENGTH 12 +#endif + +#if !defined(APP_RESERVATION_SIZE) +# define APP_RESERVATION_SIZE 0 +#endif + +#if !defined(BOARD_FIRST_FLASH_SECTOR_TO_ERASE) +# define BOARD_FIRST_FLASH_SECTOR_TO_ERASE 1 +#endif + +#if !defined(USB_DATA_ALIGN) +# define USB_DATA_ALIGN +#endif + +#ifndef BOOT_DEVICES_SELECTION +# define BOOT_DEVICES_SELECTION USB0_DEV|SERIAL0_DEV|SERIAL1_DEV +#endif + +#ifndef BOOT_DEVICES_FILTER_ONUSB +# define BOOT_DEVICES_FILTER_ONUSB USB0_DEV|SERIAL0_DEV|SERIAL1_DEV +#endif + +#endif /* HW_CONFIG_H_ */ diff --git a/boards/nxp/mr-tropic/src/hw_rev_ver_tropic.c b/boards/nxp/mr-tropic/src/hw_rev_ver_tropic.c new file mode 100644 index 0000000000..7414c21a32 --- /dev/null +++ b/boards/nxp/mr-tropic/src/hw_rev_ver_tropic.c @@ -0,0 +1,165 @@ +/**************************************************************************** + * + * 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 hw_rev_ver_canhubk3.c + * CANHUBK3 Hardware Revision and Version ID API + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#if defined(BOARD_HAS_HW_VERSIONING) + +#define HW_INFO_SIZE HW_INFO_VER_DIGITS + HW_INFO_REV_DIGITS + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static int hw_revision = 0; +static char hw_info[HW_INFO_SIZE] = {0}; +#if defined(BOARD_HAS_HW_SPLIT_VERSIONING) +static char hw_base_info[HW_INFO_SIZE] = {0}; +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ +/************************************************************************************ + * Name: board_get_hw_type + * + * Description: + * Optional returns a 0 terminated string defining the HW type. + * + * Input Parameters: + * None + * + * Returned Value: + * a 0 terminated string defining the HW type. This my be a 0 length string "" + * + ************************************************************************************/ + +__EXPORT const char *board_get_hw_type_name() +{ + return (const char *) hw_info; +} + +#if defined(BOARD_HAS_HW_SPLIT_VERSIONING) +/************************************************************************************ + * Name: board_get_hw_base_type_name + * + * Description: + * Optional returns a 0 terminated string defining the base type. + * + * Input Parameters: + * None + * + * Returned Value: + * a 0 terminated string defining the HW type. This my be a 0 length string "" + * + ************************************************************************************/ + +__EXPORT const char *board_get_hw_base_type_name() +{ + return (const char *) hw_base_info; +} +#endif + +/************************************************************************************ + * Name: board_get_hw_version + * + * Description: + * Optional returns a integer HW version + * + * Input Parameters: + * None + * + * Returned Value: + * An integer value of this boards hardware version. + * A value of -1 is the default for boards not supporting the BOARD_HAS_VERSIONING API. + * A value of 0 is the default for boards supporting the API but not having version. + * + ************************************************************************************/ + +__EXPORT int board_get_hw_version() +{ + return 0; +} + +/************************************************************************************ + * Name: board_get_hw_revision + * + * Description: + * Optional returns a integer HW revision + * + * Input Parameters: + * None + * + * Returned Value: + * An integer value of this boards hardware revision. + * A value of -1 is the default for boards not supporting the BOARD_HAS_VERSIONING API. + * A value of 0 is the default for boards supporting the API but not having revision. + * + ************************************************************************************/ + +__EXPORT int board_get_hw_revision() +{ + return hw_revision; +} + +/************************************************************************************ + * Name: board_determine_hw_info + * + * Description: + * Uses GPIO to detect MR-CANHUBK3-ADAP + * + ************************************************************************************/ + +int board_determine_hw_info() +{ + hw_revision = 0; //TODO Read fuses + + sprintf(hw_info, "%03d", hw_revision); + + return 0; +} +#endif diff --git a/boards/nxp/mr-tropic/src/i2c.cpp b/boards/nxp/mr-tropic/src/i2c.cpp new file mode 100644 index 0000000000..a118a69d0f --- /dev/null +++ b/boards/nxp/mr-tropic/src/i2c.cpp @@ -0,0 +1,40 @@ +/**************************************************************************** + * + * Copyright (C) 2024 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 + +constexpr px4_i2c_bus_t px4_i2c_buses[I2C_BUS_MAX_BUS_ITEMS] = { + initI2CBusExternal(1), + initI2CBusExternal(3), + initI2CBusInternal(4), +}; diff --git a/boards/nxp/mr-tropic/src/imxrt_flexspi_nor_boot.c b/boards/nxp/mr-tropic/src/imxrt_flexspi_nor_boot.c new file mode 100644 index 0000000000..894c959d33 --- /dev/null +++ b/boards/nxp/mr-tropic/src/imxrt_flexspi_nor_boot.c @@ -0,0 +1,55 @@ +/**************************************************************************** + * boards/arm/imxrt/imxrt1064-evk/src/imxrt_flexspi_nor_boot.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "imxrt_flexspi_nor_boot.h" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +locate_data(".boot_hdr.ivt") +const struct ivt_s g_image_vector_table = { + IVT_HEADER, /* IVT Header */ + IMAGE_ENTRY_ADDRESS, /* Image Entry Function */ + IVT_RSVD, /* Reserved = 0 */ + (uint32_t)DCD_ADDRESS, /* Address where DCD information is stored */ + (uint32_t)BOOT_DATA_ADDRESS, /* Address where BOOT Data Structure is stored */ + (uint32_t)IMAG_VECTOR_TABLE, /* Pointer to IVT Self (absolute address */ + (uint32_t)CSF_ADDRESS, /* Address where CSF file is stored */ + IVT_RSVD /* Reserved = 0 */ +}; + +locate_data(".boot_hdr.boot_data") +const struct boot_data_s g_boot_data = { + IMAGE_DEST, /* boot start location */ + (IMAGE_DEST_END - IMAGE_DEST), /* size */ + PLUGIN_FLAG, /* Plugin flag */ + 0xffffffff /* empty - extra data word */ +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/* None */ diff --git a/boards/nxp/mr-tropic/src/imxrt_flexspi_nor_boot.h b/boards/nxp/mr-tropic/src/imxrt_flexspi_nor_boot.h new file mode 100644 index 0000000000..ca6b9cf8b3 --- /dev/null +++ b/boards/nxp/mr-tropic/src/imxrt_flexspi_nor_boot.h @@ -0,0 +1,166 @@ +/**************************************************************************** + * boards/arm/imxrt/imxrt1064-evk/src/imxrt_flexspi_nor_boot.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM_IMXRT_IMXRT1060_EVK_SRC_IMXRT_FLEXSPI_NOR_BOOT_H +#define __BOARDS_ARM_IMXRT_IMXRT1060_EVK_SRC_IMXRT_FLEXSPI_NOR_BOOT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* IVT Data */ + +#define IVT_MAJOR_VERSION 0x4 +#define IVT_MAJOR_VERSION_SHIFT 0x4 +#define IVT_MAJOR_VERSION_MASK 0xf +#define IVT_MINOR_VERSION 0x1 +#define IVT_MINOR_VERSION_SHIFT 0x0 +#define IVT_MINOR_VERSION_MASK 0xf + +#define IVT_VERSION(major, minor) \ + ((((major) & IVT_MAJOR_VERSION_MASK) << IVT_MAJOR_VERSION_SHIFT) | \ + (((minor) & IVT_MINOR_VERSION_MASK) << IVT_MINOR_VERSION_SHIFT)) + +#define IVT_TAG_HEADER (0xd1) /* Image Vector Table */ +#define IVT_SIZE 0x2000 +#define IVT_PAR IVT_VERSION(IVT_MAJOR_VERSION, IVT_MINOR_VERSION) + +#define IVT_HEADER (IVT_TAG_HEADER | (IVT_SIZE << 8) | (IVT_PAR << 24)) +#define IVT_RSVD (uint32_t)(0x00000000) + +/* DCD Data */ + +#define DCD_TAG_HEADER (0xd2) +#define DCD_TAG_HEADER_SHIFT (24) +#define DCD_VERSION (0x40) +#define DCD_ARRAY_SIZE 1 + +#define FLASH_BASE 0x70000000 +#define FLASH_END 0x70400000 + +/* This needs to take into account the memory configuration at boot + * bootloader + */ + +#define ROM_BOOTLOADER_OCRAM_RES 0x8000 +#define OCRAM_BASE (0x20200000 + ROM_BOOTLOADER_OCRAM_RES) +#define OCRAM_END (OCRAM_BASE + (512 * 1024) + (256 * 1024) \ + - ROM_BOOTLOADER_OCRAM_RES) + +#define SCLK 1 +#if defined(CONFIG_BOOT_RUNFROMFLASH) +# define IMAGE_DEST FLASH_BASE +# define IMAGE_DEST_END FLASH_END +# define IMAGE_DEST_OFFSET 0 +#else +# define IMAGE_DEST OCRAM_BASE +# define IMAGE_DEST_END OCRAM_END +# define IMAGE_DEST_OFFSET IVT_SIZE +#endif + +#define LOCATE_IN_DEST(x) (((uint32_t)(x)) - FLASH_BASE + IMAGE_DEST) +#define LOCATE_IN_SRC(x) (((uint32_t)(x)) - IMAGE_DEST + FLASH_BASE) + +#ifdef CONFIG_IMXRT1064_EVK_SDRAM +# define DCD_ADDRESS &g_dcd_data +#else +# define DCD_ADDRESS 0 +#endif +#define BOOT_DATA_ADDRESS LOCATE_IN_DEST(&g_boot_data) +#define CSF_ADDRESS 0 +#define PLUGIN_FLAG (uint32_t)0 + +/* Located in Destination Memory */ + +#define IMAGE_ENTRY_ADDRESS ((uint32_t)&_vectors) +#define IMAG_VECTOR_TABLE LOCATE_IN_DEST(&g_image_vector_table) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* IVT Data */ + +struct ivt_s { + /* Header with tag #HAB_TAG_IVT, length and HAB version fields + * (see data) + */ + + uint32_t hdr; + + /* Absolute address of the first instruction to execute from the + * image + */ + + uint32_t entry; + + /* Reserved in this version of HAB: should be NULL. */ + + uint32_t reserved1; + + /* Absolute address of the image DCD: may be NULL. */ + + uint32_t dcd; + + /* Absolute address of the Boot Data: may be NULL, but not interpreted + * any further by HAB + */ + + uint32_t boot_data; + + /* Absolute address of the IVT. */ + + uint32_t self; + + /* Absolute address of the image CSF. */ + + uint32_t csf; + + /* Reserved in this version of HAB: should be zero. */ + + uint32_t reserved2; +}; + +/* Boot Data */ + +struct boot_data_s { + uint32_t start; /* boot start location */ + uint32_t size; /* size */ + uint32_t plugin; /* plugin flag - 1 if downloaded application is plugin */ + uint32_t placeholder; /* placeholder to make even 0x10 size */ +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +extern const struct boot_data_s g_boot_data; +#ifdef CONFIG_IMXRT1064_EVK_SDRAM +extern const uint8_t g_dcd_data[]; +#endif +extern const uint32_t _vectors[]; + +#endif /* __BOARDS_ARM_IMXRT_IMXRT1060_EVK_SRC_IMXRT_FLEXSPI_NOR_BOOT_H */ diff --git a/boards/nxp/mr-tropic/src/imxrt_flexspi_nor_flash.c b/boards/nxp/mr-tropic/src/imxrt_flexspi_nor_flash.c new file mode 100644 index 0000000000..25fcd2e2a1 --- /dev/null +++ b/boards/nxp/mr-tropic/src/imxrt_flexspi_nor_flash.c @@ -0,0 +1,107 @@ +/**************************************************************************** + * boards/arm/imxrt/teensy-4.x/src/imxrt_flexspi_nor_flash.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "imxrt_flexspi_nor_flash.h" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +enum { + /* SPI instructions */ + + READ_FAST = 0, + READ_STATUS_REG = 1, + WRITE_ENABLE = 3, + SECTOR_ERASE_4K = 5, + READ_FAST_QUAD_OUTPUT = 6, + PAGE_PROGRAM_QUAD_INPUT = 7, + ERASE_BLOCK = 8, + PAGE_PROGRAM = 9, + CHIP_ERASE = 11, +}; + +locate_data(".boot_hdr.conf") +const struct flexspi_nor_config_s g_flash_config = { + .mem_config = + { + .tag = FLEXSPI_CFG_BLK_TAG, + .version = FLEXSPI_CFG_BLK_VERSION, + .read_sample_clksrc = FLASH_READ_SAMPLE_CLK_LOOPBACK_FROM_DQSPAD, + .cs_hold_time = 3u, + .cs_setup_time = 3u, + .column_address_width = 0u, + .device_type = FLEXSPI_DEVICE_TYPE_SERIAL_NOR, + .sflash_pad_type = SERIAL_FLASH_4PADS, + .serial_clk_freq = FLEXSPI_SERIAL_CLKFREQ_133MHz, + .sflash_a1size = 4u * 1024u * 1024u, + .lookup_table = + { + [4 * READ_FAST] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xeb, + RADDR_SDR, FLEXSPI_4PAD, 0x18), + [4 * READ_FAST + 1] = FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, + READ_SDR, FLEXSPI_4PAD, 0x04), + + [4 * READ_STATUS_REG] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, + READ_SDR, FLEXSPI_1PAD, 0x04), + + [4 * WRITE_ENABLE] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, + STOP, FLEXSPI_1PAD, 0), + + [4 * SECTOR_ERASE_4K] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, + RADDR_SDR, FLEXSPI_1PAD, 0x18), + + [4 * CHIP_ERASE] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, + STOP, FLEXSPI_1PAD, 0), + + [4 * ERASE_BLOCK] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xd8, + RADDR_SDR, FLEXSPI_1PAD, 0x18), + + [4 * PAGE_PROGRAM] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, + RADDR_SDR, FLEXSPI_1PAD, 0x18), + [4 * PAGE_PROGRAM + 1] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0x04, + STOP, FLEXSPI_1PAD, 0x0), + + [4 * READ_FAST_QUAD_OUTPUT] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6b, + RADDR_SDR, FLEXSPI_1PAD, 0x18), + [4 * READ_FAST_QUAD_OUTPUT + 1] = FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, + READ_SDR, FLEXSPI_4PAD, 0x04), + + [4 * PAGE_PROGRAM_QUAD_INPUT] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, + RADDR_SDR, FLEXSPI_1PAD, 0x18), + [4 * PAGE_PROGRAM_QUAD_INPUT + 1] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, + STOP, FLEXSPI_1PAD, 0), + + }, + }, + + .page_size = 256u, + .sector_size = 4u * 1024u, + .blocksize = 64u * 1024u, + .is_uniform_blocksize = false, +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ diff --git a/boards/nxp/mr-tropic/src/imxrt_flexspi_nor_flash.h b/boards/nxp/mr-tropic/src/imxrt_flexspi_nor_flash.h new file mode 100644 index 0000000000..1fb3f41cce --- /dev/null +++ b/boards/nxp/mr-tropic/src/imxrt_flexspi_nor_flash.h @@ -0,0 +1,349 @@ +/**************************************************************************** + * boards/arm/imxrt/imxrt1064-evk/src/imxrt_flexspi_nor_flash.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM_IMXRT_IMXRT1064_EVK_SRC_IMXRT_FLEXSPI_NOR_FLASH_H +#define __BOARDS_ARM_IMXRT_IMXRT1064_EVK_SRC_IMXRT_FLEXSPI_NOR_FLASH_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* FLEXSPI memory config block related definitions */ + +#define FLEXSPI_CFG_BLK_TAG (0x42464346ul) +#define FLEXSPI_CFG_BLK_VERSION (0x56010400ul) +#define FLEXSPI_CFG_BLK_SIZE (512) + +/* FLEXSPI Feature related definitions */ + +#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1 + +/* Lookup table related definitions */ + +#define CMD_INDEX_READ 0 +#define CMD_INDEX_READSTATUS 1 +#define CMD_INDEX_WRITEENABLE 2 +#define CMD_INDEX_WRITE 4 + +#define CMD_LUT_SEQ_IDX_READ 0 +#define CMD_LUT_SEQ_IDX_READSTATUS 1 +#define CMD_LUT_SEQ_IDX_WRITEENABLE 3 +#define CMD_LUT_SEQ_IDX_WRITE 9 + +#define CMD_SDR 0x01 +#define CMD_DDR 0x21 +#define RADDR_SDR 0x02 +#define RADDR_DDR 0x22 +#define CADDR_SDR 0x03 +#define CADDR_DDR 0x23 +#define MODE1_SDR 0x04 +#define MODE1_DDR 0x24 +#define MODE2_SDR 0x05 +#define MODE2_DDR 0x25 +#define MODE4_SDR 0x06 +#define MODE4_DDR 0x26 +#define MODE8_SDR 0x07 +#define MODE8_DDR 0x27 +#define WRITE_SDR 0x08 +#define WRITE_DDR 0x28 +#define READ_SDR 0x09 +#define READ_DDR 0x29 +#define LEARN_SDR 0x0a +#define LEARN_DDR 0x2a +#define DATSZ_SDR 0x0b +#define DATSZ_DDR 0x2b +#define DUMMY_SDR 0x0c +#define DUMMY_DDR 0x2c +#define DUMMY_RWDS_SDR 0x0d +#define DUMMY_RWDS_DDR 0x2d +#define JMP_ON_CS 0x1f +#define STOP 0 + +#define FLEXSPI_1PAD 0 +#define FLEXSPI_2PAD 1 +#define FLEXSPI_4PAD 2 +#define FLEXSPI_8PAD 3 + +#define FLEXSPI_LUT_OPERAND0_MASK (0xffu) +#define FLEXSPI_LUT_OPERAND0_SHIFT (0U) +#define FLEXSPI_LUT_OPERAND0(x) (((uint32_t) \ + (((uint32_t)(x)) << FLEXSPI_LUT_OPERAND0_SHIFT)) & \ + FLEXSPI_LUT_OPERAND0_MASK) +#define FLEXSPI_LUT_NUM_PADS0_MASK (0x300u) +#define FLEXSPI_LUT_NUM_PADS0_SHIFT (8u) +#define FLEXSPI_LUT_NUM_PADS0(x) (((uint32_t) \ + (((uint32_t)(x)) << FLEXSPI_LUT_NUM_PADS0_SHIFT)) & \ + FLEXSPI_LUT_NUM_PADS0_MASK) +#define FLEXSPI_LUT_OPCODE0_MASK (0xfc00u) +#define FLEXSPI_LUT_OPCODE0_SHIFT (10u) +#define FLEXSPI_LUT_OPCODE0(x) (((uint32_t) \ + (((uint32_t)(x)) << FLEXSPI_LUT_OPCODE0_SHIFT)) & \ + FLEXSPI_LUT_OPCODE0_MASK) +#define FLEXSPI_LUT_OPERAND1_MASK (0xff0000u) +#define FLEXSPI_LUT_OPERAND1_SHIFT (16U) +#define FLEXSPI_LUT_OPERAND1(x) (((uint32_t) \ + (((uint32_t)(x)) << FLEXSPI_LUT_OPERAND1_SHIFT)) & \ + FLEXSPI_LUT_OPERAND1_MASK) +#define FLEXSPI_LUT_NUM_PADS1_MASK (0x3000000u) +#define FLEXSPI_LUT_NUM_PADS1_SHIFT (24u) +#define FLEXSPI_LUT_NUM_PADS1(x) (((uint32_t) \ + (((uint32_t)(x)) << FLEXSPI_LUT_NUM_PADS1_SHIFT)) & \ + FLEXSPI_LUT_NUM_PADS1_MASK) +#define FLEXSPI_LUT_OPCODE1_MASK (0xfc000000u) +#define FLEXSPI_LUT_OPCODE1_SHIFT (26u) +#define FLEXSPI_LUT_OPCODE1(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUT_OPCODE1_SHIFT)) & \ + FLEXSPI_LUT_OPCODE1_MASK) + +#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ + (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | \ + FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \ + FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) + +/* */ + +#define NOR_CMD_INDEX_READ CMD_INDEX_READ +#define NOR_CMD_INDEX_READSTATUS CMD_INDEX_READSTATUS +#define NOR_CMD_INDEX_WRITEENABLE CMD_INDEX_WRITEENABLE +#define NOR_CMD_INDEX_ERASESECTOR 3 +#define NOR_CMD_INDEX_PAGEPROGRAM CMD_INDEX_WRITE +#define NOR_CMD_INDEX_CHIPERASE 5 +#define NOR_CMD_INDEX_DUMMY 6 +#define NOR_CMD_INDEX_ERASEBLOCK 7 + +/* READ LUT sequence id in lookupTable stored in config block */ + +#define NOR_CMD_LUT_SEQ_IDX_READ CMD_LUT_SEQ_IDX_READ + +/* Read Status LUT sequence id in lookupTable stored in config block */ + +#define NOR_CMD_LUT_SEQ_IDX_READSTATUS CMD_LUT_SEQ_IDX_READSTATUS + +/* 2 Read status DPI/QPI/OPI sequence id in LUT stored in config block */ + +#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 2 + +/* 3 Write Enable sequence id in lookupTable stored in config block */ + +#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE CMD_LUT_SEQ_IDX_WRITEENABLE + +/* 4 Write Enable DPI/QPI/OPI sequence id in LUT stored in config block */ + +#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE_XPI 4 + +/* 5 Erase Sector sequence id in lookupTable stored in config block */ + +#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5 + +/* 8 Erase Block sequence id in lookupTable stored in config block */ + +#define NOR_CMD_LUT_SEQ_IDX_ERASEBLOCK 8 + +/* 9 Program sequence id in lookupTable stored in config block */ + +#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM CMD_LUT_SEQ_IDX_WRITE + +/* 11 Chip Erase sequence in lookupTable id stored in config block */ + +#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11 + +/* 13 Read SFDP sequence in lookupTable id stored in config block */ + +#define NOR_CMD_LUT_SEQ_IDX_READ_SFDP 13 + +/* 14 Restore 0-4-4/0-8-8 mode sequence id in LUT stored in config block */ + +#define NOR_CMD_LUT_SEQ_IDX_RESTORE_NOCMD 14 + +/* 15 Exit 0-4-4/0-8-8 mode sequence id in LUT stored in config blobk */ + +#define NOR_CMD_LUT_SEQ_IDX_EXIT_NOCMD 15 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Definitions for FlexSPI Serial Clock Frequency */ + +enum flexspi_serial_clkfreq_e { + FLEXSPI_SERIAL_CLKFREQ_30MHz = 1, + FLEXSPI_SERIAL_CLKFREQ_50MHz = 2, + FLEXSPI_SERIAL_CLKFREQ_60MHz = 3, + FLEXSPI_SERIAL_CLKFREQ_75MHz = 4, + FLEXSPI_SERIAL_CLKFREQ_80MHz = 5, + FLEXSPI_SERIAL_CLKFREQ_100MHz = 6, + FLEXSPI_SERIAL_CLKFREQ_120MHz = 7, + FLEXSPI_SERIAL_CLKFREQ_133MHz = 8, + FLEXSPI_SERIAL_CLKFREQ_166MHz = 9, +}; + +/* FlexSPI clock configuration type */ + +enum flexspi_serial_clockmode_e { + FLEXSPI_CLKMODE_SDR, + FLEXSPI_CLKMODE_DDR, +}; + +/* FlexSPI Read Sample Clock Source definition */ + +enum flash_read_sample_clk_e { + FLASH_READ_SAMPLE_CLK_LOOPBACK_INTERNELLY = 0, + FLASH_READ_SAMPLE_CLK_LOOPBACK_FROM_DQSPAD = 1, + FLASH_READ_SAMPLE_CLK_LOOPBACK_FROM_SCKPAD = 2, + FLASH_READ_SAMPLE_CLK_EXT_INPUT_FROM_DQSPAD = 3, +}; + +/* Misc feature bit definitions */ + +enum flash_misc_feature_e { + FLEXSPIMISC_OFFSET_DIFFCLKEN = 0, /* Bit for Differential clock enable */ + FLEXSPIMISC_OFFSET_CK2EN = 1, /* Bit for CK2 enable */ + FLEXSPIMISC_OFFSET_PARALLELEN = 2, /* Bit for Parallel mode enable */ + FLEXSPIMISC_OFFSET_WORD_ADDRESSABLE_EN = 3, /* Bit for Word Addressable enable */ + FLEXSPIMISC_OFFSET_SAFECONFIG_FREQ_EN = 4, /* Bit for Safe Configuration Frequency enable */ + FLEXSPIMISC_OFFSET_PAD_SETTING_OVERRIDE_EN = 5, /* Bit for Pad setting override enable */ + FLEXSPIMISC_OFFSET_DDR_MODE_EN = 6, /* Bit for DDR clock confiuration indication. */ +}; + +/* Flash Type Definition */ + +enum flash_flash_type_e { + FLEXSPI_DEVICE_TYPE_SERIAL_NOR = 1, /* Flash devices are Serial NOR */ + FLEXSPI_DEVICE_TYPE_SERIAL_NAND = 2, /* Flash devices are Serial NAND */ + FLEXSPI_DEVICE_TYPE_SERIAL_RAM = 3, /* Flash devices are Serial RAM/HyperFLASH */ + FLEXSPI_DEVICE_TYPE_MCP_NOR_NAND = 0x12, /* Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND */ + FLEXSPI_DEVICE_TYPE_MCP_NOR_RAM = 0x13, /* Flash device is MCP device, A1 is Serial NOR, A2 is Serial RAMs */ +}; + +/* Flash Pad Definitions */ + +enum flash_flash_pad_e { + SERIAL_FLASH_1PAD = 1, + SERIAL_FLASH_2PADS = 2, + SERIAL_FLASH_4PADS = 4, + SERIAL_FLASH_8PADS = 8, +}; + +/* Flash Configuration Command Type */ + +enum flash_config_cmd_e { + DEVICE_CONFIG_CMD_TYPE_GENERIC, /* Generic command, for example: configure dummy cycles, drive strength, etc */ + DEVICE_CONFIG_CMD_TYPE_QUADENABLE, /* Quad Enable command */ + DEVICE_CONFIG_CMD_TYPE_SPI2XPI, /* Switch from SPI to DPI/QPI/OPI mode */ + DEVICE_CONFIG_CMD_TYPE_XPI2SPI, /* Switch from DPI/QPI/OPI to SPI mode */ + DEVICE_CONFIG_CMD_TYPE_SPI2NO_CMD, /* Switch to 0-4-4/0-8-8 mode */ + DEVICE_CONFIG_CMD_TYPE_RESET, /* Reset device command */ +}; + +/* FlexSPI LUT Sequence structure */ + +struct flexspi_lut_seq_s { + uint8_t seq_num; /* Sequence Number, valid number: 1-16 */ + uint8_t seq_id; /* Sequence Index, valid number: 0-15 */ + uint16_t reserved; +}; + +/* FlexSPI Memory Configuration Block */ + +struct flexspi_mem_config_s { + uint32_t tag; + uint32_t version; + uint32_t reserved0; + uint8_t read_sample_clksrc; + uint8_t cs_hold_time; + uint8_t cs_setup_time; + uint8_t column_address_width; /* [0x00f-0x00f] Column Address with, for + * HyperBus protocol, it is fixed to 3, + * For Serial NAND, need to refer to + * datasheet + */ + uint8_t device_mode_cfg_enable; + uint8_t device_mode_type; + uint16_t wait_time_cfg_commands; + struct flexspi_lut_seq_s device_mode_seq; + uint32_t device_mode_arg; + uint8_t config_cmd_enable; + uint8_t config_mode_type[3]; + struct flexspi_lut_seq_s config_cmd_seqs[3]; + uint32_t reserved1; + uint32_t config_cmd_args[3]; + uint32_t reserved2; + uint32_t controller_misc_option; + uint8_t device_type; + uint8_t sflash_pad_type; + uint8_t serial_clk_freq; + uint8_t lut_custom_seq_enable; + uint32_t reserved3[2]; + uint32_t sflash_a1size; + uint32_t sflash_a2size; + uint32_t sflash_b1size; + uint32_t sflash_b2size; + uint32_t cspad_setting_override; + uint32_t sclkpad_setting_override; + uint32_t datapad_setting_override; + uint32_t dqspad_setting_override; + uint32_t timeout_in_ms; + uint32_t command_interval; + uint16_t data_valid_time[2]; + uint16_t busy_offset; + uint16_t busybit_polarity; + uint32_t lookup_table[64]; + struct flexspi_lut_seq_s lut_customseq[12]; + uint32_t reserved4[4]; +}; + +/* Serial NOR configuration block */ + +struct flexspi_nor_config_s { + struct flexspi_mem_config_s mem_config; /* Common memory configuration info + * via FlexSPI + */ + + uint32_t page_size; /* Page size of Serial NOR */ + uint32_t sector_size; /* Sector size of Serial NOR */ + uint8_t ipcmd_serial_clkfreq; /* Clock frequency for IP command */ + uint8_t is_uniform_blocksize; /* Sector/Block size is the same */ + uint8_t reserved0[2]; /* Reserved for future use */ + uint8_t serial_nor_type; /* Serial NOR Flash type: 0/1/2/3 */ + uint8_t need_exit_nocmdmode; /* Need to exit NoCmd mode before + * other IP command + */ + + uint8_t halfclk_for_nonreadcmd; /* Half the Serial Clock for non-read + * command: true/false + */ + + uint8_t need_restore_nocmdmode; /* Need to Restore NoCmd mode after IP + * command execution + */ + + uint32_t blocksize; /* Block size */ + uint32_t reserve2[11]; /* Reserved for future use */ +}; + +extern const struct flexspi_nor_config_s g_flash_config; + +#endif /* __BOARDS_ARM_IMXRT_IMXRT1064_EVK_SRC_IMXRT_FLEXSPI_NOR_FLASH_H */ diff --git a/boards/nxp/mr-tropic/src/imxrt_flexspi_storage.c b/boards/nxp/mr-tropic/src/imxrt_flexspi_storage.c new file mode 100644 index 0000000000..2b505176b4 --- /dev/null +++ b/boards/nxp/mr-tropic/src/imxrt_flexspi_storage.c @@ -0,0 +1,411 @@ +/**************************************************************************** + * boards/nxp/mr-tropic/src/imxrt_flexspi_storage.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "px4_log.h" + +#include +#include +#include "board_config.h" +#include "hardware/imxrt_pinmux.h" +#include "barriers.h" + +/* Used sectors must be multiple of the flash block size + * i.e. W25Q32JV has a block size of 64KB +*/ + +#define NOR_USED_SECTORS (0x40U) /* 64 * 4KB = 256KB */ +#define NOR_TOTAL_SECTORS (0x0400U) +#define NOR_PAGE_SIZE (0x0100U) /* 256 bytes */ +#define NOR_SECTOR_SIZE (0x1000U) /* 4KB */ +#define NOR_START_SECTOR (NOR_TOTAL_SECTORS - NOR_USED_SECTORS) +#define NOR_START_PAGE ((NOR_START_SECTOR * NOR_SECTOR_SIZE) / NOR_PAGE_SIZE) +#define NOR_STORAGE_ADDR (IMXRT_FLEX2CIPHER_BASE + NOR_START_SECTOR * NOR_SECTOR_SIZE) +#define NOR_STORAGE_END (IMXRT_FLEX2CIPHER_BASE + (NOR_START_SECTOR + NOR_TOTAL_SECTORS) * NOR_SECTOR_SIZE) + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +extern struct flexspi_nor_config_s g_bootConfig; + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* FlexSPI NOR device private data */ + +struct imxrt_flexspi_storage_dev_s { + struct mtd_dev_s mtd; + uint8_t *ahb_base; +}; + +/**************************************************************************** + * Private Functions Prototypes + ****************************************************************************/ + +/* MTD driver methods */ + +static int imxrt_flexspi_storage_erase(struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks); +static ssize_t imxrt_flexspi_storage_read(struct mtd_dev_s *dev, + off_t offset, + size_t nbytes, + uint8_t *buffer); +static ssize_t imxrt_flexspi_storage_bread(struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, + uint8_t *buffer); +static ssize_t imxrt_flexspi_storage_bwrite(struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, + const uint8_t *buffer); +static int imxrt_flexspi_storage_ioctl(struct mtd_dev_s *dev, + int cmd, + unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct imxrt_flexspi_storage_dev_s g_flexspi_nor = { + .mtd = + { + .erase = imxrt_flexspi_storage_erase, + .bread = imxrt_flexspi_storage_bread, + .bwrite = imxrt_flexspi_storage_bwrite, + .read = imxrt_flexspi_storage_read, + .ioctl = imxrt_flexspi_storage_ioctl, +#ifdef CONFIG_MTD_BYTE_WRITE + .write = NULL, +#endif + .name = "imxrt_flexspi_storage" + }, + .ahb_base = (uint8_t *) NOR_STORAGE_ADDR, +}; + +/* Ensure exclusive access to the driver */ + +static sem_t g_exclsem = SEM_INITIALIZER(1); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int imxrt_flexspi_storage_erase_chip( + const struct imxrt_flexspi_storage_dev_s *dev) +{ + /* We can't erase the chip we're executing from */ + return -EINVAL; +} + +static ssize_t imxrt_flexspi_storage_read(struct mtd_dev_s *dev, + off_t offset, + size_t nbytes, + uint8_t *buffer) +{ + ssize_t ret; + struct imxrt_flexspi_storage_dev_s *priv = + (struct imxrt_flexspi_storage_dev_s *)dev; + uint8_t *src; + + finfo("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes); + + if (offset < 0) { + return -EIO; + } + + src = priv->ahb_base + offset; + + if (src + nbytes > (uint8_t *)NOR_STORAGE_END) { + return -EIO; + } + + ret = nxsem_wait(&g_exclsem); + + if (ret < 0) { + return ret; + } + + memcpy(buffer, src, nbytes); + + nxsem_post(&g_exclsem); + + finfo("return nbytes: %d\n", (int)nbytes); + return (ssize_t)nbytes; +} + +static ssize_t imxrt_flexspi_storage_bread(struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, + uint8_t *buffer) +{ + ssize_t nbytes; + + finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); + + /* On this device, we can handle the block read just like the byte-oriented + * read + */ + + nbytes = imxrt_flexspi_storage_read(dev, startblock * NOR_PAGE_SIZE, + nblocks * NOR_PAGE_SIZE, buffer); + + if (nbytes > 0) { + nbytes /= NOR_PAGE_SIZE; + } + + return nbytes; +} + +locate_code(".ramfunc") +static ssize_t imxrt_flexspi_storage_bwrite(struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, + const uint8_t *buffer) +{ + ssize_t ret; + struct flexspi_nor_config_s *pConfig = &g_bootConfig; + size_t len = nblocks * NOR_PAGE_SIZE; + off_t offset = (startblock + NOR_START_PAGE) * NOR_PAGE_SIZE; + uint8_t *src = (uint8_t *) buffer; +#ifdef CONFIG_ARMV7M_DCACHE + struct imxrt_flexspi_storage_dev_s *priv = + (struct imxrt_flexspi_storage_dev_s *)dev; + uint8_t *dst = priv->ahb_base + startblock * NOR_PAGE_SIZE; +#endif + int i; + + if (((uintptr_t)buffer % 4) != 0) { + return -EINVAL; // Byte aligned write not supported + } + + finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); + + ret = nxsem_wait(&g_exclsem); + + if (ret < 0) { + return ret; + } + + while (len) { + i = MIN(NOR_PAGE_SIZE, len); + cpsid(); // Disable interrupts +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + volatile uint32_t status = ROM_FLEXSPI_NorFlash_ProgramPage(NOR_INSTANCE, pConfig, offset, (const uint32_t *)src); +#pragma GCC diagnostic pop + cpsie(); // Enable interrupts + usleep(0); // Yield to scheduler + UNUSED(status); + + offset += i; + src += i; + len -= i; + } + +#ifdef CONFIG_ARMV7M_DCACHE + up_invalidate_dcache((uintptr_t)dst, + (uintptr_t)dst + nblocks * NOR_PAGE_SIZE); +#endif + + nxsem_post(&g_exclsem); + + return nblocks; +} + +locate_code(".ramfunc") +static int imxrt_flexspi_storage_erase(struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks) +{ + struct flexspi_nor_config_s *pConfig = &g_bootConfig; + size_t blocksleft = nblocks; +#ifdef CONFIG_ARMV7M_DCACHE + struct imxrt_flexspi_storage_dev_s *priv = + (struct imxrt_flexspi_storage_dev_s *)dev; + uint8_t *dst = priv->ahb_base + startblock * NOR_SECTOR_SIZE; +#endif + ssize_t ret; + + startblock += NOR_START_SECTOR; + + finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); + + ret = nxsem_wait(&g_exclsem); + + if (ret < 0) { + return ret; + } + + while (blocksleft-- > 0) { + /* Erase each sector */ + cpsid(); // Disable interrupts + volatile uint32_t status = ROM_FLEXSPI_NorFlash_Erase(NOR_INSTANCE, pConfig, + (startblock * NOR_SECTOR_SIZE), NOR_SECTOR_SIZE); + cpsie(); // Enable interrupts + usleep(0); // Yield to scheduler + UNUSED(status); + startblock++; + } + +#ifdef CONFIG_ARMV7M_DCACHE + up_invalidate_dcache((uintptr_t)dst, + (uintptr_t)dst + nblocks * NOR_SECTOR_SIZE); +#endif + nxsem_post(&g_exclsem); + + return (int)nblocks; +} + +static int imxrt_flexspi_storage_ioctl(struct mtd_dev_s *dev, + int cmd, + unsigned long arg) +{ + struct imxrt_flexspi_storage_dev_s *priv = + (struct imxrt_flexspi_storage_dev_s *)dev; + int ret = -EINVAL; /* Assume good command with bad parameters */ + + finfo("cmd: %d\n", cmd); + + switch (cmd) { + case MTDIOC_GEOMETRY: { + struct mtd_geometry_s *geo = + (struct mtd_geometry_s *)((uintptr_t)arg); + + if (geo) { + /* Populate the geometry structure with information need to + * know the capacity and how to access the device. + * + * NOTE: + * that the device is treated as though it where just an array + * of fixed size blocks. That is most likely not true, but the + * client will expect the device logic to do whatever is + * necessary to make it appear so. + */ + + geo->blocksize = (NOR_PAGE_SIZE); + geo->erasesize = (NOR_SECTOR_SIZE); + geo->neraseblocks = (NOR_USED_SECTORS); + + ret = OK; + + finfo("blocksize: %lu erasesize: %lu neraseblocks: %lu\n", + geo->blocksize, geo->erasesize, geo->neraseblocks); + } + } + break; + + case BIOC_PARTINFO: { + struct partition_info_s *info = + (struct partition_info_s *)arg; + + if (info != NULL) { + info->numsectors = (NOR_USED_SECTORS * NOR_SECTOR_SIZE) / NOR_PAGE_SIZE; + info->sectorsize = NOR_PAGE_SIZE; + info->startsector = 0; + info->parent[0] = '\0'; + ret = OK; + } + } + break; + + case MTDIOC_BULKERASE: { + /* Erase the entire device */ + + imxrt_flexspi_storage_erase_chip(priv); + ret = OK; + } + break; + + default: + ret = -ENOTTY; /* Bad/unsupported command */ + break; + } + + finfo("return %d\n", ret); + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + + +/**************************************************************************** + * Name: imxrt_flexspi_storage_initialize + * + * Description: + * This function is called by board-bringup logic to configure the + * flash device. + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int imxrt_flexspi_storage_initialize(void) +{ + struct mtd_dev_s *mtd_dev = &g_flexspi_nor.mtd; + int ret = -ENODEV; + + /* Register the MTD driver so that it can be accessed from the + * VFS. + */ + + ret = register_mtddriver("/dev/nor", mtd_dev, 0755, NULL); + + if (ret < 0) { + syslog(LOG_ERR, "ERROR: Failed to register MTD driver: %d\n", + ret); + } + +#ifdef CONFIG_FS_LITTLEFS + + /* Mount the LittleFS file system */ + + ret = nx_mount("/dev/nor", "/fs/nor", "littlefs", 0, + "autoformat"); + + if (ret < 0) { + syslog(LOG_ERR, + "ERROR: Failed to mount LittleFS at /mnt/lfs: %d\n", + ret); + } + +#endif + + return ret; +} diff --git a/boards/nxp/mr-tropic/src/imxrt_ocram_initialize.c b/boards/nxp/mr-tropic/src/imxrt_ocram_initialize.c new file mode 100644 index 0000000000..67c1a4ca36 --- /dev/null +++ b/boards/nxp/mr-tropic/src/imxrt_ocram_initialize.c @@ -0,0 +1,102 @@ +/**************************************************************************** + * + * Copyright (c) 2018-2019, 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 imxrt_ocram_initialize.c + * + * PX4 fmu-v6xrt RAM startup early startup code. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "arm_internal.h" +#include "imxrt_iomuxc.h" + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +__BEGIN_DECLS +extern const uint64_t _fitcmfuncs; /* Copy source address in FLASH */ +extern uint64_t _sitcmfuncs; /* Copy destination start address in ITCM */ +extern uint64_t _eitcmfuncs; /* Copy destination end address in ITCM */ +extern uint64_t _sdtcm; /* Copy destination start address in DTCM */ +extern uint64_t _edtcm; /* Copy destination end address in DTCM */ +__END_DECLS + +/**************************************************************************** + * Name: imxrt_ocram_initialize + * + * Description: + * Called off reset vector to reconfigure the flexRAM + * and finish the FLASH to RAM Copy. + * CMakeLists.txt Forces compiler not to use builtin functions using -fno-builtin + * + ****************************************************************************/ + +__EXPORT void imxrt_ocram_initialize(void) +{ + uint32_t regval; + register uint64_t *src; + register uint64_t *dest; + + /* FlexRAM Configuration + * F = 64K ITCM + * A = 64K DTCM + * 5 = 64K OCRAM + * So 0xFFFFFFAA is + * 384K FlexRAM ITCM + * 128K FlexRAM DTCM + * */ + + putreg32(0xFFFFFFAA, IMXRT_IOMUXC_GPR_GPR17); + regval = getreg32(IMXRT_IOMUXC_GPR_GPR16); + putreg32(regval | GPR_GPR16_FLEXRAM_BANK_CFG_SEL, IMXRT_IOMUXC_GPR_GPR16); + + /* Copy any necessary code sections from FLASH to ITCM. The process is the + * same as the code copying from FLASH to RAM above. */ + for (src = (uint64_t *)&_fitcmfuncs, dest = (uint64_t *)&_sitcmfuncs; + dest < (uint64_t *)&_eitcmfuncs;) { + *dest++ = *src++; + } + + /* Clear .dtcm. We'll do this inline (vs. calling memset) just to be + * certain that there are no issues with the state of global variables. + */ + + for (dest = &_sdtcm; dest < &_edtcm;) { + *dest++ = 0; + } +} diff --git a/boards/nxp/mr-tropic/src/init.c b/boards/nxp/mr-tropic/src/init.c new file mode 100644 index 0000000000..7c71fbbef0 --- /dev/null +++ b/boards/nxp/mr-tropic/src/init.c @@ -0,0 +1,400 @@ +/**************************************************************************** + * + * Copyright (c) 2024 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 init.c + * + * NXP imxrt1062-v1 specific early startup code. This file implements the + * board_app_initialize() function that is called early by nsh during startup. + * + * Code here is run before the rcS script is invoked; it should start required + * subsystems and perform board-specific initialization. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "board_config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "arm_internal.h" +#include "imxrt_flexspi_nor_boot.h" +#include +#include "imxrt_iomuxc.h" +#include "imxrt_flexcan.h" +#include "imxrt_enet.h" +#include +#include "board_config.h" + +#include +#undef FLEXSPI_LUT_COUNT +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Configuration ************************************************************/ + +/* + * Ideally we'd be able to get these from arm_internal.h, + * but since we want to be able to disable the NuttX use + * of leds for system indication at will and there is no + * separate switch, we need to build independent of the + * CONFIG_ARCH_LEDS configuration switch. + */ +__BEGIN_DECLS +extern void led_init(void); +extern void led_on(int led); +extern void led_off(int led); + +extern uint32_t _srodata; /* Start of .rodata */ +extern uint32_t _erodata; /* End of .rodata */ +__END_DECLS + +/************************************************************************************ + * Name: board_peripheral_reset + * + * Description: + * + ************************************************************************************/ +__EXPORT void board_peripheral_reset(int ms) +{ + +} +/************************************************************************************ + * Name: board_on_reset + * + * Description: + * Optionally provided function called on entry to board_system_reset + * It should perform any house keeping prior to the rest. + * + * status - 1 if resetting to boot loader + * 0 if just resetting + * + ************************************************************************************/ + +__EXPORT void board_on_reset(int status) +{ + for (int i = 0; i < DIRECT_PWM_OUTPUT_CHANNELS; ++i) { + px4_arch_configgpio(PX4_MAKE_GPIO_INPUT(io_timer_channel_get_gpio_output(i))); + } + + /* + * On resets invoked from system (not boot) ensure we establish a low + * output state on PWM pins to disarm the ESC and prevent the reset from potentially + * spinning up the motors. + */ + if (status >= 0) { + up_mdelay(100); + } +} + +/**************************************************************************** + * Name: imxrt_flash_romapi_initialize + * + * Description: + * + ****************************************************************************/ +struct flexspi_nor_config_s g_bootConfig; + +locate_code(".ramfunc") +void imxrt_flash_romapi_initialize(void) +{ + memcpy((struct flexspi_nor_config_s *)&g_bootConfig, &g_flash_config, + sizeof(struct flexspi_nor_config_s)); + g_bootConfig.memConfig.tag = FLEXSPI_CFG_BLK_TAG; + + ROM_API_Init(); + + ROM_FLEXSPI_NorFlash_Init(NOR_INSTANCE, (struct flexspi_nor_config_s *)&g_bootConfig); + ROM_FLEXSPI_NorFlash_ClearCache(NOR_INSTANCE); + + ARM_DSB(); + ARM_ISB(); + ARM_DMB(); +} + +locate_code(".ramfunc") +void imxrt_flash_setup_prefetch_partition(void) +{ +//Prefetch tuning to be determined +#if 0 + putreg32((uint32_t)&_srodata, IMXRT_FLEXSPI1_AHBBUFREGIONSTART0); + putreg32((uint32_t)&_erodata, IMXRT_FLEXSPI1_AHBBUFREGIONEND0); + /*putreg32((uint32_t)&_stext, IMXRT_FLEXSPI1_AHBBUFREGIONSTART1); + putreg32((uint32_t)&_etext, IMXRT_FLEXSPI1_AHBBUFREGIONEND1); + putreg32((uint32_t)&_stext, IMXRT_FLEXSPI1_AHBBUFREGIONSTART2); + putreg32((uint32_t)&_etext, IMXRT_FLEXSPI1_AHBBUFREGIONEND2); + putreg32((uint32_t)&_stext, IMXRT_FLEXSPI1_AHBBUFREGIONSTART3); + putreg32((uint32_t)&_etext, IMXRT_FLEXSPI1_AHBBUFREGIONEND3);*/ +#endif +#if 0 + struct flexspi_type_s *g_flexspi = (struct flexspi_type_s *)IMXRT_FLEXSPIC_BASE; + /* RODATA */ + g_flexspi->AHBRXBUFCR0[0] = FLEXSPI_AHBRXBUFCR0_BUFSZ(48) | + FLEXSPI_AHBRXBUFCR0_MSTRID(0) | + FLEXSPI_AHBRXBUFCR0_PREFETCHEN(1) | + FLEXSPI_AHBRXBUFCR0_REGIONEN(1); + + + /* All Text */ + g_flexspi->AHBRXBUFCR0[1] = FLEXSPI_AHBRXBUFCR0_BUFSZ(80) | + FLEXSPI_AHBRXBUFCR0_MSTRID(0) | + FLEXSPI_AHBRXBUFCR0_PREFETCHEN(1) | + FLEXSPI_AHBRXBUFCR0_REGIONEN(1); + + /* Disable 2 */ + g_flexspi->AHBRXBUFCR0[2] = FLEXSPI_AHBRXBUFCR0_BUFSZ(0) | + FLEXSPI_AHBRXBUFCR0_MSTRID(0) | + FLEXSPI_AHBRXBUFCR0_PREFETCHEN(1) | + FLEXSPI_AHBRXBUFCR0_REGIONEN(0); + + /* Disable 3 */ + g_flexspi->AHBRXBUFCR0[3] = FLEXSPI_AHBRXBUFCR0_BUFSZ(0) | + FLEXSPI_AHBRXBUFCR0_MSTRID(0) | + FLEXSPI_AHBRXBUFCR0_PREFETCHEN(1) | + FLEXSPI_AHBRXBUFCR0_REGIONEN(0); +#endif + + ARM_DSB(); + ARM_ISB(); + ARM_DMB(); +} + +/**************************************************************************** + * Name: imxrt_boardinitialize + * + * Description: + * All i.MX RT architectures must provide the following entry point. This + * entry point is called early in the initialization -- after clocking and + * memory have been configured but before caches have been enabled and + * before any devices have been initialized. + * + ****************************************************************************/ + +__EXPORT void imxrt_boardinitialize(void) +{ + imxrt_flash_setup_prefetch_partition(); + + imxrt_flash_romapi_initialize(); + + board_on_reset(-1); /* Reset PWM first thing */ + + /* configure LEDs */ + + board_autoled_initialize(); + + /* configure pins */ + + const uint32_t gpio[] = PX4_GPIO_INIT_LIST; + px4_gpio_init(gpio, arraySize(gpio)); + + imxrt_usb_initialize(); + + fmurt1062_timer_initialize(); +} + +/**************************************************************************** + * Function: imxrt_phy_boardinitialize + * + * Description: + * Some boards require specialized initialization of the PHY before it can + * be used. This may include such things as configuring GPIOs, resetting + * the PHY, etc. + * If CONFIG_IMXRT_ENET_PHYINIT is defined in the configuration then the + * board specific logic must provide imxrt_phyinitialize(); + * The i.MX RT Ethernet driver will call this function one time before it + * first uses the PHY. + * + * Input Parameters: + * intf - Always zero for now. + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +int imxrt_phy_boardinitialize(int intf) +{ +#ifdef CONFIG_IMXRT_GPIO1_0_15_IRQ + /* Configure the PHY interrupt pin */ + + printf("Configuring interrupt: %08x\n", GPIO_ENET_INT); + imxrt_config_gpio(GPIO_ENET_INT); +#endif + return OK; +} + +void imxrt_flexio_clocking(void) +{ + uint32_t reg; + + /* Init USB PLL3 PFD2 */ + + reg = getreg32(IMXRT_CCM_ANALOG_PFD_480); + + while ((getreg32(IMXRT_CCM_ANALOG_PLL_USB1) & + CCM_ANALOG_PLL_USB1_LOCK) == 0) { + } + + reg &= ~CCM_ANALOG_PFD_480_PFD2_FRAC_MASK; + + /* Set PLL3 PFD2 to 480 * 18 / CONFIG_PLL3_PFD2_FRAC */ + + reg |= ((uint32_t)(CONFIG_PLL3_PFD2_FRAC) << CCM_ANALOG_PFD_480_PFD3_FRAC_SHIFT); + + putreg32(reg, IMXRT_CCM_ANALOG_PFD_480); + + reg = getreg32(IMXRT_CCM_CDCDR); + reg &= ~(CCM_CDCDR_FLEXIO1_CLK_SEL_MASK | + CCM_CDCDR_FLEXIO1_CLK_PODF_MASK | + CCM_CDCDR_FLEXIO1_CLK_PRED_MASK); + reg |= CCM_CDCDR_FLEXIO1_CLK_SEL(CONFIG_FLEXIO1_CLK); + reg |= CCM_CDCDR_FLEXIO1_CLK_PODF + (CCM_PODF_FROM_DIVISOR(CONFIG_FLEXIO1_PODF_DIVIDER)); + reg |= CCM_CDCDR_FLEXIO1_CLK_PRED + (CCM_PRED_FROM_DIVISOR(CONFIG_FLEXIO1_PRED_DIVIDER)); + putreg32(reg, IMXRT_CCM_CDCDR); +} + + +/**************************************************************************** + * Name: board_app_initialize + * + * Description: + * Perform application specific initialization. This function is never + * called directly from application code, but only indirectly via the + * (non-standard) boardctl() interface using the command BOARDIOC_INIT. + * + * Input Parameters: + * arg - The boardctl() argument is passed to the board_app_initialize() + * implementation without modification. The argument has no + * meaning to NuttX; the meaning of the argument is a contract + * between the board-specific initalization logic and the the + * matching application logic. The value cold be such things as a + * mode enumeration value, a set of DIP switch switch settings, a + * pointer to configuration data read from a file or serial FLASH, + * or whatever you would like to do with it. Every implementation + * should accept zero/NULL as a default configuration. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure to indicate the nature of the failure. + * + ****************************************************************************/ +__EXPORT int board_app_initialize(uintptr_t arg) +{ + int ret = OK; + +#if !defined(BOOTLOADER) + + imxrt_flexio_clocking(); + + /* Power on Interfaces */ + + px4_platform_init(); + + imxrt_spiinitialize(); + + board_determine_hw_info(); + + /* configure the DMA allocator */ + + if (board_dma_alloc_init() < 0) { + syslog(LOG_ERR, "[boot] DMA alloc FAILED\n"); + } + +#if defined(SERIAL_HAVE_RXDMA) + // set up the serial DMA polling at 1ms intervals for received bytes that have not triggered a DMA event. + static struct hrt_call serial_dma_call; + hrt_call_every(&serial_dma_call, 1000, 1000, (hrt_callout)imxrt_serial_dma_poll, NULL); +#endif + +#if defined(CONFIG_IMXRT_USDHC) + ret = fmurt1062_usdhc_initialize(); +#endif + + imxrt_spiinitialize(); + + board_spi_reset(10, 0xffff); + +#ifdef CONFIG_IMXRT_ENET + imxrt_gpio_write(GPIO_ENET_RST, true); + + usleep(2000); + + imxrt_netinitialize(0); +#endif + +#ifdef CONFIG_IMXRT_FLEXCAN3 + imxrt_caninitialize(3); +#endif + + ret = imxrt_flexspi_storage_initialize(); + + if (ret < 0) { + syslog(LOG_ERR, + "ERROR: imxrt_flexspi_nor_initialize failed: %d\n", ret); + } + +#endif /* !defined(BOOTLOADER) */ + + return ret; +} diff --git a/boards/nxp/mr-tropic/src/manifest.c b/boards/nxp/mr-tropic/src/manifest.c new file mode 100644 index 0000000000..afd3de58e5 --- /dev/null +++ b/boards/nxp/mr-tropic/src/manifest.c @@ -0,0 +1,79 @@ +/**************************************************************************** + * + * 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 manifest.c + * + * This module supplies the interface to the manifest of hardware that is + * optional and dependent on the HW REV and HW VER IDs + * + * The manifest allows the system to know whether a hardware option + * say for example the PX4IO is an no-pop option vs it is broken. + * + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "systemlib/px4_macros.h" +#include "px4_log.h" + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + + +/************************************************************************************ + * Name: board_query_manifest + * + * Description: + * Optional returns manifest item. + * + * Input Parameters: + * manifest_id - the ID for the manifest item to retrieve + * + * Returned Value: + * 0 - item is not in manifest => assume legacy operations + * pointer to a manifest item + * + ************************************************************************************/ + +__EXPORT px4_hw_mft_item board_query_manifest(px4_hw_mft_item_id_t id) +{ + return px4_hw_mft_unsupported; +} diff --git a/boards/nxp/mr-tropic/src/sdhc.c b/boards/nxp/mr-tropic/src/sdhc.c new file mode 100644 index 0000000000..df2f92cc1c --- /dev/null +++ b/boards/nxp/mr-tropic/src/sdhc.c @@ -0,0 +1,128 @@ +/**************************************************************************** + * + * Copyright (C) 2016-2018 Gregory Nutt. All rights reserved. + * Authors: Gregory Nutt + * David Sidrane + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ +/* A micro Secure Digital (SD) card slot is available on the board connected to + * the SD Host Controller (USDHC1) signals of the MCU. This slot will accept + * micro format SD memory cards. + * + * ------------ ------------- -------- + * SD Card Slot Board Signal IMXRT Pin + * ------------ ------------- -------- + * DAT0 USDHC1_DATA0 GPIO_SD_B0_02 + * DAT1 USDHC1_DATA1 GPIO_SD_B0_03 + * DAT2 USDHC1_DATA2 GPIO_SD_B0_04 + * CD/DAT3 USDHC1_DATA3 GPIO_SD_B0_05 + * CMD USDHC1_CMD GPIO_SD_B0_00 + * CLK USDHC1_CLK GPIO_SD_B0_01 + * CD USDHC1_CD GPIO_B1_12 + * ------------ ------------- -------- + * + * There are no Write Protect available to the IMXRT. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "chip.h" +#include "imxrt_usdhc.h" + +#include "board_config.h" + +#ifdef CONFIG_IMXRT_USDHC +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ +/**************************************************************************** + * Private Data + ****************************************************************************/ +/**************************************************************************** + * Private Functions + ****************************************************************************/ +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: fmurt1062_usdhc_initialize + * + * Description: + * Inititialize the SDHC SD card slot + * + ****************************************************************************/ + +int fmurt1062_usdhc_initialize(void) +{ + int ret; + + /* Mount the SDHC-based MMC/SD block driver */ + /* First, get an instance of the SDHC interface */ + + struct sdio_dev_s *sdhc = imxrt_usdhc_initialize(CONFIG_NSH_MMCSDSLOTNO); + + if (!sdhc) { + PX4_ERR("ERROR: Failed to initialize SDHC slot %d\n", CONFIG_NSH_MMCSDSLOTNO); + return -ENODEV; + } + + /* Now bind the SDHC interface to the MMC/SD driver */ + + ret = mmcsd_slotinitialize(CONFIG_NSH_MMCSDMINOR, sdhc); + + if (ret != OK) { + PX4_ERR("ERROR: Failed to bind SDHC to the MMC/SD driver: %d\n", ret); + return ret; + } + + syslog(LOG_INFO, "Successfully bound SDHC to the MMC/SD driver\n"); + + return OK; +} +#endif /* CONFIG_IMXRT_USDHC */ diff --git a/boards/nxp/mr-tropic/src/spi.cpp b/boards/nxp/mr-tropic/src/spi.cpp new file mode 100644 index 0000000000..afea0032a5 --- /dev/null +++ b/boards/nxp/mr-tropic/src/spi.cpp @@ -0,0 +1,95 @@ +/************************************************************************************ + * + * Copyright (C) 2016, 2018 Gregory Nutt. All rights reserved. + * Authors: Gregory Nutt + * David Sidrane + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name 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. + * + ************************************************************************************/ + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include "imxrt_lpspi.h" +#include "imxrt_gpio.h" +#include "board_config.h" +#include + +constexpr px4_spi_bus_all_hw_t px4_spi_buses_all_hw[BOARD_NUM_SPI_CFG_HW_VERSIONS] = { + initSPIFmumID(TROPIC_0, { + initSPIBus(SPI::Bus::LPSPI3, { + initSPIDevice(DRV_IMU_DEVTYPE_ICM45686, SPI::CS{GPIO::Port1, GPIO::Pin28}, SPI::DRDY{GPIO::Port3, GPIO::Pin18}), /* GPIO_AD_B1_12 GPIO1_IO28 */ + }), + initSPIBus(SPI::Bus::LPSPI4, { + initSPIDevice(DRV_GYR_DEVTYPE_BMI088, SPI::CS{GPIO::Port2, GPIO::Pin18}, SPI::DRDY{GPIO::Port2, GPIO::Pin10}), /* GPIO_B1_02 GPIO2_IO18 */ + initSPIDevice(DRV_ACC_DEVTYPE_BMI088, SPI::CS{GPIO::Port2, GPIO::Pin0}, SPI::DRDY{GPIO::Port1, GPIO::Pin25}), /* GPIO_B0_00 GPIO2_IO00 */ + }), + }), + + initSPIFmumID(TROPIC_1, { + initSPIBus(SPI::Bus::LPSPI3, { + initSPIDevice(DRV_IMU_DEVTYPE_ICM42688P, SPI::CS{GPIO::Port1, GPIO::Pin28}), /* GPIO_AD_B1_12 GPIO1_IO28 */ + }), + initSPIBus(SPI::Bus::LPSPI4, { + initSPIDevice(DRV_GYR_DEVTYPE_BMI088, SPI::CS{GPIO::Port2, GPIO::Pin18}), /* GPIO_B1_02 GPIO2_IO18 */ + initSPIDevice(DRV_ACC_DEVTYPE_BMI088, SPI::CS{GPIO::Port2, GPIO::Pin0}), /* GPIO_B0_00 GPIO2_IO00 */ + }), + }), + + initSPIFmumID(TROPIC_2, { + initSPIBus(SPI::Bus::LPSPI3, { + initSPIDevice(DRV_IMU_DEVTYPE_ICM42686P, SPI::CS{GPIO::Port1, GPIO::Pin28}), /* GPIO_AD_B1_12 GPIO1_IO28 */ + }), + initSPIBus(SPI::Bus::LPSPI4, { + initSPIDevice(DRV_GYR_DEVTYPE_BMI088, SPI::CS{GPIO::Port2, GPIO::Pin18}), /* GPIO_B1_02 GPIO2_IO18 */ + initSPIDevice(DRV_ACC_DEVTYPE_BMI088, SPI::CS{GPIO::Port2, GPIO::Pin0}), /* GPIO_B0_00 GPIO2_IO00 */ + }), + }), +}; + +static constexpr bool unused = validateSPIConfig(px4_spi_buses_all_hw); diff --git a/boards/nxp/mr-tropic/src/timer_config.cpp b/boards/nxp/mr-tropic/src/timer_config.cpp new file mode 100644 index 0000000000..a15a7e83fb --- /dev/null +++ b/boards/nxp/mr-tropic/src/timer_config.cpp @@ -0,0 +1,152 @@ +/**************************************************************************** + * + * Copyright (C) 2024 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ +#include + +#include +#include "hardware/imxrt_tmr.h" +#include "hardware/imxrt_flexpwm.h" +#include "imxrt_gpio.h" +#include "imxrt_iomuxc.h" +#include "hardware/imxrt_pinmux.h" +#include "imxrt_xbar.h" +#include "imxrt_periphclks.h" + +#include +#include + +#include "board_config.h" + +/**************************************************************************************************** + * Definitions + ****************************************************************************************************/ + +/* Register accessors */ + +#define _REG(_addr) (*(volatile uint16_t *)(_addr)) + +/* QTimer3 register accessors */ + +#define REG(_reg) _REG(IMXRT_QTIMER3_BASE + IMXRT_TMR_OFFSET(IMXRT_TMR_CH0,(_reg))) + +#define rCOMP1 REG(IMXRT_TMR_COMP1_OFFSET) +#define rCOMP2 REG(IMXRT_TMR_COMP2_OFFSET) +#define rCAPT REG(IMXRT_TMR_CAPT_OFFSET) +#define rLOAD REG(IMXRT_TMR_LOAD_OFFSET) +#define rHOLD REG(IMXRT_TMR_HOLD_OFFSET) +#define rCNTR REG(IMXRT_TMR_CNTR_OFFSET) +#define rCTRL REG(IMXRT_TMR_CTRL_OFFSET) +#define rSCTRL REG(IMXRT_TMR_SCTRL_OFFSET) +#define rCMPLD1 REG(IMXRT_TMR_CMPLD1_OFFSET) +#define rCMPLD2 REG(IMXRT_TMR_CMPLD2_OFFSET) +#define rCSCTRL REG(IMXRT_TMR_CSCTRL_OFFSET) +#define rFILT REG(IMXRT_TMR_FILT_OFFSET) +#define rDMA REG(IMXRT_TMR_DMA_OFFSET) +#define rENBL REG(IMXRT_TMR_ENBL_OFFSET) + + +constexpr io_timers_t io_timers[MAX_IO_TIMERS] = { + initIOPWMDshot(PWM::FlexPWM2, PWM::Submodule0), // PWM_1, PMW_2 + initIOPWMDshot(PWM::FlexPWM2, PWM::Submodule1), // PWM_3, PWM_4 + initIOPWMDshot(PWM::FlexPWM4, PWM::Submodule1), // PWM_5, PWM_6 + initIOPWMDshot(PWM::FlexPWM4, PWM::Submodule2), // PWM_7, PWM_8 +}; + +#define FXIO_IOMUX (IOMUX_SLEW_FAST | IOMUX_DRIVE_130OHM | IOMUX_PULL_UP_47K | IOMUX_SCHMITT_TRIGGER) + +constexpr timer_io_channels_t timer_io_channels[MAX_TIMER_IO_CHANNELS] = { + initIOTimerChannelDshot(io_timers, {PWM::PWM2_PWM_A, PWM::Submodule0}, IOMUX::Pad::GPIO_EMC_06, GPIO_FLEXIO1_FLEXIO06_1 | FXIO_IOMUX, 6), + initIOTimerChannelDshot(io_timers, {PWM::PWM2_PWM_B, PWM::Submodule0}, IOMUX::Pad::GPIO_EMC_07, GPIO_FLEXIO1_FLEXIO07_1 | FXIO_IOMUX, 7), + initIOTimerChannelDshot(io_timers, {PWM::PWM2_PWM_A, PWM::Submodule1}, IOMUX::Pad::GPIO_EMC_08, GPIO_FLEXIO1_FLEXIO08_1 | FXIO_IOMUX, 8), + initIOTimerChannelDshot(io_timers, {PWM::PWM2_PWM_B, PWM::Submodule1}, IOMUX::Pad::GPIO_EMC_09, GPIO_FLEXIO1_FLEXIO09_1 | FXIO_IOMUX, 9), + initIOTimerChannelDshot(io_timers, {PWM::PWM4_PWM_A, PWM::Submodule1}, IOMUX::Pad::GPIO_EMC_02, GPIO_FLEXIO1_FLEXIO02_1 | FXIO_IOMUX, 2), + initIOTimerChannelDshot(io_timers, {PWM::PWM4_PWM_B, PWM::Submodule1}, IOMUX::Pad::GPIO_EMC_03, GPIO_FLEXIO1_FLEXIO03_1 | FXIO_IOMUX, 3), + initIOTimerChannelDshot(io_timers, {PWM::PWM4_PWM_A, PWM::Submodule2}, IOMUX::Pad::GPIO_EMC_04, GPIO_FLEXIO1_FLEXIO04_1 | FXIO_IOMUX, 4), + initIOTimerChannelDshot(io_timers, {PWM::PWM4_PWM_B, PWM::Submodule2}, IOMUX::Pad::GPIO_EMC_05, GPIO_FLEXIO1_FLEXIO05_1 | FXIO_IOMUX, 5), +}; + +constexpr io_timers_channel_mapping_t io_timers_channel_mapping = + initIOTimerChannelMapping(io_timers, timer_io_channels); + +constexpr io_timers_t led_pwm_timers[MAX_LED_TIMERS] = { +}; + +constexpr timer_io_channels_t led_pwm_channels[MAX_TIMER_LED_CHANNELS] = { +}; + +#include +void fmurt1062_timer_initialize(void) +{ + /* We must configure Qtimer 3 as the IPG divide by to yield 16 Mhz + * and deliver that clock to the eFlexPWM234 via XBAR + * + * IPG = 144 Mhz + * 16Mhz = 144 / 9 + * COMP 1 = 5, COMP2 = 4 + * + * */ + + /* Enable Block Clocks for Qtimer and XBAR1 */ + + imxrt_clockall_timer3(); + imxrt_clockall_xbar1(); + + /* Disable Timer */ + + rCTRL = 0; + rCOMP1 = 5 - 1; // N - 1 + rCOMP2 = 4 - 1; + + rCAPT = 0; + rLOAD = 0; + rCNTR = 0; + + rSCTRL = TMR_SCTRL_OEN; + + rCMPLD1 = 0; + rCMPLD2 = 0; + rCSCTRL = 0; + rFILT = 0; + rDMA = 0; + + /* Count rising edges of primary source, + * Prescaler is /1 + * Count UP until compare, then re-initialize. a successful compare occurs when the counter reaches a COMP1 value. + * Toggle OFLAG output using alternating compare registers + */ + rCTRL = (TMR_CTRL_CM_MODE1 | TMR_CTRL_PCS_DIV1 | TMR_CTRL_LENGTH | TMR_CTRL_OUTMODE_TOG_ALT); + + /* QTIMER3_TIMER0 -> Flexpwm234ExtClk */ + + imxrt_xbar_connect(IMXRT_XBARA1_OUT_FLEXPWM234_EXT_CLK_SEL_OFFSET, IMXRT_XBARA1_IN_QTIMER3_TMR0_OUT); + imxrt_xbar_connect(IMXRT_XBARA1_OUT_FLEXPWM1_EXT_CLK_SEL_OFFSET, IMXRT_XBARA1_IN_QTIMER3_TMR0_OUT); +} diff --git a/boards/nxp/mr-tropic/src/tropic_led_pwm.cpp b/boards/nxp/mr-tropic/src/tropic_led_pwm.cpp new file mode 100644 index 0000000000..45598fc787 --- /dev/null +++ b/boards/nxp/mr-tropic/src/tropic_led_pwm.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** + * + * Copyright (c) 2024 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 Airmind 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 tropic_led_pwm.cpp +*/ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include "imxrt_xbar.h" +#include "imxrt_periphclks.h" +#include "hardware/imxrt_tmr.h" +#include "hardware/imxrt_flexpwm.h" + +#define LED_PWM_FREQ 1000 +#define FLEXPWM_FREQ 1000000 +#define QTMR_FREQ (144000000/128) + +#define SM_SPACING (IMXRT_FLEXPWM_SM1CNT_OFFSET-IMXRT_FLEXPWM_SM0CNT_OFFSET) + +#define FLEXPWM_TIMER_BASE IMXRT_FLEXPWM2_BASE + +/* Register accessors */ +#define _REG(_addr) (*(volatile uint16_t *)(_addr)) +#define _REG16(_base, _reg) (*(volatile uint16_t *)(_base + _reg)) +#define FLEXPWMREG(_tmr, _sm, _reg) _REG16(_tmr + ((_sm) * SM_SPACING), (_reg)) + +/* FlexPWM Registers for LED_G */ +#define rINIT(_tim, _sm) FLEXPWMREG(_tim, _sm,IMXRT_FLEXPWM_SM0INIT_OFFSET) /* Initial Count Register */ +#define rCTRL(_tim, _sm) FLEXPWMREG(_tim, _sm,IMXRT_FLEXPWM_SM0CTRL_OFFSET) /* Control Register */ +#define rCTRL2(_tim, _sm) FLEXPWMREG(_tim, _sm,IMXRT_FLEXPWM_SM0CTRL2_OFFSET) /* Control 2 Register */ +#define rFSTS0(_tim) FLEXPWMREG(_tim, 0, IMXRT_FLEXPWM_FSTS0_OFFSET) /* Fault Status Register */ +#define rVAL0(_tim, _sm) FLEXPWMREG(_tim, _sm,IMXRT_FLEXPWM_SM0VAL0_OFFSET) /* Value Register 0 */ +#define rVAL1(_tim, _sm) FLEXPWMREG(_tim, _sm,IMXRT_FLEXPWM_SM0VAL1_OFFSET) /* Value Register 1 */ +#define rVAL2(_tim, _sm) FLEXPWMREG(_tim, _sm,IMXRT_FLEXPWM_SM0VAL2_OFFSET) /* Value Register 2 */ +#define rVAL3(_tim, _sm) FLEXPWMREG(_tim, _sm,IMXRT_FLEXPWM_SM0VAL3_OFFSET) /* Value Register 3 */ +#define rVAL4(_tim, _sm) FLEXPWMREG(_tim, _sm,IMXRT_FLEXPWM_SM0VAL4_OFFSET) /* Value Register 4 */ +#define rVAL5(_tim, _sm) FLEXPWMREG(_tim, _sm,IMXRT_FLEXPWM_SM0VAL5_OFFSET) /* Value Register 5 */ +#define rFFILT0(_tim) FLEXPWMREG(_tim, 0, IMXRT_FLEXPWM_FFILT0_OFFSET) /* Fault Filter Register */ +#define rDISMAP0(_tim, _sm) FLEXPWMREG(_tim, _sm,IMXRT_FLEXPWM_SM0DISMAP0_OFFSET) /* Fault Disable Mapping Register 0 */ +#define rDISMAP1(_tim, _sm) FLEXPWMREG(_tim, _sm,IMXRT_FLEXPWM_SM0DISMAP1_OFFSET) /* Fault Disable Mapping Register 1 */ +#define rOUTEN(_tim) FLEXPWMREG(_tim, 0, IMXRT_FLEXPWM_OUTEN_OFFSET) /* Output Enable Register */ +#define rDTSRCSEL(_tim) FLEXPWMREG(_tim, 0, IMXRT_FLEXPWM_DTSRCSEL_OFFSET) /* PWM Source Select Register */ +#define rMCTRL(_tim) FLEXPWMREG(_tim, 0, IMXRT_FLEXPWM_MCTRL_OFFSET) /* Master Control Register */ + +#define OUTEN_A_MASK 0x1 +#define OUTEN_B_MASK 0x2 + +#define FREQ + +static void flexpwm_led(uint32_t timer, uint32_t sm, uint16_t cvalue, uint32_t gpio_mux, uint32_t pwm_mux, + uint32_t out_mask) +{ + if (cvalue == 0) { + //rMCTRL(timer) &= ~MCTRL_RUN(1 << sm); + px4_arch_configgpio(gpio_mux); + + } else { + rMCTRL(timer) |= (1 << (sm + MCTRL_CLDOK_SHIFT)); + rVAL1(timer, sm) = (FLEXPWM_FREQ / LED_PWM_FREQ) - 1; + + if (out_mask & OUTEN_A_MASK) { + rVAL3(timer, sm) = (FLEXPWM_FREQ / LED_PWM_FREQ) - (cvalue); + + } else if (out_mask & OUTEN_B_MASK) { + rVAL5(timer, sm) = (FLEXPWM_FREQ / LED_PWM_FREQ) - (cvalue); + } + + rMCTRL(timer) |= MCTRL_LDOK(1 << sm) | MCTRL_RUN(1 << sm); + px4_arch_configgpio(pwm_mux); + } +} + +int +led_pwm_servo_set(unsigned channel, uint8_t cvalue) +{ + if (channel == 0) { + flexpwm_led(IMXRT_FLEXPWM3_BASE, 2, cvalue, GPIO_nLED_RED, PWM_LED_RED, OUTEN_A_MASK); + + } else if (channel == 1) { + flexpwm_led(IMXRT_FLEXPWM1_BASE, 3, cvalue, GPIO_nLED_GREEN, PWM_LED_GREEN, OUTEN_A_MASK); + + } else if (channel == 2) { + flexpwm_led(IMXRT_FLEXPWM3_BASE, 2, cvalue * 3, GPIO_nLED_BLUE, PWM_LED_BLUE, OUTEN_B_MASK); + } + + return 0; +} + +void flexpwm_init(uint32_t timer, uint32_t sm, uint32_t out_mask) +{ + /* Clear all Faults */ + rFSTS0(timer) = FSTS_FFLAG_MASK; + rMCTRL(timer) |= (1 << (sm + MCTRL_CLDOK_SHIFT)); + + rCTRL2(timer, sm) = SMCTRL2_CLK_SEL_EXT_CLK | SMCTRL2_DBGEN | SMCTRL2_INDEP; + rCTRL(timer, sm) = SMCTRL_PRSC_DIV16 | SMCTRL_FULL; + /* Edge aligned at 0 */ + rINIT(timer, sm) = 0; + rVAL0(timer, sm) = 0; + rVAL2(timer, sm) = 0; + rVAL4(timer, sm) = 0; + rFFILT0(timer) &= ~FFILT_FILT_PER_MASK; + rDISMAP0(timer, sm) = 0xf000; + rDISMAP1(timer, sm) = 0xf000; + + + if (out_mask & OUTEN_A_MASK) { + rOUTEN(timer) |= OUTEN_PWMA_EN(1 << sm); + } + + if (out_mask & OUTEN_B_MASK) { + rOUTEN(timer) |= OUTEN_PWMB_EN(1 << sm); + } + + rDTSRCSEL(timer) = 0; + rMCTRL(timer) |= MCTRL_LDOK(1 << sm); +} + +int led_pwm_servo_init() +{ + /* PWM_LED_GREEN - FLEXPWM2_PWMB03 */ + imxrt_clockall_pwm1(); + imxrt_clockall_pwm3(); + + flexpwm_init(IMXRT_FLEXPWM3_BASE, 2, OUTEN_A_MASK | OUTEN_B_MASK); // GPIO_FLEXPWM3_PWMA02_1 + flexpwm_init(IMXRT_FLEXPWM1_BASE, 3, OUTEN_A_MASK); // GPIO_FLEXPWM1_PWMA03_2 + + + + return OK; +} diff --git a/boards/nxp/mr-tropic/src/usb.c b/boards/nxp/mr-tropic/src/usb.c new file mode 100644 index 0000000000..cae9750e9c --- /dev/null +++ b/boards/nxp/mr-tropic/src/usb.c @@ -0,0 +1,129 @@ +/**************************************************************************** + * + * Copyright (C) 2024 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 usb.c + * + * Board-specific USB functions. + */ + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include "board_config.h" +#include "imxrt_periphclks.h" + +/************************************************************************************ + * Definitions + ************************************************************************************/ + +/************************************************************************************ + * Private Functions + ************************************************************************************/ + +/************************************************************************************ + * Public Functions + ************************************************************************************/ +int imxrt_usb_initialize(void) +{ + imxrt_clockall_usboh3(); + return 0; +} +/************************************************************************************ + * Name: imxrt_usbpullup + * + * Description: + * If USB is supported and the board supports a pullup via GPIO (for USB software + * connect and disconnect), then the board software must provide imxrt_usbpullup. + * See include/nuttx/usb/usbdev.h for additional description of this method. + * Alternatively, if no pull-up GPIO the following EXTERN can be redefined to be + * NULL. + * + ************************************************************************************/ + +__EXPORT +int imxrt_usbpullup(FAR struct usbdev_s *dev, bool enable) +{ + usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); + + return OK; +} + +/************************************************************************************ + * Name: imxrt_usbsuspend + * + * Description: + * Board logic must provide the imxrt_usbsuspend logic if the USBDEV driver is + * used. This function is called whenever the USB enters or leaves suspend mode. + * This is an opportunity for the board logic to shutdown clocks, power, etc. + * while the USB is suspended. + * + ************************************************************************************/ + +__EXPORT +void imxrt_usbsuspend(FAR struct usbdev_s *dev, bool resume) +{ + uinfo("resume: %d\n", resume); +} + +/************************************************************************************ + * Name: board_read_VBUS_state + * + * Description: + * All boards must provide a way to read the state of VBUS, this my be simple + * digital input on a GPIO. Or something more complicated like a Analong input + * or reading a bit from a USB controller register. + * + * Returns - 0 if connected. + * + ************************************************************************************/ + +int board_read_VBUS_state(void) +{ + + return (getreg32(IMXRT_USB_ANALOG_USB1_VBUS_DETECT_STAT) & USB_ANALOG_USB_VBUS_DETECT_STAT_VBUS_VALID) ? 0 : 1; +} diff --git a/platforms/common/include/px4_platform_common/board_common.h b/platforms/common/include/px4_platform_common/board_common.h index 8905507cd0..1056d721b9 100644 --- a/platforms/common/include/px4_platform_common/board_common.h +++ b/platforms/common/include/px4_platform_common/board_common.h @@ -157,8 +157,13 @@ #if BOARD_NUMBER_BRICKS == 0 /* allow SITL to disable all bricks */ #elif BOARD_NUMBER_BRICKS == 1 -# define BOARD_BATT_V_LIST {ADC_BATTERY_VOLTAGE_CHANNEL} -# define BOARD_BATT_I_LIST {ADC_BATTERY_CURRENT_CHANNEL} +# if defined(BOARD_NUMBER_DIGITAL_BRICKS) +# define BOARD_BATT_V_LIST {-1} +# define BOARD_BATT_I_LIST {-1} +# else +# define BOARD_BATT_V_LIST {ADC_BATTERY_VOLTAGE_CHANNEL} +# define BOARD_BATT_I_LIST {ADC_BATTERY_CURRENT_CHANNEL} +# endif # define BOARD_BRICK_VALID_LIST {BOARD_ADC_BRICK_VALID} #elif BOARD_NUMBER_BRICKS == 2 # if defined(BOARD_NUMBER_DIGITAL_BRICKS) diff --git a/platforms/nuttx/CMakeLists.txt b/platforms/nuttx/CMakeLists.txt index 4bee8ed581..49e44b12ae 100644 --- a/platforms/nuttx/CMakeLists.txt +++ b/platforms/nuttx/CMakeLists.txt @@ -507,6 +507,9 @@ if(NOT NUTTX_DIR MATCHES "external") if(CONFIG_ARCH_CHIP_MIMXRT1062DVL6A) set(DEBUG_DEVICE "MIMXRT1062XXX6A") set(DEBUG_SVD_FILE "MIMXRT1062.xml") + elseif(CONFIG_ARCH_CHIP_MIMXRT1064DVL6A) + set(DEBUG_DEVICE "MIMXRT1064XXX6A") + set(DEBUG_SVD_FILE "MIMXRT1064.xml") elseif(CONFIG_ARCH_CHIP_MIMXRT1176DVMAA) set(DEBUG_DEVICE "MIMXRT1176DVMAA") set(DEBUG_SVD_FILE "MIMXRT1176_cm7.xml") diff --git a/platforms/nuttx/NuttX/nuttx b/platforms/nuttx/NuttX/nuttx index d50ffd3544..fb2fadf6f5 160000 --- a/platforms/nuttx/NuttX/nuttx +++ b/platforms/nuttx/NuttX/nuttx @@ -1 +1 @@ -Subproject commit d50ffd354495ce5d30814dba41d2eb70a32b8fa3 +Subproject commit fb2fadf6f599c1406f052db013efd00a2518e72c diff --git a/platforms/nuttx/cmake/px4_impl_os.cmake b/platforms/nuttx/cmake/px4_impl_os.cmake index cefa37a6c2..98be37ff3f 100644 --- a/platforms/nuttx/cmake/px4_impl_os.cmake +++ b/platforms/nuttx/cmake/px4_impl_os.cmake @@ -158,6 +158,9 @@ function(px4_os_determine_build_chip) elseif(CONFIG_ARCH_CHIP_MIMXRT1062DVL6A) set(CHIP_MANUFACTURER "nxp") set(CHIP "rt106x") + elseif(CONFIG_ARCH_CHIP_MIMXRT1064DVL6A) + set(CHIP_MANUFACTURER "nxp") + set(CHIP "rt106x") elseif(CONFIG_ARCH_CHIP_MIMXRT1176DVMAA) set(CHIP_MANUFACTURER "nxp") set(CHIP "rt117x") diff --git a/platforms/nuttx/src/bootloader/nxp/imxrt_common/main.c b/platforms/nuttx/src/bootloader/nxp/imxrt_common/main.c index dcdc50a911..a137c8477b 100644 --- a/platforms/nuttx/src/bootloader/nxp/imxrt_common/main.c +++ b/platforms/nuttx/src/bootloader/nxp/imxrt_common/main.c @@ -9,9 +9,19 @@ #include "hw_config.h" #include #include -#include -#include -#include +#ifdef CONFIG_ARCH_FAMILY_IMXRT117x +# include +# include +# include +#else +# include +# include +# include +# include +# include "hardware/imxrt_ccm.h" +# include "imxrt_periphclks.h" +# define SNVS_LPCR_GPR_Z_DIS (1 << 24) /* Bit 24: General Purpose Registers Zeroization Disable */ +#endif #include #include "imxrt_clockconfig.h" @@ -30,14 +40,31 @@ #define APP_SIZE_MAX (BOARD_FLASH_SIZE - (BOOTLOADER_RESERVATION_SIZE + APP_RESERVATION_SIZE)) +#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)) +#elif defined(CONFIG_ARCH_FAMILY_IMXRT106x) +#define CHIP_TAG "i.MX RT10?? r?.?" +#define DIGPROG_MINOR_SHIFT 0 +#define DIGPROG_MINOR_MASK (0xff << DIGPROG_MINOR_SHIFT) +#define DIGPROG_MINOR(info) (((info) & DIGPROG_MINOR_MASK) >> DIGPROG_MINOR_SHIFT) +#define DIGPROG_MAJOR_LOWER_SHIFT 8 +#define DIGPROG_MAJOR_LOWER_MASK (0xff << DIGPROG_MAJOR_LOWER_SHIFT) +#define DIGPROG_MAJOR_LOWER(info) (((info) & DIGPROG_MAJOR_LOWER_MASK) >> DIGPROG_MAJOR_LOWER_SHIFT) +#define DIGPROG_MAJOR_UPPER_SHIFT 16 +#define DIGPROG_MAJOR_UPPER_MASK (0xff << DIGPROG_MAJOR_UPPER_SHIFT) +#define DIGPROG_MAJOR_UPPER(info) (((info) & DIGPROG_MAJOR_UPPER_MASK) >> DIGPROG_MAJOR_UPPER_SHIFT) +#endif +#define CHIP_TAG_LEN sizeof(CHIP_TAG)-1 +#ifdef CONFIG_ARCH_FAMILY_IMXRT117x +#define FLASH_BASE IMXRT_FLEXSPI1_CIPHER_BASE +#elif defined(CONFIG_ARCH_CHIP_MIMXRT1064DVL6A) +#define FLASH_BASE IMXRT_FLEX2CIPHER_BASE +#endif /* context passed to cinit */ #if INTERFACE_USART @@ -287,6 +314,27 @@ board_deinit(void) px4_arch_configgpio(MK_GPIO_INPUT(BOARD_PIN_LED_BOOTLOADER)); #endif +#ifdef CONFIG_ARCH_FAMILY_IMXRT106x + + // Restore CCM registers to ROM state + putreg32(0x00000001, IMXRT_CCM_CACRR); + putreg32(0x000A8200, IMXRT_CCM_CBCDR); + putreg32(0x06490B03, IMXRT_CCM_CSCDR1); + putreg32(0x75AE8104, IMXRT_CCM_CBCMR); + putreg32(0x67930001, IMXRT_CCM_CSCMR1); + + imxrt_clockoff_lpuart3(); + imxrt_clockoff_usboh3(); + imxrt_clockoff_timer3(); + imxrt_clockoff_xbar1(); + imxrt_clockoff_xbar3(); + + up_disable_icache(); + up_disable_dcache(); + +#endif + +#ifdef CONFIG_ARCH_FAMILY_IMXRT117x const uint32_t dnfw[] = { CCM_CR_M7, CCM_CR_BUS, @@ -309,6 +357,8 @@ board_deinit(void) putreg32(CCM_CR_CTRL_OFF, IMXRT_CCM_CR_CTRL(i)); } } + +#endif } inline void arch_systic_init(void) @@ -365,7 +415,7 @@ ssize_t arch_flash_write(uintptr_t address, const void *buffer, size_t buflen) j++; } - uintptr_t offset = ((uintptr_t) address) - IMXRT_FLEXSPI1_CIPHER_BASE; + uintptr_t offset = ((uintptr_t) address) - FLASH_BASE; volatile uint32_t status = ROM_FLEXSPI_NorFlash_ProgramPage(1, pConfig, offset, (const uint32_t *)buffer); up_invalidate_dcache((uintptr_t)address, @@ -400,7 +450,7 @@ flash_func_sector_size(unsigned sector) ssize_t up_progmem_ispageerased(unsigned sector) { const uint32_t bytes_per_sector = flash_func_sector_size(sector); - uint32_t *address = (uint32_t *)(IMXRT_FLEXSPI1_CIPHER_BASE + (sector * bytes_per_sector)); + uint32_t *address = (uint32_t *)(FLASH_BASE + (sector * bytes_per_sector)); const uint32_t uint32_per_sector = bytes_per_sector / sizeof(*address); int blank = 0; /* Assume it is Bank */ @@ -437,9 +487,9 @@ flash_func_erase_sector(unsigned sector, bool force) struct flexspi_nor_config_s *pConfig = &g_bootConfig; const uint32_t bytes_per_sector = flash_func_sector_size(sector); - uint32_t *address = (uint32_t *)(IMXRT_FLEXSPI1_CIPHER_BASE + (sector * bytes_per_sector)); + uint32_t *address = (uint32_t *)(FLASH_BASE + (sector * bytes_per_sector)); - uintptr_t offset = ((uintptr_t) address) - IMXRT_FLEXSPI1_CIPHER_BASE; + uintptr_t offset = ((uintptr_t) address) - FLASH_BASE; irqstate_t flags; flags = enter_critical_section(); volatile uint32_t status = ROM_FLEXSPI_NorFlash_Erase(1, pConfig, (uintptr_t) offset, bytes_per_sector); @@ -473,6 +523,8 @@ flash_func_read_otp(uintptr_t address) return 0; } +#ifdef CONFIG_ARCH_FAMILY_IMXRT117x + uint32_t get_mcu_id(void) { // ??? is DEBUGMCU get able @@ -499,6 +551,36 @@ int get_mcu_desc(int max, uint8_t *revstr) return strp - revstr; } +#elif defined(CONFIG_ARCH_FAMILY_IMXRT106x) + +uint32_t get_mcu_id(void) +{ + return getreg32(IMXRT_OCOTP_UNIQUE_ID_LSB); +} + +int get_mcu_desc(int max, uint8_t *revstr) +{ + uint32_t info = getreg32(IMXRT_USB_ANALOG_DIGPROG); + // CHIP_TAG "i.MX RT10?? r?.?" + static uint8_t chip[sizeof(CHIP_TAG) + 1] = CHIP_TAG; + chip[CHIP_TAG_LEN - 1] = '0' + DIGPROG_MINOR(info); + chip[CHIP_TAG_LEN - 3] = '1' + DIGPROG_MAJOR_LOWER(info); + chip[CHIP_TAG_LEN - 6] = getreg32(0x401F867C) == 0x10 ? '4' : '2'; + chip[CHIP_TAG_LEN - 7] = DIGPROG_MAJOR_UPPER(info) == 0x6a ? '5' : '6'; + + uint8_t *endp = &revstr[max - 1]; + uint8_t *strp = revstr; + uint8_t *des = chip; + + while (strp < endp && *des) { + *strp++ = *des++; + } + + return strp - revstr; +} + +#endif + int check_silicon(void) { @@ -717,6 +799,7 @@ bootloader_main(void) * Returns - 0 if connected. * ************************************************************************************/ +#ifdef CONFIG_ARCH_FAMILY_IMXRT117x #undef IMXRT_USB_ANALOG_USB1_VBUS_DETECT_STAT #define USB1_VBUS_DET_STAT_OFFSET 0xd0 #define IMXRT_USB_ANALOG_USB1_VBUS_DETECT_STAT (IMXRT_USBPHY1_BASE + USB1_VBUS_DET_STAT_OFFSET) @@ -727,6 +810,17 @@ bootloader_main(void) try_boot = false; } +#elif defined(CONFIG_ARCH_FAMILY_IMXRT106x) +#undef IMXRT_USB_ANALOG_USB1_VBUS_DETECT_STAT +#define IMXRT_USB_ANALOG_USB1_VBUS_DETECT_STAT (IMXRT_ANATOP_BASE + IMXRT_USB_ANALOG_USB1_VBUS_DETECT_STAT_OFFSET) + + if ((getreg32(IMXRT_USB_ANALOG_USB1_VBUS_DETECT_STAT) & USB_ANALOG_USB_VBUS_DETECT_STAT_VBUS_VALID) != 0) { + usb_connected = true; + /* don't try booting before we set up the bootloader */ + try_boot = false; + } + +#endif #endif #if INTERFACE_USART diff --git a/platforms/nuttx/src/bootloader/nxp/rt106x/CMakeLists.txt b/platforms/nuttx/src/bootloader/nxp/rt106x/CMakeLists.txt new file mode 100644 index 0000000000..a1c9b593c9 --- /dev/null +++ b/platforms/nuttx/src/bootloader/nxp/rt106x/CMakeLists.txt @@ -0,0 +1,34 @@ +############################################################################ +# +# 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. +# +############################################################################ + +add_subdirectory(../imxrt_common arch_bootloader) diff --git a/platforms/nuttx/src/px4/nxp/imxrt/board_reset/CMakeLists.txt b/platforms/nuttx/src/px4/nxp/imxrt/board_reset/CMakeLists.txt index deff20f14c..cba22cb320 100644 --- a/platforms/nuttx/src/px4/nxp/imxrt/board_reset/CMakeLists.txt +++ b/platforms/nuttx/src/px4/nxp/imxrt/board_reset/CMakeLists.txt @@ -35,9 +35,7 @@ px4_add_library(arch_board_reset board_reset.cpp ) -if (CONFIG_ARCH_FAMILY_IMXRT117x) target_link_libraries(arch_board_reset PRIVATE arch_board_romapi) -endif() # up_systemreset if (NOT DEFINED CONFIG_BUILD_FLAT) diff --git a/platforms/nuttx/src/px4/nxp/imxrt/board_reset/board_reset.cpp b/platforms/nuttx/src/px4/nxp/imxrt/board_reset/board_reset.cpp index 1d29a64dfb..85236a00e6 100644 --- a/platforms/nuttx/src/px4/nxp/imxrt/board_reset/board_reset.cpp +++ b/platforms/nuttx/src/px4/nxp/imxrt/board_reset/board_reset.cpp @@ -45,6 +45,12 @@ #ifdef CONFIG_ARCH_FAMILY_IMXRT117x #include +#elif defined CONFIG_ARCH_FAMILY_IMXRT106x +# include +# define SNVS_LPCR_GPR_Z_DIS (1 << 24) /* Bit 24: General Purpose Registers Zeroization Disable */ +#endif + +#ifdef BOARD_HAS_ISP_BOOTLOADER #include #include #endif @@ -59,13 +65,9 @@ static int board_reset_enter_bootloader() { -#ifdef CONFIG_ARCH_FAMILY_IMXRT117x uint32_t regvalue = BOOT_RTC_SIGNATURE; modifyreg32(IMXRT_SNVS_LPCR, 0, SNVS_LPCR_GPR_Z_DIS); putreg32(regvalue, PX4_IMXRT_RTC_REBOOT_REG_ADDRESS); -#elif defined(BOARD_HAS_TEENSY_BOOTLOADER) - asm("BKPT #251"); /* Enter Teensy MKL02 bootloader */ -#endif return OK; } @@ -75,15 +77,16 @@ int board_reset(int status) board_reset_enter_bootloader(); } -#if defined(BOARD_HAS_ISP_BOOTLOADER) - else if (status == REBOOT_TO_ISP) { +#ifdef BOARD_HAS_TEENSY_BOOTLOADER + asm("BKPT #251"); /* Enter Teensy MKL02 bootloader */ +#elif defined(BOARD_HAS_ISP_BOOTLOADER) uint32_t arg = 0xeb100000; ROM_API_Init(); ROM_RunBootloader(&arg); +#endif } -#endif #if defined(BOARD_HAS_ON_RESET) board_on_reset(status); diff --git a/platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/imxrt_flexspi_nor_flash.h b/platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/imxrt_flexspi_nor_flash.h index 727744b974..e58554aa5b 100644 --- a/platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/imxrt_flexspi_nor_flash.h +++ b/platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/imxrt_flexspi_nor_flash.h @@ -138,18 +138,33 @@ (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \ FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) +#ifdef CONFIG_ARCH_FAMILY_IMXRT106x +//!@brief Definitions for FlexSPI Serial Clock Frequency +typedef enum _FlexSpiSerialClockFreq { + kFlexSpiSerialClk_30MHz = 1, + kFlexSpiSerialClk_50MHz = 2, + kFlexSpiSerialClk_60MHz = 3, + kFlexSpiSerialClk_75MHz = 4, + kFlexSpiSerialClk_80MHz = 5, + kFlexSpiSerialClk_100MHz = 6, + kFlexSpiSerialClk_120MHz = 7, + kFlexSpiSerialClk_133MHz = 8, + kFlexSpiSerialClk_166MHz = 9, +} flexspi_serial_clk_freq_t; +#elif defined(CONFIG_ARCH_FAMILY_IMXRT117x) //!@brief Definitions for FlexSPI Serial Clock Frequency typedef enum _FlexSpiSerialClockFreq { kFlexSpiSerialClk_30MHz = 1, kFlexSpiSerialClk_50MHz = 2, kFlexSpiSerialClk_60MHz = 3, kFlexSpiSerialClk_80MHz = 4, - kFlexSpiSerialClk_100MHz = 5, + kFlexSpiSerialClk_100MHz = 5, kFlexSpiSerialClk_120MHz = 6, kFlexSpiSerialClk_133MHz = 7, kFlexSpiSerialClk_166MHz = 8, kFlexSpiSerialClk_200MHz = 9, } flexspi_serial_clk_freq_t; +#endif //!@brief FlexSPI clock configuration type enum { diff --git a/platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/imxrt_romapi.h b/platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/imxrt_romapi.h index f51775e2bd..fa944e0c1b 100644 --- a/platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/imxrt_romapi.h +++ b/platforms/nuttx/src/px4/nxp/imxrt/include/px4_arch/imxrt_romapi.h @@ -239,7 +239,9 @@ status_t ROM_FLEXSPI_NorFlash_Erase(uint32_t instance, flexspi_nor_config_t *con * @retval kStatus_ROM_FLEXSPI_SequenceExecutionTimeout Sequence Execution timeout. * @retval kStatus_ROM_FLEXSPI_DeviceTimeout the device timeout */ +#ifdef CONFIG_ARCH_FAMILY_IMXRT117x status_t ROM_FLEXSPI_NorFlash_EraseSector(uint32_t instance, flexspi_nor_config_t *config, uint32_t start); +#endif /*! * @brief Erase one block specified by address @@ -259,7 +261,9 @@ status_t ROM_FLEXSPI_NorFlash_EraseSector(uint32_t instance, flexspi_nor_config_ * @retval kStatus_ROM_FLEXSPI_SequenceExecutionTimeout Sequence Execution timeout. * @retval kStatus_ROM_FLEXSPI_DeviceTimeout the device timeout */ +#ifdef CONFIG_ARCH_FAMILY_IMXRT117x status_t ROM_FLEXSPI_NorFlash_EraseBlock(uint32_t instance, flexspi_nor_config_t *config, uint32_t start); +#endif /*! * @brief Erase all the Serial NOR devices connected on FLEXSPI. @@ -342,10 +346,12 @@ status_t ROM_FLEXSPI_NorFlash_UpdateLut(uint32_t instance, * @retval kStatus_ROM_FLEXSPI_InvalidSequence A invalid Sequence is provided. * @retval kStatus_ROM_FLEXSPI_DeviceTimeout Device timeout. */ +#ifdef CONFIG_ARCH_FAMILY_IMXRT117x status_t ROM_FLEXSPI_NorFlash_WaitBusy(uint32_t instance, flexspi_nor_config_t *config, bool isParallelMode, uint32_t address); +#endif /*@}*/ /*! diff --git a/platforms/nuttx/src/px4/nxp/imxrt/romapi/imxrt_romapi.c b/platforms/nuttx/src/px4/nxp/imxrt/romapi/imxrt_romapi.c index 68443e3353..1d63860965 100644 --- a/platforms/nuttx/src/px4/nxp/imxrt/romapi/imxrt_romapi.c +++ b/platforms/nuttx/src/px4/nxp/imxrt/romapi/imxrt_romapi.c @@ -52,8 +52,29 @@ typedef union _standard_version { #endif } standard_version_t; + +#ifdef CONFIG_ARCH_FAMILY_IMXRT106x + /*! - * @brief Interface for the ROM FLEXSPI NOR flash driver. + * @brief Interface for the IMXRT106X ROM FLEXSPI NOR flash driver. + */ +typedef struct { + uint32_t version; + status_t (*init)(uint32_t instance, flexspi_nor_config_t *config); + status_t (*page_program)(uint32_t instance, flexspi_nor_config_t *config, uint32_t dst_addr, const uint32_t *src); + status_t (*erase_all)(uint32_t instance, flexspi_nor_config_t *config); + status_t (*erase)(uint32_t instance, flexspi_nor_config_t *config, uint32_t start, uint32_t length); + status_t (*read)(uint32_t instance, flexspi_nor_config_t *config, uint32_t *dst, uint32_t start, uint32_t bytes); + void (*clear_cache)(uint32_t instance); + status_t (*xfer)(uint32_t instance, flexspi_xfer_t *xfer); + status_t (*update_lut)(uint32_t instance, uint32_t seqIndex, const uint32_t *lutBase, uint32_t numberOfSeq); + status_t (*get_config)(uint32_t instance, flexspi_nor_config_t *config, serial_nor_config_option_t *option); +} flexspi_nor_driver_interface_t; + +#elif defined(CONFIG_ARCH_FAMILY_IMXRT117x) + +/*! + * @brief Interface for the IMXRT117X ROM FLEXSPI NOR flash driver. */ typedef struct { uint32_t version; @@ -73,6 +94,33 @@ typedef struct { const uint32_t reserved1[2]; /*!< Reserved */ } flexspi_nor_driver_interface_t; +#endif + + +#ifdef CONFIG_ARCH_FAMILY_IMXRT106x + +/*! +* @brief Root of the bootloader api tree. +* +* An instance of this struct resides in read-only memory in the bootloader. It +* provides a user application access to APIs exported by the bootloader. +* +* @note The order of existing fields must not be changed. +*/ +typedef struct { + const uint32_t version; //!< Bootloader version number + const char *copyright; //!< Bootloader Copyright + void (*runBootloader)(void *arg); //!< Function to start the bootloader executing + const uint32_t *reserved0; //!< Reserved + const flexspi_nor_driver_interface_t *flexSpiNorDriver; //!< FlexSPI NOR Flash API + const uint32_t *reserved1; //!< Reserved + const uint32_t *unused_rtwdogDriver; + const uint32_t *unused_wdogDriver; + const uint32_t *reserved2; +} bootloader_api_entry_t; + +#elif defined(CONFIG_ARCH_FAMILY_IMXRT117x) + /*! * @brief Root of the bootloader api tree. * @@ -89,6 +137,8 @@ typedef struct { const uint32_t reserved[8]; /*!< Reserved */ } bootloader_api_entry_t; +#endif + /******************************************************************************* * Variables ******************************************************************************/ @@ -104,6 +154,9 @@ static bootloader_api_entry_t *g_bootloaderTree = NULL; locate_code(".ramfunc") void ROM_API_Init(void) { +#ifdef CONFIG_ARCH_FAMILY_IMXRT106x + g_bootloaderTree = ((bootloader_api_entry_t *) * (uint32_t *)0x0020001cU); +#else if ((getreg32(IMXRT_ANADIG_MISC_MISC_DIFPROG) & ANADIG_MISC_MISC_DIFPROG_CHIPID(0x10U)) != 0U) { g_bootloaderTree = ((bootloader_api_entry_t *) * (uint32_t *)0x0021001cU); @@ -111,6 +164,8 @@ void ROM_API_Init(void) } else { g_bootloaderTree = ((bootloader_api_entry_t *) * (uint32_t *)0x0020001cU); } + +#endif } /*! @@ -193,6 +248,8 @@ status_t ROM_FLEXSPI_NorFlash_Erase(uint32_t instance, flexspi_nor_config_t *con return g_bootloaderTree->flexSpiNorDriver->erase(instance, config, start, length); } +#ifdef CONFIG_ARCH_FAMILY_IMXRT117x + /*! * @brief Erase one sector specified by address. * @@ -219,6 +276,8 @@ status_t ROM_FLEXSPI_NorFlash_EraseBlock(uint32_t instance, flexspi_nor_config_t return g_bootloaderTree->flexSpiNorDriver->erase_block(instance, config, start); } +#endif + /*! @brief Erase all the Serial NOR devices connected on FLEXSPI. */ locate_code(".ramfunc") status_t ROM_FLEXSPI_NorFlash_EraseAll(uint32_t instance, flexspi_nor_config_t *config) @@ -242,6 +301,19 @@ status_t ROM_FLEXSPI_NorFlash_UpdateLut(uint32_t instance, return g_bootloaderTree->flexSpiNorDriver->update_lut(instance, seqIndex, lutBase, seqNumber); } + +#ifdef CONFIG_ARCH_FAMILY_IMXRT106x + +/*! @brief Software reset for the FLEXSPI logic. */ +locate_code(".ramfunc") +void ROM_FLEXSPI_NorFlash_ClearCache(uint32_t instance) +{ + g_bootloaderTree->flexSpiNorDriver->clear_cache(instance); +} + + +#elif defined(CONFIG_ARCH_FAMILY_IMXRT117x) + /*! @brief Software reset for the FLEXSPI logic. */ locate_code(".ramfunc") void ROM_FLEXSPI_NorFlash_ClearCache(uint32_t instance) @@ -259,6 +331,9 @@ void ROM_FLEXSPI_NorFlash_ClearCache(uint32_t instance) MISRA_CAST(clearCacheCommand_t, clearCacheCommand, uint32_t, clearCacheFunctionAddress); (void)clearCacheCommand(instance); } +#endif + +#ifdef CONFIG_ARCH_FAMILY_IMXRT117x /*! @brief Wait until device is idle*/ locate_code(".ramfunc") @@ -269,3 +344,5 @@ status_t ROM_FLEXSPI_NorFlash_WaitBusy(uint32_t instance, { return g_bootloaderTree->flexSpiNorDriver->wait_busy(instance, config, isParallelMode, address); } + +#endif diff --git a/platforms/nuttx/src/px4/nxp/imxrt/version/board_mcu_version.c b/platforms/nuttx/src/px4/nxp/imxrt/version/board_mcu_version.c index ae8594bd4f..94c75844d8 100644 --- a/platforms/nuttx/src/px4/nxp/imxrt/version/board_mcu_version.c +++ b/platforms/nuttx/src/px4/nxp/imxrt/version/board_mcu_version.c @@ -90,7 +90,7 @@ int board_mcu_version(char *rev, const char **revstr, const char **errata) #define DIGPROG_MAJOR_UPPER_MASK (0xff << DIGPROG_MAJOR_UPPER_SHIFT) #define DIGPROG_MAJOR_UPPER(info) (((info) & DIGPROG_MAJOR_UPPER_MASK) >> DIGPROG_MAJOR_UPPER_SHIFT) // 876543210 -#define CHIP_TAG "i.MX RT10?2 r?.?" +#define CHIP_TAG "i.MX RT10?? r?.?" #define CHIP_TAG_LEN sizeof(CHIP_TAG)-1 int board_mcu_version(char *rev, const char **revstr, const char **errata) @@ -100,6 +100,7 @@ int board_mcu_version(char *rev, const char **revstr, const char **errata) chip[CHIP_TAG_LEN - 1] = '0' + DIGPROG_MINOR(info); chip[CHIP_TAG_LEN - 3] = '1' + DIGPROG_MAJOR_LOWER(info); + chip[CHIP_TAG_LEN - 6] = getreg32(0x401F867C) == 0x10 ? '4' : '2'; chip[CHIP_TAG_LEN - 7] = DIGPROG_MAJOR_UPPER(info) == 0x6a ? '5' : '6'; *revstr = chip; *rev = '0' + DIGPROG_MINOR(info); diff --git a/platforms/nuttx/src/px4/nxp/rt106x/CMakeLists.txt b/platforms/nuttx/src/px4/nxp/rt106x/CMakeLists.txt index f487b031c7..57bd94ee6e 100644 --- a/platforms/nuttx/src/px4/nxp/rt106x/CMakeLists.txt +++ b/platforms/nuttx/src/px4/nxp/rt106x/CMakeLists.txt @@ -36,11 +36,13 @@ add_subdirectory(../imxrt/adc 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/romapi romapi) add_subdirectory(../imxrt/dshot dshot) add_subdirectory(../imxrt/hrt hrt) add_subdirectory(../imxrt/led_pwm led_pwm) add_subdirectory(../imxrt/io_pins io_pins) add_subdirectory(../imxrt/tone_alarm tone_alarm) add_subdirectory(../imxrt/version version) +add_subdirectory(../imxrt/spi spi) add_subdirectory(px4io_serial) diff --git a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/hw_description.h b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/hw_description.h index d4aada2ffe..27da505127 100644 --- a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/hw_description.h +++ b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/hw_description.h @@ -41,8 +41,8 @@ #include #include -#ifndef CONFIG_ARCH_CHIP_MIMXRT1062DVL6A -# error "This code has only been validated with IMXRT1062. Make sure it is correct before using it on another board." +#if !defined(CONFIG_ARCH_CHIP_MIMXRT1062DVL6A) && !defined(CONFIG_ARCH_CHIP_MIMXRT1064DVL6A) +# error "This code has only been validated with IMXRT1062 and IMXRT1064. Make sure it is correct before using it on another board." #endif /* diff --git a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/imxrt_flexspi_nor_flash.h b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/imxrt_flexspi_nor_flash.h new file mode 100644 index 0000000000..3925012e86 --- /dev/null +++ b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/imxrt_flexspi_nor_flash.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * + * Copyright (c) 2024 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/imxrt_flexspi_nor_flash.h" diff --git a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/imxrt_romapi.h b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/imxrt_romapi.h new file mode 100644 index 0000000000..aeab841162 --- /dev/null +++ b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/imxrt_romapi.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * + * Copyright (c) 2024 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/imxrt_romapi.h" diff --git a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/io_timer_hw_description.h b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/io_timer_hw_description.h index 5cbc33fdc3..a5ec76ea25 100644 --- a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/io_timer_hw_description.h +++ b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/io_timer_hw_description.h @@ -47,8 +47,8 @@ #include #include -#ifndef CONFIG_ARCH_CHIP_MIMXRT1062DVL6A -# error "This code has only been validated with IMXRT1062. Make sure it is correct before using it on another board." +#if !defined(CONFIG_ARCH_CHIP_MIMXRT1062DVL6A) && !defined(CONFIG_ARCH_CHIP_MIMXRT1064DVL6A) +# error "This code has only been validated with IMXRT1062 and IMXRT1064. Make sure it is correct before using it on another board." #endif diff --git a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/spi_hw_description.h b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/spi_hw_description.h index de0c30247d..0e1a46b8e3 100644 --- a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/spi_hw_description.h +++ b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/spi_hw_description.h @@ -46,6 +46,58 @@ #define GENERAL_OUTPUT_IOMUX (IOMUX_CMOS_OUTPUT | IOMUX_PULL_KEEP | IOMUX_DRIVE_33OHM | IOMUX_SPEED_MEDIUM | IOMUX_SLEW_FAST) +constexpr bool validateSPIConfig(const px4_spi_bus_t spi_busses_conf[SPI_BUS_MAX_BUS_ITEMS]) +{ + const bool nuttx_enabled_spi_buses[] = { +#ifdef CONFIG_IMXRT_LPSPI1 + true, +#else + false, +#endif +#ifdef CONFIG_IMXRT_LPSPI2 + true, +#else + false, +#endif +#ifdef CONFIG_IMXRT_LPSPI3 + true, +#else + false, +#endif +#ifdef CONFIG_IMXRT_LPSPI4 + true, +#else + false, +#endif +#ifdef CONFIG_IMXRT_LPSPI5 + true, +#else + false, +#endif +#ifdef CONFIG_IMXRT_LPSPI6 + true, +#else + false, +#endif + }; + + for (unsigned i = 0; i < sizeof(nuttx_enabled_spi_buses) / sizeof(nuttx_enabled_spi_buses[0]); ++i) { + bool found_bus = false; + + for (int j = 0; j < SPI_BUS_MAX_BUS_ITEMS; ++j) { + if (spi_busses_conf[j].bus == (int)i + 1) { + found_bus = true; + } + } + + // Either the bus is enabled in NuttX and configured in spi_busses_conf, or disabled and not configured + constexpr_assert(found_bus == nuttx_enabled_spi_buses[i], "SPI bus config mismatch (CONFIG_STM32H7_SPIx)"); + } + + return false; +} + + 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{}; @@ -138,8 +190,57 @@ static inline constexpr SPI::bus_device_external_cfg_t initSPIConfigExternal(SPI return ret; } -constexpr bool validateSPIConfig(const px4_spi_bus_t spi_busses_conf[SPI_BUS_MAX_BUS_ITEMS]) + +struct px4_spi_bus_array_t { + px4_spi_bus_t item[SPI_BUS_MAX_BUS_ITEMS]; +}; +#if defined(BOARD_HAS_HW_SPLIT_VERSIONING) +static inline constexpr px4_spi_bus_all_hw_t initSPIFmumID(hw_fmun_id_t hw_fmun_id, + const px4_spi_bus_array_t &bus_items) { - return true; + px4_spi_bus_all_hw_t ret{}; + + for (int i = 0; i < SPI_BUS_MAX_BUS_ITEMS; ++i) { + ret.buses[i] = bus_items.item[i]; + } + + ret.board_hw_fmun_id = hw_fmun_id; + return ret; } +#else +static inline constexpr px4_spi_bus_all_hw_t initSPIHWVersion(int hw_version_revision, + const px4_spi_bus_array_t &bus_items) +{ + px4_spi_bus_all_hw_t ret{}; + + for (int i = 0; i < SPI_BUS_MAX_BUS_ITEMS; ++i) { + ret.buses[i] = bus_items.item[i]; + } + + ret.board_hw_version_revision = hw_version_revision; + return ret; +} +#endif +constexpr bool validateSPIConfig(const px4_spi_bus_t spi_buses_conf[SPI_BUS_MAX_BUS_ITEMS]); + +constexpr bool validateSPIConfig(const px4_spi_bus_all_hw_t spi_buses_conf[BOARD_NUM_SPI_CFG_HW_VERSIONS]) +{ + for (int ver = 0; ver < BOARD_NUM_SPI_CFG_HW_VERSIONS; ++ver) { + validateSPIConfig(spi_buses_conf[ver].buses); + } + + for (int ver = 1; ver < BOARD_NUM_SPI_CFG_HW_VERSIONS; ++ver) { + for (int i = 0; i < SPI_BUS_MAX_BUS_ITEMS; ++i) { + const bool equal_power_enable_gpio = spi_buses_conf[ver].buses[i].power_enable_gpio == spi_buses_conf[ver - + 1].buses[i].power_enable_gpio; + // currently board_control_spi_sensors_power_configgpio() depends on that - this restriction can be removed + // by ensuring board_control_spi_sensors_power_configgpio() is called after the hw version is determined + // and SPI config is initialized. + constexpr_assert(equal_power_enable_gpio, "All HW versions must define the same power enable GPIO"); + } + } + + return false; +} + #endif // CONFIG_SPI From cbbdc20bd3d30cf77a97490b3fe4a14f8831a305 Mon Sep 17 00:00:00 2001 From: Beniamino Pozzan Date: Mon, 3 Nov 2025 22:25:03 +0000 Subject: [PATCH 020/139] docs(uxrce_dds): add missing closure for info section Signed-off-by: Beniamino Pozzan --- docs/en/middleware/uxrce_dds.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/middleware/uxrce_dds.md b/docs/en/middleware/uxrce_dds.md index 8f8da255d3..e931cda1a9 100644 --- a/docs/en/middleware/uxrce_dds.md +++ b/docs/en/middleware/uxrce_dds.md @@ -441,6 +441,7 @@ uxrce_dds_client start -n fancy_uav ``` This can be included in `etc/extras.txt` as part of a custom [System Startup](../concept/system_startup.md). +::: ## PX4 ROS 2 QoS Settings From 311b3cfb677bad7d28643c08c53ebba22eae8194 Mon Sep 17 00:00:00 2001 From: Hubert <1701213518@sz.pku.edu.cn> Date: Thu, 6 Nov 2025 07:05:42 +0800 Subject: [PATCH 021/139] docs: add micoair743-lite documentation. (#25870) * add docs for MicoAir743-Lite * Update images and prettier * update micoair743-lite.md * Update docs/en/flight_controller/micoair743-lite.md * Prettier and cross link RC + add badges * Update docs/en/flight_controller/micoair743-lite.md --------- Co-authored-by: Minderring <1701213518@sz.edu.pku.cn> Co-authored-by: Farhang <46557204+farhangnaderi@users.noreply.github.com> Co-authored-by: Hamish Willee --- .../micoair743_lite/back_view.png | Bin 0 -> 63849 bytes .../micoair743_lite/front_view.png | Bin 0 -> 78387 bytes .../micoair743_lite/interfaces_diagram.png | Bin 0 -> 517207 bytes .../micoair743_lite_pinout.xlsx | Bin 0 -> 14523 bytes .../micoair743_lite/size.png | Bin 0 -> 130706 bytes .../micoair743_lite/wiring_diagram.png | Bin 0 -> 368632 bytes docs/en/SUMMARY.md | 1 + .../autopilot_manufacturer_supported.md | 1 + docs/en/flight_controller/micoair743-lite.md | 152 ++++++++++++++++++ 9 files changed, 154 insertions(+) create mode 100644 docs/assets/flight_controller/micoair743_lite/back_view.png create mode 100644 docs/assets/flight_controller/micoair743_lite/front_view.png create mode 100644 docs/assets/flight_controller/micoair743_lite/interfaces_diagram.png create mode 100644 docs/assets/flight_controller/micoair743_lite/micoair743_lite_pinout.xlsx create mode 100644 docs/assets/flight_controller/micoair743_lite/size.png create mode 100644 docs/assets/flight_controller/micoair743_lite/wiring_diagram.png create mode 100644 docs/en/flight_controller/micoair743-lite.md diff --git a/docs/assets/flight_controller/micoair743_lite/back_view.png b/docs/assets/flight_controller/micoair743_lite/back_view.png new file mode 100644 index 0000000000000000000000000000000000000000..eee32821146b5f8ef3ff8b9882966dfbe129a6c5 GIT binary patch literal 63849 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