diff --git a/.vscode/cmake-variants.yaml b/.vscode/cmake-variants.yaml index f41c0af8cb..c43792847b 100644 --- a/.vscode/cmake-variants.yaml +++ b/.vscode/cmake-variants.yaml @@ -351,6 +351,16 @@ CONFIG: buildType: MinSizeRel settings: CONFIG: cubepilot_cubeorangeplus_test + cubepilot_cubered-primary_default: + short: cubepilot_cubered-primary + buildType: MinSizeRel + settings: + CONFIG: cubepilot_cubered-primary_default + cubepilot_cubered-secondary_default: + short: cubepilot_cubered-secondary + buildType: MinSizeRel + settings: + CONFIG: cubepilot_cubered-primary_default emlid_navio2_default: short: emlid_navio2 buildType: MinSizeRel diff --git a/boards/cubepilot/cubered-primary/README.md b/boards/cubepilot/cubered-primary/README.md new file mode 100644 index 0000000000..72fee04205 --- /dev/null +++ b/boards/cubepilot/cubered-primary/README.md @@ -0,0 +1,41 @@ +# PX4 on CubePilot CubeRed + +CubePilot CubeRed is a dual-MCU autopilot built around two STM32H743 MCUs: + +- **Primary** (`cubepilot_cubered-primary`) runs the main PX4 flight stack + and the `cubered_bridge_primary` driver + (`src/drivers/cubered_bridge/primary`). +- **Secondary** (`cubepilot_cubered-secondary`) runs the + `cubered_bridge_secondary` driver + (`src/drivers/cubered_bridge/secondary`), which speaks the PX4IO register + protocol so the primary can drive PWM/RC over the UART7 link between the + two MCUs. + +References: +- [Hardware overview](https://docs.cubepilot.org/user-guides/autopilot/cube-red) +- [Carrier board pinout](https://docs.cubepilot.org/user-guides/carrier-boards/cube-red-standard-carrier-board-pinout) + +## Bootloader + +PX4 currently uses the **ArduPilot bootloader** on this board. A native PX4 +bootloader is not yet available, so the upload protocol is driven through +ArduPilot's bootloader and the secondary is exposed as the second device of +the primary's composite USB bootloader. + +## Building and flashing + +Both MCUs need to be flashed. Build and upload the secondary first, then +the primary: + +```sh +make cubepilot_cubered-secondary_default upload && \ +make cubepilot_cubered-primary_default upload +``` + +A manual power cycle is currently required between the secondary upload +finishing and the secondary rebooting into application mode. + +## Console + +- Primary console is on the carrier's GPS2 connector (UART4) at 57600 baud. +- Secondary console is on the carrier's CONS connector (UART8) at 57600 baud. diff --git a/boards/cubepilot/cubered-primary/default.px4board b/boards/cubepilot/cubered-primary/default.px4board new file mode 100644 index 0000000000..b6ea6b5a57 --- /dev/null +++ b/boards/cubepilot/cubered-primary/default.px4board @@ -0,0 +1,100 @@ +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/ttyS0" +CONFIG_BOARD_SERIAL_TEL2="/dev/ttyS3" +CONFIG_BOARD_EXTERNAL_FLASH=y + +CONFIG_DRIVERS_ADC_ADS1115=y +CONFIG_DRIVERS_ADC_BOARD_ADC=y +CONFIG_DRIVERS_BAROMETER_MS5611=y +CONFIG_DRIVERS_BATT_SMBUS=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_DSHOT=y +#CONFIG_DRIVERS_GNSS_SEPTENTRIO=y +CONFIG_DRIVERS_GPS=y +CONFIG_DRIVERS_IMU_ANALOG_DEVICES_ADIS16448=y +CONFIG_DRIVERS_IMU_INVENSENSE_ICM20649=y +CONFIG_DRIVERS_IMU_INVENSENSE_ICM20948=y +CONFIG_DRIVERS_IMU_INVENSENSE_ICM42688P=y +CONFIG_DRIVERS_IMU_INVENSENSE_ICM45686=y +CONFIG_COMMON_INS=y +CONFIG_DRIVERS_IRLOCK=y +CONFIG_COMMON_LIGHT=y +CONFIG_COMMON_MAGNETOMETER=y +CONFIG_COMMON_OPTICAL_FLOW=y +#CONFIG_DRIVERS_PCA9685_PWM_OUT=y +#CONFIG_DRIVERS_POWER_MONITOR_INA226=y +CONFIG_DRIVERS_PWM_INPUT=y +CONFIG_DRIVERS_PWM_OUT=y +#CONFIG_DRIVERS_SMART_BATTERY_BATMON=y +CONFIG_COMMON_TELEMETRY=y +CONFIG_DRIVERS_TONE_ALARM=y +CONFIG_DRIVERS_TRANSPONDER_SAGETECH_MXS=y +CONFIG_DRIVERS_UAVCAN=y +CONFIG_BOARD_UAVCAN_TIMER_OVERRIDE=4 +CONFIG_DRIVERS_CUBERED_BRIDGE_PRIMARY=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_LAND_DETECTOR=y +CONFIG_MODULES_LANDING_TARGET_ESTIMATOR=y +CONFIG_MODULES_LOAD_MON=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_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_GPIO=y +CONFIG_SYSTEMCMDS_HARDFAULT_LOG=y +CONFIG_SYSTEMCMDS_I2CDETECT=y +CONFIG_SYSTEMCMDS_LED_CONTROL=y +CONFIG_SYSTEMCMDS_MFT=y +CONFIG_SYSTEMCMDS_MTD=y +CONFIG_SYSTEMCMDS_NETMAN=y +CONFIG_SYSTEMCMDS_NSHTERM=y +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_TUNE_CONTROL=y +CONFIG_SYSTEMCMDS_UORB=y +CONFIG_SYSTEMCMDS_USB_CONNECTED=y +CONFIG_SYSTEMCMDS_VER=y +CONFIG_SYSTEMCMDS_WORK_QUEUE=y +CONFIG_SYSTEMCMDS_MICROBENCH=y +CONFIG_SYSTEMCMDS_SD_STRESS=y diff --git a/boards/cubepilot/cubered-primary/extras/net_config.bin b/boards/cubepilot/cubered-primary/extras/net_config.bin new file mode 100644 index 0000000000..e2a32c1c38 Binary files /dev/null and b/boards/cubepilot/cubered-primary/extras/net_config.bin differ diff --git a/boards/cubepilot/cubered-primary/firmware.prototype b/boards/cubepilot/cubered-primary/firmware.prototype new file mode 100644 index 0000000000..d9d34e82e1 --- /dev/null +++ b/boards/cubepilot/cubered-primary/firmware.prototype @@ -0,0 +1,13 @@ +{ + "board_id": 1069, + "magic": "PX4FWv1", + "description": "Firmware for the CubePilot CubeRed Primary board", + "image": "", + "build_time": 0, + "summary": "CubeRed-Primary", + "version": "0.1", + "image_size": 0, + "image_maxsize": 1966080, + "git_identity": "", + "board_revision": 0 +} diff --git a/boards/cubepilot/cubered-primary/init/rc.board_defaults b/boards/cubepilot/cubered-primary/init/rc.board_defaults new file mode 100644 index 0000000000..64b8bbba97 --- /dev/null +++ b/boards/cubepilot/cubered-primary/init/rc.board_defaults @@ -0,0 +1,17 @@ +#!/bin/sh +# +# board specific defaults +#------------------------------------------------------------------------------ + +param set-default BAT1_V_DIV 10.1 +param set-default BAT2_V_DIV 10.1 + +param set-default BAT1_A_PER_V 17 +param set-default BAT2_A_PER_V 17 + +# Disable IMU thermal control +param set-default SENS_EN_THERMAL 0 + +param set-default -s SENS_TEMP_ID 2621474 + +#set IOFW "/etc/extras/cubepilot_io-v2_default.bin" diff --git a/boards/cubepilot/cubered-primary/init/rc.board_mavlink b/boards/cubepilot/cubered-primary/init/rc.board_mavlink new file mode 100644 index 0000000000..13f47935d9 --- /dev/null +++ b/boards/cubepilot/cubered-primary/init/rc.board_mavlink @@ -0,0 +1,2 @@ +#!/bin/sh + diff --git a/boards/cubepilot/cubered-primary/init/rc.board_sensors b/boards/cubepilot/cubered-primary/init/rc.board_sensors new file mode 100644 index 0000000000..08b8bab853 --- /dev/null +++ b/boards/cubepilot/cubered-primary/init/rc.board_sensors @@ -0,0 +1,34 @@ +#!/bin/sh +# +# Board specific sensors init +#------------------------------------------------------------------------------ +# TODO: start all three instances +board_adc start + + +# SPI1, SPI2 isolated +# SPI4 fixed + +# SPI1 +ms5611 -s -b 1 start -c 13 +if ! icm42688p -s -b 1 -q -R 2 -c 9 start +then + icm45686 -s -b 1 -R 2 -c 9 start +fi + +# SPI2 +rm3100 -s -b 2 -R 6 start -c 15 +if ! icm42688p -s -b 2 -q -R 10 -c 14 start +then + icm45686 -s -b 2 -R 10 -c 14 start +fi + +# SPI4 +if ! icm20649 -s -b 4 -q -R 10 -c 5 start +then + icm45686 -s -b 4 -R 12 -c 5 start +fi +ms5611 -s -b 4 start -c 2 + +# Start the bridge driver that talks to the CubeRed Secondary over UART7. +cubered_bridge_primary start diff --git a/boards/cubepilot/cubered-primary/nuttx-config/include/board.h b/boards/cubepilot/cubered-primary/nuttx-config/include/board.h new file mode 100644 index 0000000000..02d07dfbcd --- /dev/null +++ b/boards/cubepilot/cubered-primary/nuttx-config/include/board.h @@ -0,0 +1,290 @@ +/************************************************************************************ + * nuttx-config/include/board.h + * + * Copyright (C) 2020 Gregory Nutt. All rights reserved. + * Authors: 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. + * + ************************************************************************************/ +#pragma once + +#include "board_dma_map.h" + +#include + +#ifndef __ASSEMBLY__ +# include +#endif + +#include "stm32_rcc.h" +#include "stm32_sdmmc.h" + +/* Clocking *************************************************************************/ +/* The board provides the following clock sources: + * + * X1: 24 MHz crystal for HSE + * + * So we have these clock source available within the STM32 + * + * HSI: 16 MHz RC factory-trimmed internal oscillator + * HSE: 24 MHz crystal for HSE + */ +#define STM32_BOARD_XTAL 24000000ul + +#define STM32_HSI_FREQUENCY 16000000ul +#define STM32_LSI_FREQUENCY 32000 +#define STM32_HSE_FREQUENCY STM32_BOARD_XTAL + +/* Main PLL Configuration. + * + * PLL source is HSE = 24,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 + */ + +/* PLL1, wide 4 - 8 MHz input, enable DIVP, DIVQ, DIVR + * + * PLL1_VCO = (24,000,000 / 3) * 100 = 800 MHz + * + * PLL1P = PLL1_VCO/2 = 800 MHz / 2 = 400 MHz + * PLL1Q = PLL1_VCO/8 = 800 MHz / 8 = 100 MHz + * PLL1R = PLL1_VCO/2 = 800 MHz / 2 = 400 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(3) +#define STM32_PLLCFG_PLL1N RCC_PLL1DIVR_N1(100) +#define STM32_PLLCFG_PLL1P RCC_PLL1DIVR_P1(2) +#define STM32_PLLCFG_PLL1Q RCC_PLL1DIVR_Q1(10) +#define STM32_PLLCFG_PLL1R RCC_PLL1DIVR_R1(2) + +#define STM32_VCO1_FREQUENCY ((STM32_HSE_FREQUENCY / 3) * 100) +#define STM32_PLL1P_FREQUENCY (STM32_VCO1_FREQUENCY / 2) +#define STM32_PLL1Q_FREQUENCY (STM32_VCO1_FREQUENCY / 10) +#define STM32_PLL1R_FREQUENCY (STM32_VCO1_FREQUENCY / 2) + +/* PLL2 */ +#define STM32_PLLCFG_PLL2CFG (RCC_PLLCFGR_PLL2VCOSEL_WIDE|RCC_PLLCFGR_PLL2RGE_8_16_MHZ|RCC_PLLCFGR_DIVP2EN|RCC_PLLCFGR_DIVQ2EN|RCC_PLLCFGR_DIVR2EN) +#define STM32_PLLCFG_PLL2M RCC_PLLCKSELR_DIVM2(2) +#define STM32_PLLCFG_PLL2N RCC_PLL2DIVR_N2(50) +#define STM32_PLLCFG_PLL2P RCC_PLL2DIVR_P2(3) +#define STM32_PLLCFG_PLL2Q RCC_PLL2DIVR_Q2(6) +#define STM32_PLLCFG_PLL2R RCC_PLL2DIVR_R2(3) + +#define STM32_VCO2_FREQUENCY ((STM32_HSE_FREQUENCY / 2) * 50) +#define STM32_PLL2P_FREQUENCY (STM32_VCO2_FREQUENCY / 3) +#define STM32_PLL2Q_FREQUENCY (STM32_VCO2_FREQUENCY / 6) +#define STM32_PLL2R_FREQUENCY (STM32_VCO2_FREQUENCY / 3) + +/* 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(6) +#define STM32_PLLCFG_PLL3N RCC_PLL3DIVR_N3(72) +#define STM32_PLLCFG_PLL3P RCC_PLL3DIVR_P3(3) +#define STM32_PLLCFG_PLL3Q RCC_PLL3DIVR_Q3(6) +#define STM32_PLLCFG_PLL3R RCC_PLL3DIVR_R3(9) + +#define STM32_VCO3_FREQUENCY ((STM32_HSE_FREQUENCY / 6) * 72) +#define STM32_PLL3P_FREQUENCY (STM32_VCO3_FREQUENCY / 3) +#define STM32_PLL3Q_FREQUENCY (STM32_VCO3_FREQUENCY / 6) +#define STM32_PLL3R_FREQUENCY (STM32_VCO3_FREQUENCY / 9) + +/* SYSCLK = PLL1P = 400MHz + * CPUCLK = SYSCLK / 1 = 400 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 = 200 + */ +#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/4 (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 + */ +#define STM32_RCC_D1CCIPR_SDMMCSEL RCC_D1CCIPR_SDMMC_PLL1 + +#define STM32_RCC_D2CCIP2R_I2C123SRC RCC_D2CCIP2R_I2C123SEL_HSI /* I2C123 clock source */ +#define STM32_RCC_D3CCIPR_I2C4SRC RCC_D3CCIPR_I2C4SEL_HSI +#define STM32_RCC_D2CCIP1R_SPI123SRC RCC_D2CCIP1R_SPI123SEL_PLL2 /* SPI123 clock source */ +#define STM32_RCC_D2CCIP1R_SPI45SRC RCC_D2CCIP1R_SPI45SEL_PLL2 /* SPI45 clock source */ +#define STM32_RCC_D2CCIP2R_USBSRC RCC_D2CCIP2R_USBSEL_PLL3 /* USB 1 and 2 clock source */ +#define STM32_RCC_D2CCIP1R_FDCANSEL RCC_D2CCIP1R_FDCANSEL_HSE /* FDCAN 1 2 clock source */ + +#define STM32_RCC_D3CCIPR_ADCSRC RCC_D3CCIPR_ADCSEL_PLL2 /* ADC 1 2 3 clock source */ + +/* UART clock selection */ +/* reset to default to overwrite any changes done by any bootloader */ + +#define STM32_RCC_D2CCIP2R_USART234578_SEL RCC_D2CCIP2R_USART234578SEL_RCC +#define STM32_RCC_D2CCIP2R_USART16_SEL RCC_D2CCIP2R_USART16SEL_RCC + + +/* FLASH wait states */ +#define BOARD_FLASH_WAITSTATES 2 + +/* SDMMC definitions ********************************************************/ +/* Init 400kHz, freq = PLL1Q/(2*div) div = PLL1Q/(2*freq) */ +#define STM32_SDMMC_INIT_CLKDIV (125 << STM32_SDMMC_CLKCR_CLKDIV_SHIFT) + +/* 25 MHz Max for now, 25 mHZ = PLL1Q/(2*div), div = PLL1Q/(2*freq) + * div = 100 / (2*25) + */ +#define STM32_SDMMC_MMCXFR_CLKDIV (2 << STM32_SDMMC_CLKCR_CLKDIV_SHIFT) +#define STM32_SDMMC_SDXFR_CLKDIV (2 << STM32_SDMMC_CLKCR_CLKDIV_SHIFT) + +#define STM32_SDMMC_CLKCR_EDGE STM32_SDMMC_CLKCR_NEGEDGE + + +/* Ethernet phy */ +#define GPIO_ETH_RMII_TX_EN GPIO_ETH_RMII_TX_EN_1 /* PB11 */ +#define GPIO_ETH_RMII_TXD0 GPIO_ETH_RMII_TXD0_1 /* PB12 */ +#define GPIO_ETH_RMII_TXD1 GPIO_ETH_RMII_TXD1_1 /* PB13 */ +//#define GPIO_ETH_RMII_RXD0 GPIO_ETH_RMII_RXD0 /* PC4 */ +//#define GPIO_ETH_RMII_RXD1 GPIO_ETH_RMII_RXD1 /* PC5 */ + +/* UART/USART */ + +// USART2 -> /dev/ttyS0 -> Telem1 +// USART3 -> /dev/ttyS1 -> GPS1 +// UART4 -> /dev/ttyS2 -> GPS2 +// USART6 -> /dev/ttyS3 -> Telem2 +// UART7 -> /dev/ttyS4 -> to Secondary (but swapped because not crossed over in hardware) +// UART8 -> /dev/ttyS5 -> console + +#define GPIO_USART2_TX GPIO_USART2_TX_2 /* PD5 */ +#define GPIO_USART2_RX GPIO_USART2_RX_2 /* PD6 */ +#define GPIO_USART2_CTS GPIO_USART2_CTS_NSS_2 /* PD3 */ +#define GPIO_USART2_RTS GPIO_USART2_RTS_2 /* PD4 */ + +#define GPIO_USART3_TX GPIO_USART3_TX_3 /* PD8 */ +#define GPIO_USART3_RX GPIO_USART3_RX_3 /* PD9 */ + +#define GPIO_UART4_TX GPIO_UART4_TX_5 /* PD1 */ +#define GPIO_UART4_RX GPIO_UART4_RX_5 /* PD0 */ + +#define GPIO_USART6_TX GPIO_USART6_TX_1 /* PC6 */ +#define GPIO_USART6_RX GPIO_USART6_RX_1 /* PC7 */ +#define GPIO_USART6_CTS GPIO_USART6_CTS_NSS_2 /* PG15 */ +#define GPIO_USART6_RTS GPIO_USART6_RTS_2 /* PG8 */ + +// Defined normal but needs swapping in software! +#define GPIO_UART7_TX GPIO_UART7_TX_3 /* PE8 */ +#define GPIO_UART7_RX GPIO_UART7_RX_3 /* PE7 */ + +#define GPIO_UART8_TX GPIO_UART8_TX_1 /* PE1 */ +#define GPIO_UART8_RX GPIO_UART8_RX_1 /* PE0 */ + + +/* CAN */ +#define GPIO_CAN1_RX GPIO_CAN1_RX_2 /* PB8 */ +#define GPIO_CAN1_TX GPIO_CAN1_TX_2 /* PB9 */ + +#define GPIO_CAN2_RX GPIO_CAN2_RX_2 /* PB5 */ +#define GPIO_CAN2_TX GPIO_CAN2_TX_2 /* PB6 */ + + +/* SPI */ +#define ADJ_SLEW_RATE(p) (((p) & ~GPIO_SPEED_MASK) | (GPIO_SPEED_2MHz)) + +#define GPIO_SPI1_SCK ADJ_SLEW_RATE(GPIO_SPI1_SCK_2) /* PB3 */ +#define GPIO_SPI1_MISO GPIO_SPI1_MISO_2 /* PB4 */ +#define GPIO_SPI1_MOSI GPIO_SPI1_MOSI_3 /* PD7 */ + +#define GPIO_SPI2_SCK ADJ_SLEW_RATE(GPIO_SPI2_SCK_2) /* PA9 */ +#define GPIO_SPI2_MISO GPIO_SPI2_MISO_1 /* PB14 */ +#define GPIO_SPI2_MOSI GPIO_SPI2_MOSI_1 /* PB15 */ + +#define GPIO_SPI4_SCK ADJ_SLEW_RATE(GPIO_SPI4_SCK_1) /* PE12 */ +#define GPIO_SPI4_MISO GPIO_SPI4_MISO_2 /* PE5 */ +#define GPIO_SPI4_MOSI GPIO_SPI4_MOSI_2 /* PE6 */ + + +/* I2C */ +#define GPIO_I2C2_SCL GPIO_I2C2_SCL_2 /* PF1 */ +#define GPIO_I2C2_SDA GPIO_I2C2_SDA_2 /* PF0 */ + +#define GPIO_I2C4_SCL GPIO_I2C4_SCL_2 /* PF14 */ +#define GPIO_I2C4_SDA GPIO_I2C4_SDA_2 /* PF15 */ diff --git a/boards/cubepilot/cubered-primary/nuttx-config/include/board_dma_map.h b/boards/cubepilot/cubered-primary/nuttx-config/include/board_dma_map.h new file mode 100644 index 0000000000..6fba164d08 --- /dev/null +++ b/boards/cubepilot/cubered-primary/nuttx-config/include/board_dma_map.h @@ -0,0 +1,55 @@ +/**************************************************************************** + * + * Copyright (c) 2020 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#pragma once + +// DMAMUX1 +#define DMAMAP_SPI1_RX DMAMAP_DMA12_SPI1RX_0 +#define DMAMAP_SPI1_TX DMAMAP_DMA12_SPI1TX_0 + +#define DMAMAP_SPI2_RX DMAMAP_DMA12_SPI2RX_0 +#define DMAMAP_SPI2_TX DMAMAP_DMA12_SPI2TX_0 + +#define DMAMAP_SPI4_RX DMAMAP_DMA12_SPI4RX_0 +#define DMAMAP_SPI4_TX DMAMAP_DMA12_SPI4TX_0 + +#define DMAMAP_UART7_RX DMAMAP_DMA12_UART7RX_0 +#define DMAMAP_UART7_TX DMAMAP_DMA12_UART7TX_0 + +//#define DMAMAP_UART4_RX DMAMAP_DMA12_UART4RX_0 /* DMA1:63 */ +//#define DMAMAP_UART4_TX DMAMAP_DMA12_UART4TX_0 /* DMA1:64 */ + +// DMA 2 +// Timer 1 +// Timer 2 +// Timer 3 diff --git a/boards/cubepilot/cubered-primary/nuttx-config/nsh/defconfig b/boards/cubepilot/cubered-primary/nuttx-config/nsh/defconfig new file mode 100644 index 0000000000..01615ffeb8 --- /dev/null +++ b/boards/cubepilot/cubered-primary/nuttx-config/nsh/defconfig @@ -0,0 +1,314 @@ +# +# 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_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_ARP 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_IFCONFIG is not set +# CONFIG_NSH_DISABLE_IFUPDOWN 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_NSLOOKUP 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_TELNETD 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/cubepilot/cubered-primary/nuttx-config" +CONFIG_ARCH_BOARD_CUSTOM_DIR_RELPATH=y +CONFIG_ARCH_BOARD_CUSTOM_NAME="px4" +CONFIG_ARCH_CHIP="stm32h7" +CONFIG_ARCH_CHIP_STM32H747XI=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_ARM_MPU_EARLY_RESET=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_ASSERT_RESET_VALUE=0 +CONFIG_BOARD_CRASHDUMP=y +CONFIG_BOARD_LOOPSPERMSEC=79954 +CONFIG_BOARD_RESET_ON_ASSERT=2 +CONFIG_BUILTIN=y +CONFIG_CDCACM=y +CONFIG_CDCACM_IFLOWCONTROL=y +CONFIG_CDCACM_PRODUCTID=0x1059 +CONFIG_CDCACM_PRODUCTSTR="CubeRed" +CONFIG_CDCACM_RXBUFSIZE=600 +CONFIG_CDCACM_TXBUFSIZE=12000 +CONFIG_CDCACM_VENDORID=0x2DAE +CONFIG_CDCACM_VENDORSTR="CubePilot" +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_HARDFAULT_ALERT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEBUG_TCBINFO=y +CONFIG_DEFAULT_SMALL=y +CONFIG_DEV_FIFO_SIZE=0 +CONFIG_DEV_PIPE_MAXSIZE=1024 +CONFIG_DEV_PIPE_SIZE=70 +CONFIG_DEV_URANDOM=y +CONFIG_ETH0_PHY_LAN8720=y +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_FSUTILS_IPCFG=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_THROTTLE=0 +CONFIG_IPCFG_BINARY=y +CONFIG_IPCFG_CHARDEV=y +CONFIG_IPCFG_PATH="/fs/microsd/mtd_net" +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_REGIONS=4 +CONFIG_MTD=y +CONFIG_MTD_BYTE_WRITE=y +CONFIG_MTD_PARTITION=y +CONFIG_MTD_PROGMEM=y +CONFIG_MTD_RAMTRON=y +CONFIG_NAME_MAX=40 +CONFIG_NET=y +CONFIG_NETDB_DNSCLIENT=y +CONFIG_NETDB_DNSCLIENT_ENTRIES=8 +CONFIG_NETDB_DNSSERVER_NOADDR=y +CONFIG_NETDEV_PHY_IOCTL=y +CONFIG_NETINIT_DHCPC=y +CONFIG_NETINIT_DNS=y +CONFIG_NETINIT_DNSIPADDR=0xA290AFE +CONFIG_NETINIT_DRIPADDR=0xA290AFE +CONFIG_NETINIT_MONITOR=y +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_ETH_PKTSIZE=1518 +CONFIG_NET_ICMP=y +CONFIG_NET_ICMP_SOCKET=y +CONFIG_NET_NACTIVESOCKETS=16 +CONFIG_NET_SOLINGER=y +CONFIG_NET_TCP=y +CONFIG_NET_TCPBACKLOG=y +CONFIG_NET_TCP_DELAYED_ACK=y +CONFIG_NET_TCP_WRITE_BUFFERS=y +CONFIG_NET_UDP=y +CONFIG_NET_UDP_CHECKSUMS=y +CONFIG_NET_UDP_WRITE_BUFFERS=y +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_TELNET=y +CONFIG_NSH_TELNET_LOGIN=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_RAMTRON_EMULATE_PAGE_SHIFT=5 +CONFIG_RAMTRON_EMULATE_SECTOR_SHIFT=5 +CONFIG_RAMTRON_SETSPEED=y +CONFIG_RAM_SIZE=245760 +CONFIG_RAM_START=0x20010000 +CONFIG_RAW_BINARY=y +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_READLINE_TABCOMPLETION=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_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_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_BKPSRAM=y +CONFIG_STM32H7_DMA1=y +CONFIG_STM32H7_DMA2=y +CONFIG_STM32H7_DMACAPABLE=y +CONFIG_STM32H7_ETHMAC=y +CONFIG_STM32H7_FLOWCONTROL_BROKEN=y +CONFIG_STM32H7_I2C2=y +CONFIG_STM32H7_I2C4=y +CONFIG_STM32H7_I2C_DYNTIMEO=y +CONFIG_STM32H7_I2C_DYNTIMEO_STARTSTOP=10 +CONFIG_STM32H7_OTGFS=y +CONFIG_STM32H7_PHYADDR=0 +CONFIG_STM32H7_PHYSR=31 +CONFIG_STM32H7_PHYSR_100MBPS=0x8 +CONFIG_STM32H7_PHYSR_FULLDUPLEX=0x10 +CONFIG_STM32H7_PHYSR_MODE=0x10 +CONFIG_STM32H7_PHYSR_SPEED=0x8 +CONFIG_STM32H7_PHY_POLLING=y +CONFIG_STM32H7_PROGMEM=y +CONFIG_STM32H7_PWR_DIRECT_SMPS_SUPPLY=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_SPI1=y +CONFIG_STM32H7_SPI1_DMA=y +CONFIG_STM32H7_SPI1_DMA_BUFFER=1024 +CONFIG_STM32H7_SPI2=y +CONFIG_STM32H7_SPI2_DMA=y +CONFIG_STM32H7_SPI2_DMA_BUFFER=1024 +CONFIG_STM32H7_SPI4=y +CONFIG_STM32H7_SPI4_DMA=y +CONFIG_STM32H7_SPI4_DMA_BUFFER=1024 +CONFIG_STM32H7_TIM12=y +CONFIG_STM32H7_TIM1=y +CONFIG_STM32H7_TIM2=y +CONFIG_STM32H7_TIM3=y +CONFIG_STM32H7_UART4=y +CONFIG_STM32H7_UART7=y +CONFIG_STM32H7_UART8=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_DHCPC_RENEW=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=24 +CONFIG_TTY_SIGINT=y +CONFIG_TTY_SIGINT_CHAR=0x03 +CONFIG_SYSTEM_PING=y +CONFIG_SYSTEM_SYSTEM=y +CONFIG_TTY_SIGTSTP=y +CONFIG_UART4_BAUD=57600 +CONFIG_UART4_RXBUFSIZE=600 +CONFIG_UART4_TXBUFSIZE=1500 +CONFIG_UART4_SERIAL_CONSOLE=y +CONFIG_UART7_BAUD=57600 +CONFIG_UART7_RXBUFSIZE=600 +CONFIG_UART7_TXBUFSIZE=1500 +CONFIG_UART8_BAUD=57600 +CONFIG_UART8_RXBUFSIZE=600 +CONFIG_UART8_TXBUFSIZE=1500 +CONFIG_USART2_BAUD=57600 +CONFIG_USART2_IFLOWCONTROL=y +CONFIG_USART2_OFLOWCONTROL=y +CONFIG_USART2_RXBUFSIZE=600 +CONFIG_USART2_TXBUFSIZE=1500 +CONFIG_USART3_BAUD=57600 +CONFIG_USART3_RXBUFSIZE=600 +CONFIG_USART3_TXBUFSIZE=3000 +CONFIG_USART6_BAUD=57600 +CONFIG_USART6_IFLOWCONTROL=y +CONFIG_USART6_OFLOWCONTROL=y +CONFIG_USART6_RXBUFSIZE=600 +CONFIG_USART6_TXBUFSIZE=1500 +CONFIG_USBDEV=y +CONFIG_USBDEV_BUSPOWERED=y +CONFIG_USBDEV_MAXPOWER=500 +CONFIG_USEC_PER_TICK=1000 +CONFIG_WATCHDOG=y diff --git a/boards/cubepilot/cubered-primary/nuttx-config/scripts/script.ld b/boards/cubepilot/cubered-primary/nuttx-config/scripts/script.ld new file mode 100644 index 0000000000..6b643fbde9 --- /dev/null +++ b/boards/cubepilot/cubered-primary/nuttx-config/scripts/script.ld @@ -0,0 +1,239 @@ +/**************************************************************************** + * 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 STM32H757ZI 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 STM32H757ZI, 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 STM32H757ZI 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 = 1664K /* 2 sectors of 128K following for params) */ + EXT_FLASH (rx) : ORIGIN = 0x90000000, LENGTH = 32768K + + 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 +{ + startup : ALIGN(4) SUBALIGN(4) + { + _stext = ABSOLUTE(.); + *(.vectors) + . = ALIGN(32); + /* + This signature provides the bootloader with a way to delay booting + */ + _bootdelay_signature = ABSOLUTE(.); + FILL(0xffecc2925d7d05c5) + . += 8; + } > FLASH + + /* + * Init functions (static constructors and the like) + */ + init_section : { + _sinit = ABSOLUTE(.); + KEEP(*(.init_array .init_array.*)) + _einit = ABSOLUTE(.); + } > FLASH + + /* External Flash area if defined */ + .extflash : ALIGN(4) SUBALIGN(4) + { + *libromfs.a:*.*(.text* .rodata*) + *libmodules__mavlink.a:*.*(.text* .rodata*) + *(.extflash) + _etext = ABSOLUTE(.); + } > EXT_FLASH + + .text : { + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.rodata .rodata.*) + *(.gnu.linkonce.t.*) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + } > 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/cubepilot/cubered-primary/src/CMakeLists.txt b/boards/cubepilot/cubered-primary/src/CMakeLists.txt new file mode 100644 index 0000000000..c8e7699046 --- /dev/null +++ b/boards/cubepilot/cubered-primary/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 "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 + spi.cpp + timer_config.cpp + usb.c + ) + + target_link_libraries(drivers_board + PRIVATE + arch_io_pins + arch_spi + drivers__led + nuttx_arch + nuttx_drivers + px4_layer + ) +endif() diff --git a/boards/cubepilot/cubered-primary/src/board_config.h b/boards/cubepilot/cubered-primary/src/board_config.h new file mode 100644 index 0000000000..23b556836b --- /dev/null +++ b/boards/cubepilot/cubered-primary/src/board_config.h @@ -0,0 +1,199 @@ +/**************************************************************************** + * + * 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 + * + * Board internal definitions + */ + +#pragma once + +#include +#include +#include +#include + +/** + * If NuttX is built without support for SMPS it can brick the hardware. + * Therefore, we make sure the NuttX headers are correct. + */ +#include "hardware/stm32h7x3xx_pwr.h" +#if STM32_PWR_CR3_SMPSEXTHP != (1 << 3) +# error "No SMPS support in NuttX submodule"); +#endif + + +/* PX4IO connection configuration */ +#define BOARD_USES_PX4IO_VERSION 2 +#define PX4IO_SERIAL_DEVICE "/dev/ttyS4" +#define PX4IO_SERIAL_TX_GPIO GPIO_UART7_TX +#define PX4IO_SERIAL_RX_GPIO GPIO_UART7_RX +#define PX4IO_SERIAL_BASE STM32_UART7_BASE +#define PX4IO_SERIAL_VECTOR STM32_IRQ_UART7 +#define PX4IO_SERIAL_TX_DMAMAP DMAMAP_UART7_TX +#define PX4IO_SERIAL_RX_DMAMAP DMAMAP_UART7_RX +#define PX4IO_SERIAL_RCC_REG STM32_RCC_APB1ENR +#define PX4IO_SERIAL_RCC_EN RCC_APB1LENR_UART7EN +#define PX4IO_SERIAL_CLOCK STM32_PCLK1_FREQUENCY +#define PX4IO_SERIAL_BITRATE 1500000 /* 1.5Mbps -> max rate for IO */ +#define PX4IO_SERIAL_SWAPPED + + +/* LEDs */ +#define GPIO_nLED_AMBER /* PG5 */ (GPIO_OUTPUT|GPIO_OPENDRAIN|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTG|GPIO_PIN5) + +#define BOARD_HAS_CONTROL_STATUS_LEDS 1 +#define BOARD_ARMED_LED LED_AMBER + + +/* ADC channels */ +#define PX4_ADC_GPIO \ + /* PF11 */ GPIO_ADC1_INP2, \ + /* PC0 */ GPIO_ADC123_INP10, \ + /* PF13 */ GPIO_ADC2_INP2, \ + /* PB1 */ GPIO_ADC12_INP5, \ + /* PF12 */ GPIO_ADC1_INP6, \ + /* PF3 */ GPIO_ADC3_INP5 + +/* Define Channel numbers must match above GPIO pins */ +#define ADC_BATTERY1_VOLTAGE_CHANNEL 2 /* PF11: BATT_VOLTAGE_SENS */ +#define ADC_BATTERY1_CURRENT_CHANNEL 10 /* PC0: BATT_CURRENT_SENS */ +#define ADC_SCALED_V5_CHANNEL 2 /* PF13: VDD_5V_SENS */ +#define ADC_BATTERY2_VOLTAGE_CHANNEL 5 /* PB1: FMU_AUX_POWER_ADC1 */ +#define ADC_BATTERY2_CURRENT_CHANNEL 6 /* PF12: FMU_AUX_ADC2 */ +#define ADC_AIRSPEED_VOLTAGE_CHANNEL 5 /* PF3: PRESSURE_SENS */ + +#define ADC_CHANNELS \ + ((1 << ADC_BATTERY1_VOLTAGE_CHANNEL) | \ + (1 << ADC_BATTERY1_CURRENT_CHANNEL) | \ + (1 << ADC_SCALED_V5_CHANNEL) | \ + (1 << ADC_BATTERY2_VOLTAGE_CHANNEL) | \ + (1 << ADC_BATTERY2_CURRENT_CHANNEL) | \ + (1 << ADC_AIRSPEED_VOLTAGE_CHANNEL)) + +/* HW has to large of R termination on ADC todo:change when HW value is chosen */ +#define BOARD_ADC_OPEN_CIRCUIT_V (5.6f) + +/* PWM */ +#define DIRECT_PWM_OUTPUT_CHANNELS 6 + +/* Power supply control and monitoring GPIOs */ +#define BOARD_NUMBER_BRICKS 2 +#define GPIO_nVDD_BRICK1_VALID /* PE15 */ (GPIO_INPUT|GPIO_PULLUP|GPIO_PORTE|GPIO_PIN15) // VDD_BRICK_nVALID +#define GPIO_nVDD_BRICK2_VALID /* PE4 */ (GPIO_INPUT|GPIO_PULLUP|GPIO_PORTE|GPIO_PIN4) // VDD_BRICK2_nVALID +#define GPIO_nVDD_USB_VALID /* PE3 */ (GPIO_INPUT|GPIO_PULLUP|GPIO_PORTE|GPIO_PIN3) // VBUS_nVALID +#define GPIO_VDD_3V3_SENSORS_EN /* PG0 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_SET|GPIO_PORTG|GPIO_PIN0) // VDD_3V3_SENSORS_EN +#define GPIO_nVDD_5V_PERIPH_EN /* PF2 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_CLEAR|GPIO_PORTF|GPIO_PIN2) // nVDD_5V_PERIPH_EN +//#define GPIO_nVDD_5V_PERIPH_OC /* PD10 */ (GPIO_INPUT|GPIO_PULLUP|GPIO_PORTD|GPIO_PIN10) // VDD_5V_PERIPH_nOC +//#define GPIO_nVDD_5V_HIPOWER_OC /* PF4 */ (GPIO_INPUT|GPIO_PULLUP|GPIO_PORTF|GPIO_PIN4) // VDD_5V_HIPOWER_nOC +#define GPIO_ICM42688P_CLKIN_EN /* PA8 */ (GPIO_INPUT|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN8) + +/* Tone alarm output */ +#define TONE_ALARM_TIMER 5 /* timer 5 */ +#define TONE_ALARM_CHANNEL 1 /* PA0 TIM5_CH1 */ + +#define GPIO_BUZZER_1 /* PA0 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_CLEAR|GPIO_PORTA|GPIO_PIN0) // ALARM + +#define GPIO_TONE_ALARM_IDLE GPIO_BUZZER_1 +#define GPIO_TONE_ALARM GPIO_TIM5_CH1OUT_1 + +/* PWM input driver. Use FMU AUX5 pins attached to timer3 channel 1 */ +#define PWMIN_TIMER 3 +#define PWMIN_TIMER_CHANNEL /* T3C1 */ 1 +#define GPIO_PWM_IN /* PA6 */ GPIO_TIM3_CH1IN_1 + +/* 3 timers for PWM out */ +#define BOARD_NUM_IO_TIMERS 3 + +/* USB OTG VBUS is not connected, we use GPIO_nVDD_USB_VALID instead to determine USB being connected. */ + +/* High-resolution timer */ +#define HRT_TIMER 12 /* use timer12 for the HRT */ +#define HRT_TIMER_CHANNEL 1 /* use capture/compare channel 1 */ + +#define BOARD_ADC_USB_VALID (!px4_arch_gpioread(GPIO_nVDD_USB_VALID)) +#define BOARD_ADC_BRICK1_VALID (!px4_arch_gpioread(GPIO_nVDD_BRICK1_VALID)) +#define BOARD_ADC_BRICK2_VALID (!px4_arch_gpioread(GPIO_nVDD_BRICK2_VALID)) +//#define BOARD_ADC_PERIPH_5V_OC (!px4_arch_gpioread(GPIO_nVDD_5V_PERIPH_OC)) +//#define BOARD_ADC_HIPOWER_5V_OC (!px4_arch_gpioread(GPIO_nVDD_5V_HIPOWER_OC)) + +/* 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_STATIC_MANIFEST 1 + +/* There is no FRAM/EEPROM */ +#define FLASH_BASED_PARAMS + +#define BOARD_ENABLE_CONSOLE_BUFFER + +#define PX4_GPIO_INIT_LIST { \ + PX4_ADC_GPIO, \ + GPIO_CAN1_TX, \ + GPIO_CAN1_RX, \ + GPIO_CAN2_TX, \ + GPIO_CAN2_RX, \ + GPIO_nVDD_BRICK1_VALID, \ + GPIO_nVDD_BRICK1_VALID, \ + GPIO_nVDD_USB_VALID, \ + GPIO_VDD_3V3_SENSORS_EN, \ + GPIO_nVDD_5V_PERIPH_EN, \ + PX4_MAKE_GPIO_OUTPUT_CLEAR(GPIO_I2C2_SCL), \ + PX4_MAKE_GPIO_OUTPUT_CLEAR(GPIO_I2C2_SDA), \ + PX4_MAKE_GPIO_OUTPUT_CLEAR(GPIO_I2C4_SCL), \ + PX4_MAKE_GPIO_OUTPUT_CLEAR(GPIO_I2C4_SDA), \ + PX4_GPIO_PIN_OFF(GPIO_SDMMC1_D0), \ + PX4_GPIO_PIN_OFF(GPIO_SDMMC1_D1), \ + PX4_GPIO_PIN_OFF(GPIO_SDMMC1_D2), \ + PX4_GPIO_PIN_OFF(GPIO_SDMMC1_D3), \ + PX4_GPIO_PIN_OFF(GPIO_SDMMC1_CMD),\ + GPIO_TONE_ALARM_IDLE, \ + GPIO_ICM42688P_CLKIN_EN, \ + } + +//GPIO_nVDD_5V_PERIPH_OC, +//GPIO_nVDD_5V_HIPOWER_OC, + +__BEGIN_DECLS +#ifndef __ASSEMBLY__ + +extern void stm32_spiinitialize(void); +extern void board_peripheral_reset(int ms); + +#include +#endif /* __ASSEMBLY__ */ +__END_DECLS diff --git a/boards/cubepilot/cubered-primary/src/hw_config.h b/boards/cubepilot/cubered-primary/src/hw_config.h new file mode 100644 index 0000000000..a43ebadd31 --- /dev/null +++ b/boards/cubepilot/cubered-primary/src/hw_config.h @@ -0,0 +1,135 @@ +/**************************************************************************** + * + * 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 + +/**************************************************************************** + * 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 1069 +#define _FLASH_KBYTES (*(uint32_t *)0x1FF1E880) +#define BOARD_FLASH_SECTORS (14) +#define BOARD_FLASH_SIZE (_FLASH_KBYTES * 1024) + +#define OSC_FREQ 24 + +#define BOARD_PIN_LED_ACTIVITY GPIO_nLED_AMBER +#define BOARD_PIN_LED_BOOTLOADER GPIO_nLED_AMBER +#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/cubepilot/cubered-primary/src/i2c.cpp b/boards/cubepilot/cubered-primary/src/i2c.cpp new file mode 100644 index 0000000000..af98541371 --- /dev/null +++ b/boards/cubepilot/cubered-primary/src/i2c.cpp @@ -0,0 +1,39 @@ +/**************************************************************************** + * + * 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(2), + initI2CBusExternal(4), +}; diff --git a/boards/cubepilot/cubered-primary/src/init.c b/boards/cubepilot/cubered-primary/src/init.c new file mode 100644 index 0000000000..6a3cdad229 --- /dev/null +++ b/boards/cubepilot/cubered-primary/src/init.c @@ -0,0 +1,221 @@ +/**************************************************************************** + * + * 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. + * + ****************************************************************************/ + +/** + * @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 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 + +#include + +__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) +{ + /* Power off Interfaces */ + stm32_gpiowrite(GPIO_nVDD_5V_PERIPH_EN, true); + + /* wait for the peripheral rail to reach GND */ + usleep(ms * 1000); + syslog(LOG_DEBUG, "reset done, %d ms\n", ms); + + /* re-enable power */ + stm32_gpiowrite(GPIO_nVDD_5V_PERIPH_EN, false); +} + +/************************************************************************************ + * 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))); + } + + if (status >= 0) { + up_mdelay(6); + } +} + +/************************************************************************************ + * 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 pins */ + const uint32_t gpio[] = PX4_GPIO_INIT_LIST; + px4_gpio_init(gpio, arraySize(gpio)); + board_control_spi_sensors_power_configgpio(); + + /* configure LEDs */ + board_autoled_initialize(); +} + +/**************************************************************************** + * 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) +{ + /* Power on Interfaces */ + stm32_gpiowrite(GPIO_VDD_3V3_SENSORS_EN, true); + stm32_gpiowrite(GPIO_nVDD_5V_PERIPH_EN, false); + board_control_spi_sensors_power(true, 0xffff); + + px4_platform_init(); + + stm32_spiinitialize(); + + /* 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_AMBER); + + if (board_hardfault_init(2, true) != 0) { + led_on(LED_AMBER); + } + +#ifdef CONFIG_MMCSD + /* Mount the SDIO-based MMC/SD block driver */ + /* First, get an instance of the SDIO interface */ + struct sdio_dev_s *sdio_dev = sdio_initialize(0); // SDIO_SLOTNO 0 Only one slot + + if (!sdio_dev) { + syslog(LOG_ERR, "[boot] Failed to initialize SDIO slot %d\n", 0); + } + + if (mmcsd_slotinitialize(0, sdio_dev) != OK) { + syslog(LOG_ERR, "[boot] Failed to bind SDIO to the MMC/SD driver\n"); + } + + /* Assume that the SD card is inserted. What choice do we have? */ + sdio_mediachange(sdio_dev, true); +#endif /* CONFIG_MMCSD */ + +#if defined(FLASH_BASED_PARAMS) + static sector_descriptor_t params_sector_map[] = { + {14, 128 * 1024, 0x081C0000}, + //{2, 32 * 1024, 0x081C8000}, -> MTD + {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_AMBER); + return result; + } + +#endif /* FLASH_BASED_PARAMS */ + + /* Configure the HW based on the manifest */ + + px4_platform_configure(); + + return OK; +} diff --git a/boards/cubepilot/cubered-primary/src/led.c b/boards/cubepilot/cubered-primary/src/led.c new file mode 100644 index 0000000000..f3c25469c4 --- /dev/null +++ b/boards/cubepilot/cubered-primary/src/led.c @@ -0,0 +1,110 @@ +/**************************************************************************** + * + * 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. + * + ****************************************************************************/ + +/** + * @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_AMBER, +}; + +__EXPORT void led_init(void) +{ + 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/cubepilot/cubered-primary/src/spi.cpp b/boards/cubepilot/cubered-primary/src/spi.cpp new file mode 100644 index 0000000000..400e09f916 --- /dev/null +++ b/boards/cubepilot/cubered-primary/src/spi.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** + * + * 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 + +constexpr px4_spi_bus_t px4_spi_buses[SPI_BUS_MAX_BUS_ITEMS] = { + initSPIBus(SPI::Bus::SPI1, { + initSPIDevice(DRV_IMU_DEVTYPE_ICM42688P, SPI::CS{GPIO::PortE, GPIO::Pin9}), // ICM42688_0_CS + initSPIDevice(DRV_IMU_DEVTYPE_ICM45686, SPI::CS{GPIO::PortE, GPIO::Pin9}), // ICM42688_0_CS + initSPIDevice(DRV_BARO_DEVTYPE_MS5611, SPI::CS{GPIO::PortE, GPIO::Pin13}), // BARO_0_CS + }), + + initSPIBus(SPI::Bus::SPI2, { + //initSPIDevice(SPIDEV_FLASH(0), SPI::CS{GPIO::PortD, GPIO::Pin10}), // FRAM_CS + initSPIDevice(DRV_MAG_DEVTYPE_RM3100, SPI::CS{GPIO::PortD, GPIO::Pin15}), // RM3100_CS + initSPIDevice(DRV_IMU_DEVTYPE_ICM42688P, SPI::CS{GPIO::PortD, GPIO::Pin14}), // ICM42688_1_CS + initSPIDevice(DRV_IMU_DEVTYPE_ICM45686, SPI::CS{GPIO::PortD, GPIO::Pin14}), // ICM42688_1_CS + + }), + + initSPIBus(SPI::Bus::SPI4, { + initSPIDevice(DRV_IMU_DEVTYPE_ICM20649, SPI::CS{GPIO::PortF, GPIO::Pin5}), // ICM_2_CS + initSPIDevice(DRV_IMU_DEVTYPE_ICM45686, SPI::CS{GPIO::PortF, GPIO::Pin5}), // ICM_2_CS + initSPIDevice(DRV_BARO_DEVTYPE_MS5611, SPI::CS{GPIO::PortC, GPIO::Pin2}), // BARO_1_CS + }), +}; + +static constexpr bool unused = validateSPIConfig(px4_spi_buses); diff --git a/boards/cubepilot/cubered-primary/src/timer_config.cpp b/boards/cubepilot/cubered-primary/src/timer_config.cpp new file mode 100644 index 0000000000..ca5a063dc0 --- /dev/null +++ b/boards/cubepilot/cubered-primary/src/timer_config.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** + * + * 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 io_timers_t io_timers[MAX_IO_TIMERS] = { + initIOTimer(Timer::Timer1, DMA{DMA::Index2}), + initIOTimer(Timer::Timer2, DMA{DMA::Index2}), + initIOTimer(Timer::Timer3, DMA{DMA::Index2}) +}; + +constexpr timer_io_channels_t timer_io_channels[MAX_TIMER_IO_CHANNELS] = { + initIOTimerChannel(io_timers, {Timer::Timer1, Timer::Channel2}, {GPIO::PortE, GPIO::Pin11}), + initIOTimerChannel(io_timers, {Timer::Timer1, Timer::Channel4}, {GPIO::PortE, GPIO::Pin14}), + initIOTimerChannel(io_timers, {Timer::Timer2, Timer::Channel1}, {GPIO::PortA, GPIO::Pin15}), + initIOTimerChannel(io_timers, {Timer::Timer2, Timer::Channel4}, {GPIO::PortA, GPIO::Pin3}), + initIOTimerChannel(io_timers, {Timer::Timer3, Timer::Channel1}, {GPIO::PortA, GPIO::Pin6}), + initIOTimerChannel(io_timers, {Timer::Timer3, Timer::Channel3}, {GPIO::PortB, GPIO::Pin0}) +}; + +constexpr io_timers_channel_mapping_t io_timers_channel_mapping = + initIOTimerChannelMapping(io_timers, timer_io_channels); diff --git a/boards/cubepilot/cubered-primary/src/usb.c b/boards/cubepilot/cubered-primary/src/usb.c new file mode 100644 index 0000000000..ab0f0a1e21 --- /dev/null +++ b/boards/cubepilot/cubered-primary/src/usb.c @@ -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. + * + ****************************************************************************/ + +/** + * @file usb.c + * + * Board-specific USB functions. + */ + +#include "board_config.h" +#include +#include +#include +#include +#include + +/************************************************************************************ + * 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); +} + +int board_read_VBUS_state(void) +{ + return BOARD_ADC_USB_VALID ? 0 : -1; +} diff --git a/boards/cubepilot/cubered-secondary/default.px4board b/boards/cubepilot/cubered-secondary/default.px4board new file mode 100644 index 0000000000..265a79923d --- /dev/null +++ b/boards/cubepilot/cubered-secondary/default.px4board @@ -0,0 +1,33 @@ +CONFIG_BOARD_TOOLCHAIN="arm-none-eabi" +CONFIG_BOARD_ARCHITECTURE="cortex-m7" +CONFIG_BOARD_SERIAL_GPS1="/dev/ttyS2" +CONFIG_BOARD_SERIAL_TEL1="/dev/ttyS0" +CONFIG_BOARD_SERIAL_TEL2="/dev/ttyS1" +CONFIG_BOARD_OVERRIDE_UPLOAD_TARGET=y +CONFIG_DRIVERS_ADC_BOARD_ADC=y +CONFIG_DRIVERS_DSHOT=y +CONFIG_DRIVERS_IMU_INVENSENSE_ICM42688P=y +CONFIG_DRIVERS_IMU_INVENSENSE_ICM45686=y +CONFIG_DRIVERS_PWM_OUT=y +CONFIG_MODULES_CONTROL_ALLOCATOR=y +CONFIG_DRIVERS_CUBERED_BRIDGE_SECONDARY=y +CONFIG_MODULES_LOAD_MON=y +CONFIG_SYSTEMCMDS_ACTUATOR_TEST=y +CONFIG_SYSTEMCMDS_BSONDUMP=y +CONFIG_SYSTEMCMDS_DMESG=y +CONFIG_SYSTEMCMDS_GPIO=y +CONFIG_SYSTEMCMDS_HARDFAULT_LOG=y +CONFIG_SYSTEMCMDS_LED_CONTROL=y +CONFIG_SYSTEMCMDS_MFT=y +CONFIG_SYSTEMCMDS_MTD=y +CONFIG_SYSTEMCMDS_NSHTERM=y +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 +CONFIG_SYSTEMCMDS_MICROBENCH=y diff --git a/boards/cubepilot/cubered-secondary/firmware.prototype b/boards/cubepilot/cubered-secondary/firmware.prototype new file mode 100644 index 0000000000..451544c4cc --- /dev/null +++ b/boards/cubepilot/cubered-secondary/firmware.prototype @@ -0,0 +1,13 @@ +{ + "board_id": 1070, + "magic": "PX4FWv1", + "description": "Firmware for the CubePilot CubeRed Secondary board", + "image": "", + "build_time": 0, + "summary": "CubeRed-Secondary", + "version": "0.1", + "image_size": 0, + "image_maxsize": 1966080, + "git_identity": "", + "board_revision": 0 +} diff --git a/boards/cubepilot/cubered-secondary/init/rc.board_defaults b/boards/cubepilot/cubered-secondary/init/rc.board_defaults new file mode 100644 index 0000000000..64b8bbba97 --- /dev/null +++ b/boards/cubepilot/cubered-secondary/init/rc.board_defaults @@ -0,0 +1,17 @@ +#!/bin/sh +# +# board specific defaults +#------------------------------------------------------------------------------ + +param set-default BAT1_V_DIV 10.1 +param set-default BAT2_V_DIV 10.1 + +param set-default BAT1_A_PER_V 17 +param set-default BAT2_A_PER_V 17 + +# Disable IMU thermal control +param set-default SENS_EN_THERMAL 0 + +param set-default -s SENS_TEMP_ID 2621474 + +#set IOFW "/etc/extras/cubepilot_io-v2_default.bin" diff --git a/boards/cubepilot/cubered-secondary/init/rc.board_extras b/boards/cubepilot/cubered-secondary/init/rc.board_extras new file mode 100644 index 0000000000..cd1f2bc2bd --- /dev/null +++ b/boards/cubepilot/cubered-secondary/init/rc.board_extras @@ -0,0 +1,6 @@ +#!/bin/sh +# +# board specific extras +#------------------------------------------------------------------------------ + +cubered_bridge_secondary start diff --git a/boards/cubepilot/cubered-secondary/init/rc.board_mavlink b/boards/cubepilot/cubered-secondary/init/rc.board_mavlink new file mode 100644 index 0000000000..13f47935d9 --- /dev/null +++ b/boards/cubepilot/cubered-secondary/init/rc.board_mavlink @@ -0,0 +1,2 @@ +#!/bin/sh + diff --git a/boards/cubepilot/cubered-secondary/init/rc.board_sensors b/boards/cubepilot/cubered-secondary/init/rc.board_sensors new file mode 100644 index 0000000000..b62059cc51 --- /dev/null +++ b/boards/cubepilot/cubered-secondary/init/rc.board_sensors @@ -0,0 +1,13 @@ +#!/bin/sh +# +# Board specific sensors init +#------------------------------------------------------------------------------ +# TODO: start all three instances +board_adc start + + +# SPI2 +if ! icm42688p -s -b 2 -R 10 -c 12 -q start +then + icm45686 -s -b 2 -R 10 -c 12 start +fi diff --git a/boards/cubepilot/cubered-secondary/nuttx-config/include/board.h b/boards/cubepilot/cubered-secondary/nuttx-config/include/board.h new file mode 100644 index 0000000000..b391ff9ced --- /dev/null +++ b/boards/cubepilot/cubered-secondary/nuttx-config/include/board.h @@ -0,0 +1,258 @@ +/************************************************************************************ + * nuttx-config/include/board.h + * + * Copyright (C) 2020 Gregory Nutt. All rights reserved. + * Authors: 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. + * + ************************************************************************************/ +#pragma once + +#include "board_dma_map.h" + +#include + +#ifndef __ASSEMBLY__ +# include +#endif + +#include "stm32_rcc.h" +#include "stm32_sdmmc.h" + +/* Clocking *************************************************************************/ +/* The board provides the following clock sources: + * + * X1: 24 MHz crystal for HSE + * + * So we have these clock source available within the STM32 + * + * HSI: 16 MHz RC factory-trimmed internal oscillator + * HSE: 24 MHz crystal for HSE + */ +#define STM32_BOARD_XTAL 24000000ul + +#define STM32_HSI_FREQUENCY 16000000ul +#define STM32_LSI_FREQUENCY 32000 +#define STM32_HSE_FREQUENCY STM32_BOARD_XTAL + +/* Main PLL Configuration. + * + * PLL source is HSE = 24,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 + */ + +/* PLL1, wide 4 - 8 MHz input, enable DIVP, DIVQ, DIVR + * + * PLL1_VCO = (24,000,000 / 3) * 100 = 800 MHz + * + * PLL1P = PLL1_VCO/2 = 800 MHz / 2 = 400 MHz + * PLL1Q = PLL1_VCO/8 = 800 MHz / 8 = 100 MHz + * PLL1R = PLL1_VCO/2 = 800 MHz / 2 = 400 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(3) +#define STM32_PLLCFG_PLL1N RCC_PLL1DIVR_N1(100) +#define STM32_PLLCFG_PLL1P RCC_PLL1DIVR_P1(2) +#define STM32_PLLCFG_PLL1Q RCC_PLL1DIVR_Q1(10) +#define STM32_PLLCFG_PLL1R RCC_PLL1DIVR_R1(2) + +#define STM32_VCO1_FREQUENCY ((STM32_HSE_FREQUENCY / 3) * 100) +#define STM32_PLL1P_FREQUENCY (STM32_VCO1_FREQUENCY / 2) +#define STM32_PLL1Q_FREQUENCY (STM32_VCO1_FREQUENCY / 10) +#define STM32_PLL1R_FREQUENCY (STM32_VCO1_FREQUENCY / 2) + +/* PLL2 */ +#define STM32_PLLCFG_PLL2CFG (RCC_PLLCFGR_PLL2VCOSEL_WIDE|RCC_PLLCFGR_PLL2RGE_8_16_MHZ|RCC_PLLCFGR_DIVP2EN|RCC_PLLCFGR_DIVQ2EN|RCC_PLLCFGR_DIVR2EN) +#define STM32_PLLCFG_PLL2M RCC_PLLCKSELR_DIVM2(2) +#define STM32_PLLCFG_PLL2N RCC_PLL2DIVR_N2(50) +#define STM32_PLLCFG_PLL2P RCC_PLL2DIVR_P2(3) +#define STM32_PLLCFG_PLL2Q RCC_PLL2DIVR_Q2(6) +#define STM32_PLLCFG_PLL2R RCC_PLL2DIVR_R2(3) + +#define STM32_VCO2_FREQUENCY ((STM32_HSE_FREQUENCY / 2) * 50) +#define STM32_PLL2P_FREQUENCY (STM32_VCO2_FREQUENCY / 3) +#define STM32_PLL2Q_FREQUENCY (STM32_VCO2_FREQUENCY / 6) +#define STM32_PLL2R_FREQUENCY (STM32_VCO2_FREQUENCY / 3) + +/* 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(6) +#define STM32_PLLCFG_PLL3N RCC_PLL3DIVR_N3(72) +#define STM32_PLLCFG_PLL3P RCC_PLL3DIVR_P3(3) +#define STM32_PLLCFG_PLL3Q RCC_PLL3DIVR_Q3(6) +#define STM32_PLLCFG_PLL3R RCC_PLL3DIVR_R3(9) + +#define STM32_VCO3_FREQUENCY ((STM32_HSE_FREQUENCY / 6) * 72) +#define STM32_PLL3P_FREQUENCY (STM32_VCO3_FREQUENCY / 3) +#define STM32_PLL3Q_FREQUENCY (STM32_VCO3_FREQUENCY / 6) +#define STM32_PLL3R_FREQUENCY (STM32_VCO3_FREQUENCY / 9) + +/* SYSCLK = PLL1P = 400MHz + * CPUCLK = SYSCLK / 1 = 400 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 = 200 + */ +#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/4 (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 + */ +#define STM32_RCC_D1CCIPR_SDMMCSEL RCC_D1CCIPR_SDMMC_PLL1 + +#define STM32_RCC_D2CCIP2R_I2C123SRC RCC_D2CCIP2R_I2C123SEL_HSI /* I2C123 clock source */ +#define STM32_RCC_D3CCIPR_I2C4SRC RCC_D3CCIPR_I2C4SEL_HSI +#define STM32_RCC_D2CCIP1R_SPI123SRC RCC_D2CCIP1R_SPI123SEL_PLL2 /* SPI123 clock source */ +#define STM32_RCC_D2CCIP1R_SPI45SRC RCC_D2CCIP1R_SPI45SEL_PLL2 /* SPI45 clock source */ +#define STM32_RCC_D2CCIP2R_USBSRC RCC_D2CCIP2R_USBSEL_PLL3 /* USB 1 and 2 clock source */ +#define STM32_RCC_D2CCIP1R_FDCANSEL RCC_D2CCIP1R_FDCANSEL_HSE /* FDCAN 1 2 clock source */ + +#define STM32_RCC_D3CCIPR_ADCSRC RCC_D3CCIPR_ADCSEL_PLL2 /* ADC 1 2 3 clock source */ + +/* UART clock selection */ +/* reset to default to overwrite any changes done by any bootloader */ + +#define STM32_RCC_D2CCIP2R_USART234578_SEL RCC_D2CCIP2R_USART234578SEL_RCC +#define STM32_RCC_D2CCIP2R_USART16_SEL RCC_D2CCIP2R_USART16SEL_RCC + + +/* FLASH wait states */ +#define BOARD_FLASH_WAITSTATES 2 + +/* UART/USART */ + +// USART2 -> /dev/ttyS0 -> ? +// USART3 -> /dev/ttyS1 -> debug/SWD connector +// UART4 -> /dev/ttyS2 -> ? +// USART6 -> /dev/ttyS3 -> ? +// UART7 -> /dev/ttyS4 -> to Primary +// UART8 -> /dev/ttyS5 -> CONS + +#define GPIO_USART2_TX GPIO_USART2_TX_2 /* PD5 */ +#define GPIO_USART2_RX GPIO_USART2_RX_2 /* PD6 */ +#define GPIO_USART2_CTS GPIO_USART2_CTS_NSS_2 /* PD3 */ +#define GPIO_USART2_RTS GPIO_USART2_RTS_2 /* PD4 */ + +#define GPIO_USART3_TX GPIO_USART3_TX_2 /* PC10 */ +#define GPIO_USART3_RX GPIO_USART3_RX_2 /* PC11 */ + +#define GPIO_UART4_TX GPIO_UART4_TX_5 /* PD1 */ +#define GPIO_UART4_RX GPIO_UART4_RX_5 /* PD0 */ + +#define GPIO_USART6_TX GPIO_USART6_TX_1 /* PC6 */ +#define GPIO_USART6_RX GPIO_USART6_RX_1 /* PC7 */ +#define GPIO_USART6_CTS GPIO_USART6_CTS_NSS_2 /* PG15 */ +#define GPIO_USART6_RTS GPIO_USART6_RTS_2 /* PG8 */ + +#define GPIO_UART7_TX GPIO_UART7_TX_3 /* PE8 */ +#define GPIO_UART7_RX GPIO_UART7_RX_3 /* PE7 */ + +#define GPIO_UART8_TX GPIO_UART8_TX_1 /* PE1 */ +#define GPIO_UART8_RX GPIO_UART8_RX_1 /* PE0 */ + + +/* CAN */ +#define GPIO_CAN1_RX GPIO_CAN1_RX_2 /* PB8 */ +#define GPIO_CAN1_TX GPIO_CAN1_TX_1 /* PA12 */ + +#define GPIO_CAN2_RX GPIO_CAN2_RX_2 /* PB5 */ +#define GPIO_CAN2_TX GPIO_CAN2_TX_2 /* PB6 */ + + +/* SPI */ +#define ADJ_SLEW_RATE(p) (((p) & ~GPIO_SPEED_MASK) | (GPIO_SPEED_2MHz)) + +#define GPIO_SPI1_SCK ADJ_SLEW_RATE(GPIO_SPI1_SCK_2) /* PB3 */ +#define GPIO_SPI1_MISO GPIO_SPI1_MISO_2 /* PB4 */ +#define GPIO_SPI1_MOSI GPIO_SPI1_MOSI_3 /* PD7 */ + +#define GPIO_SPI2_SCK ADJ_SLEW_RATE(GPIO_SPI2_SCK_4) /* PB13 */ +#define GPIO_SPI2_MISO GPIO_SPI2_MISO_2 /* PC2 */ +#define GPIO_SPI2_MOSI GPIO_SPI2_MOSI_2 /* PC1 */ + diff --git a/boards/cubepilot/cubered-secondary/nuttx-config/include/board_dma_map.h b/boards/cubepilot/cubered-secondary/nuttx-config/include/board_dma_map.h new file mode 100644 index 0000000000..8fa6186e81 --- /dev/null +++ b/boards/cubepilot/cubered-secondary/nuttx-config/include/board_dma_map.h @@ -0,0 +1,54 @@ +/**************************************************************************** + * + * Copyright (c) 2020 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#pragma once + +// DMA 1 +#define DMAMAP_SPI1_RX DMAMAP_DMA12_SPI1RX_0 +#define DMAMAP_SPI1_TX DMAMAP_DMA12_SPI1TX_0 + +#define DMAMAP_SPI2_RX DMAMAP_DMA12_SPI2RX_0 +#define DMAMAP_SPI2_TX DMAMAP_DMA12_SPI2TX_0 + +#define DMAMAP_SPI4_RX DMAMAP_DMA12_SPI4RX_0 +#define DMAMAP_SPI4_TX DMAMAP_DMA12_SPI4TX_0 + +// Note: the UART7_RX must not be on DMA channel 1. Channels 0, 2, 3, ... seem to be ok. +// if it is on channel 1 we see weird cache coherency issues. Suddenly the last two chars are +// "leftovers" from previous FIFO buffer rounds. +#define DMAMAP_UART7_RX DMAMAP_DMA12_UART7RX_0 +#define DMAMAP_UART7_TX DMAMAP_DMA12_UART7TX_0 + +// DMA 2 +// Timer 1 +// Timer 2 diff --git a/boards/cubepilot/cubered-secondary/nuttx-config/nsh/defconfig b/boards/cubepilot/cubered-secondary/nuttx-config/nsh/defconfig new file mode 100644 index 0000000000..f29eaa2f00 --- /dev/null +++ b/boards/cubepilot/cubered-secondary/nuttx-config/nsh/defconfig @@ -0,0 +1,212 @@ +# +# 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_IFCONFIG is not set +# CONFIG_NSH_DISABLE_IFUPDOWN 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_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_TELNETD 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/cubepilot/cubered-secondary/nuttx-config" +CONFIG_ARCH_BOARD_CUSTOM_DIR_RELPATH=y +CONFIG_ARCH_BOARD_CUSTOM_NAME="px4" +CONFIG_ARCH_CHIP="stm32h7" +CONFIG_ARCH_CHIP_STM32H747XI=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_ARM_MPU_EARLY_RESET=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_ASSERT_RESET_VALUE=0 +CONFIG_BOARD_CRASHDUMP=y +CONFIG_BOARD_LOOPSPERMSEC=79954 +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_FIFO_SIZE=0 +CONFIG_DEV_PIPE_MAXSIZE=1024 +CONFIG_DEV_PIPE_SIZE=70 +CONFIG_DEV_URANDOM=y +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_IDLETHREAD_STACKSIZE=750 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=3194 +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_MM_REGIONS=4 +CONFIG_MTD=y +CONFIG_MTD_BYTE_WRITE=y +CONFIG_MTD_PARTITION=y +CONFIG_MTD_PROGMEM=y +CONFIG_MTD_RAMTRON=y +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_PIPES=y +CONFIG_PREALLOC_TIMERS=50 +CONFIG_PRIORITY_INHERITANCE=y +CONFIG_PTHREAD_MUTEX_ROBUST=y +CONFIG_PTHREAD_STACK_MIN=512 +CONFIG_RAMTRON_EMULATE_PAGE_SHIFT=5 +CONFIG_RAMTRON_EMULATE_SECTOR_SHIFT=5 +CONFIG_RAMTRON_SETSPEED=y +CONFIG_RAM_SIZE=245760 +CONFIG_RAM_START=0x20010000 +CONFIG_RAW_BINARY=y +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_READLINE_TABCOMPLETION=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_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_BKPSRAM=y +CONFIG_STM32H7_DMA1=y +CONFIG_STM32H7_DMA2=y +CONFIG_STM32H7_DMACAPABLE=y +CONFIG_STM32H7_PROGMEM=y +CONFIG_STM32H7_PWR_DIRECT_SMPS_SUPPLY=y +CONFIG_STM32H7_RTC=y +CONFIG_STM32H7_RTC_HSECLOCK=y +CONFIG_STM32H7_RTC_MAGIC_REG=1 +CONFIG_STM32H7_SAVE_CRASHDUMP=y +CONFIG_STM32H7_SERIALBRK_BSDCOMPAT=y +CONFIG_STM32H7_SERIAL_DISABLE_REORDERING=y +CONFIG_STM32H7_SPI2=y +CONFIG_STM32H7_SPI2_DMA=y +CONFIG_STM32H7_SPI2_DMA_BUFFER=1024 +CONFIG_STM32H7_TIM12=y +CONFIG_STM32H7_TIM1=y +CONFIG_STM32H7_TIM2=y +CONFIG_STM32H7_TIM3=y +CONFIG_STM32H7_UART7=y +CONFIG_STM32H7_UART8=y +CONFIG_STM32H7_USART3=y +CONFIG_STM32H7_USART_BREAKS=y +CONFIG_STM32H7_USART_INVERT=y +CONFIG_STM32H7_USART_SINGLEWIRE=y +CONFIG_STM32H7_USART_SWAP=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_SYSTEM=y +CONFIG_TASK_NAME_SIZE=24 +CONFIG_TTY_SIGINT=y +CONFIG_TTY_SIGTSTP=y +CONFIG_UART7_BAUD=57600 +CONFIG_UART7_RXBUFSIZE=600 +CONFIG_UART7_TXBUFSIZE=1500 +CONFIG_UART7_RXDMA=y +CONFIG_UART7_TXDMA=y +CONFIG_UART8_BAUD=57600 +CONFIG_UART8_RXBUFSIZE=600 +CONFIG_UART8_SERIAL_CONSOLE=y +CONFIG_UART8_TXBUFSIZE=1500 +CONFIG_USART3_BAUD=57600 +CONFIG_USART3_RXBUFSIZE=600 +CONFIG_USART3_TXBUFSIZE=3000 +CONFIG_USEC_PER_TICK=1000 +CONFIG_WATCHDOG=y diff --git a/boards/cubepilot/cubered-secondary/nuttx-config/scripts/script.ld b/boards/cubepilot/cubered-secondary/nuttx-config/scripts/script.ld new file mode 100644 index 0000000000..671046af8b --- /dev/null +++ b/boards/cubepilot/cubered-secondary/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 STM32H757ZI 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 STM32H757ZI, 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 STM32H757ZI 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 = 1664K /* params in last two sectors */ + + 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/cubepilot/cubered-secondary/src/CMakeLists.txt b/boards/cubepilot/cubered-secondary/src/CMakeLists.txt new file mode 100644 index 0000000000..98e8946f22 --- /dev/null +++ b/boards/cubepilot/cubered-secondary/src/CMakeLists.txt @@ -0,0 +1,63 @@ +############################################################################ +# +# 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. +# +############################################################################ +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 + init.c + spi.cpp + timer_config.cpp + led.c + ) + + target_link_libraries(drivers_board + PRIVATE + arch_io_pins + arch_spi + drivers__led + nuttx_arch + nuttx_drivers + px4_layer + ) +endif() diff --git a/boards/cubepilot/cubered-secondary/src/board_config.h b/boards/cubepilot/cubered-secondary/src/board_config.h new file mode 100644 index 0000000000..fc441be39b --- /dev/null +++ b/boards/cubepilot/cubered-secondary/src/board_config.h @@ -0,0 +1,153 @@ +/**************************************************************************** + * + * 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. + * + ****************************************************************************/ + +/** + * @file board_config.h + * + * Board internal definitions + */ + +#pragma once + +#include +#include +#include +#include + +/** + * If NuttX is built without support for SMPS it can brick the hardware. + * Therefore, we make sure the NuttX headers are correct. + */ +#include "hardware/stm32h7x3xx_pwr.h" +#if STM32_PWR_CR3_SMPSEXTHP != (1 << 3) +# error "No SMPS support in NuttX submodule"; +#endif + + +/* LEDs */ +#define GPIO_nLED_AMBER /* PD10 */ (GPIO_OUTPUT|GPIO_OPENDRAIN|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTD|GPIO_PIN10) +#define GPIO_nLED_SAFETY /* PE5 */ (GPIO_OUTPUT|GPIO_OPENDRAIN|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN5) + +//#define BOARD_HAS_CONTROL_STATUS_LEDS 1 +//#define BOARD_ARMED_LED LED_AMBER + + +/* ADC channels */ +#define PX4_ADC_GPIO \ + /* PA6 */ GPIO_ADC12_INP3, \ + /* PF11 */ GPIO_ADC1_INP2 + +#define ADC_RSSI_IN_CHANNEL 3 +#define ADC_SERVO_SENSE_CHANNEL 2 + +#define ADC_CHANNELS \ + ((1 << ADC_RSSI_IN_CHANNEL) | \ + (1 << ADC_SERVO_SENSE_CHANNEL)) + +/* HW has to large of R termination on ADC todo:change when HW value is chosen */ +#define BOARD_ADC_OPEN_CIRCUIT_V (5.6f) + +/* PWM */ +// For now, just support the basic 8 output channels, see timer_config.cpp for the rest. +#define DIRECT_PWM_OUTPUT_CHANNELS 8 + +/* Power supply control and monitoring GPIOs */ +#define BOARD_NUMBER_BRICKS 2 +#define GPIO_VDD_BRICK1_VALID /* PG0 */ (GPIO_INPUT|GPIO_PULLUP|GPIO_PORTG|GPIO_PIN0) +#define GPIO_VDD_BRICK2_VALID /* PG5 */ (GPIO_INPUT|GPIO_PULLUP|GPIO_PORTG|GPIO_PIN5) // Backup + + +/* 3 timers for PWM out */ +#define BOARD_NUM_IO_TIMERS 5 + +/* High-resolution timer */ +#define HRT_TIMER 12 /* use timer12 for the HRT */ +#define HRT_TIMER_CHANNEL 1 /* use capture/compare channel 1 */ + +#define BOARD_ADC_BRICK1_VALID (px4_arch_gpioread(GPIO_VDD_BRICK1_VALID)) +#define BOARD_ADC_BRICK2_VALID (px4_arch_gpioread(GPIO_VDD_BRICK2_VALID)) + +/* 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 + +/* Debug GPIOs for testing - PC7 for UART IDLE debugging */ +#define GPIO_UART_IDLE_DEBUG (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_CLEAR|GPIO_PORTC|GPIO_PIN7) // PC7 +//#define GPIO_UART_IDLE_DEBUG_READ (GPIO_INPUT|GPIO_FLOAT|GPIO_PORTA|GPIO_PIN3) + + +// #define GPIO_VOLT_SET (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTG|GPIO_PIN1) + +// PWM Direction Control - CRITICAL: Must match hardware requirements! +// For driving Opto's (unidirectional output): BIDIR=LOW, UNIDIR=HIGH +// For bidirectional with input monitoring: BIDIR=HIGH, UNIDIR=LOW +// DANGER: Never enable both simultaneously - will damage hardware! +// +// Current config: Unidirectional mode (matches ArduPilot) +// PB0 BIDIR_ENABLED OUTPUT LOW GPIO(4) +// PA7 HP_UNIDIR_ENABLED OUTPUT HIGH GPIO(5) +#define GPIO_BIDIR_DISABLED (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_CLEAR|GPIO_PORTB|GPIO_PIN0) +#define GPIO_UNIDIR_ENABLED (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTA|GPIO_PIN7) + + +//#define BOARD_HAS_STATIC_MANIFEST 1 + +/* There is no FRAM/EEPROM */ +#define FLASH_BASED_PARAMS + +#define BOARD_ENABLE_CONSOLE_BUFFER + +#define PX4_GPIO_INIT_LIST { \ + PX4_ADC_GPIO, \ + GPIO_CAN1_TX, \ + GPIO_CAN1_RX, \ + GPIO_CAN2_TX, \ + GPIO_CAN2_RX, \ + GPIO_VDD_BRICK1_VALID, \ + GPIO_VDD_BRICK2_VALID, \ + GPIO_UART_IDLE_DEBUG, \ + GPIO_BIDIR_DISABLED, \ + GPIO_UNIDIR_ENABLED, \ + } + +__BEGIN_DECLS +#ifndef __ASSEMBLY__ + +extern void stm32_spiinitialize(void); +extern void board_peripheral_reset(int ms); + +#include +#endif /* __ASSEMBLY__ */ +__END_DECLS diff --git a/boards/cubepilot/cubered-secondary/src/hw_config.h b/boards/cubepilot/cubered-secondary/src/hw_config.h new file mode 100644 index 0000000000..a43ebadd31 --- /dev/null +++ b/boards/cubepilot/cubered-secondary/src/hw_config.h @@ -0,0 +1,135 @@ +/**************************************************************************** + * + * 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 + +/**************************************************************************** + * 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 1069 +#define _FLASH_KBYTES (*(uint32_t *)0x1FF1E880) +#define BOARD_FLASH_SECTORS (14) +#define BOARD_FLASH_SIZE (_FLASH_KBYTES * 1024) + +#define OSC_FREQ 24 + +#define BOARD_PIN_LED_ACTIVITY GPIO_nLED_AMBER +#define BOARD_PIN_LED_BOOTLOADER GPIO_nLED_AMBER +#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/cubepilot/cubered-secondary/src/init.c b/boards/cubepilot/cubered-secondary/src/init.c new file mode 100644 index 0000000000..3adbafc9a7 --- /dev/null +++ b/boards/cubepilot/cubered-secondary/src/init.c @@ -0,0 +1,194 @@ +/**************************************************************************** + * + * 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. + * + ****************************************************************************/ + +/** + * @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 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 + +#include + +__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) +{ +} + +/************************************************************************************ + * 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))); + } + + if (status >= 0) { + up_mdelay(6); + } +} + +/************************************************************************************ + * 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 pins */ + const uint32_t gpio[] = PX4_GPIO_INIT_LIST; + px4_gpio_init(gpio, arraySize(gpio)); + board_control_spi_sensors_power_configgpio(); + + /* configure LEDs */ + board_autoled_initialize(); +} + +/**************************************************************************** + * 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) +{ + /* Power on Interfaces */ + board_control_spi_sensors_power(true, 0xffff); + + px4_platform_init(); + + stm32_spiinitialize(); + + /* 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_AMBER); + led_off(LED_SAFETY); + + if (board_hardfault_init(2, true) != 0) { + led_on(LED_AMBER); + } + +#if defined(FLASH_BASED_PARAMS) + static sector_descriptor_t params_sector_map[] = { + {14, 128 * 1024, 0x081C0000}, + //{2, 32 * 1024, 0x081C8000}, -> MTD + {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_AMBER); + return result; + } + +#endif /* FLASH_BASED_PARAMS */ + + /* Configure the HW based on the manifest */ + + px4_platform_configure(); + + return OK; +} diff --git a/boards/cubepilot/cubered-secondary/src/led.c b/boards/cubepilot/cubered-secondary/src/led.c new file mode 100644 index 0000000000..8187109bc3 --- /dev/null +++ b/boards/cubepilot/cubered-secondary/src/led.c @@ -0,0 +1,111 @@ +/**************************************************************************** + * + * 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. + * + ****************************************************************************/ + +/** + * @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_AMBER, + GPIO_nLED_SAFETY, +}; + +__EXPORT void led_init(void) +{ + 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/cubepilot/cubered-secondary/src/spi.cpp b/boards/cubepilot/cubered-secondary/src/spi.cpp new file mode 100644 index 0000000000..2bfbc95dea --- /dev/null +++ b/boards/cubepilot/cubered-secondary/src/spi.cpp @@ -0,0 +1,45 @@ +/**************************************************************************** + * + * 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 + +constexpr px4_spi_bus_t px4_spi_buses[SPI_BUS_MAX_BUS_ITEMS] = { + initSPIBus(SPI::Bus::SPI2, { + initSPIDevice(DRV_IMU_DEVTYPE_ICM42688P, SPI::CS{GPIO::PortB, GPIO::Pin12}), + initSPIDevice(DRV_IMU_DEVTYPE_ICM45686, SPI::CS{GPIO::PortB, GPIO::Pin12}), + }), +}; + +static constexpr bool unused = validateSPIConfig(px4_spi_buses); diff --git a/boards/cubepilot/cubered-secondary/src/timer_config.cpp b/boards/cubepilot/cubered-secondary/src/timer_config.cpp new file mode 100644 index 0000000000..dada2f380f --- /dev/null +++ b/boards/cubepilot/cubered-secondary/src/timer_config.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** + * + * 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 + +// CubeRed Secondary IO Board - 8 PWM output channels +// +// Hardware design: Each PWM output has dual timer pins routed through level shifters +// with direction control via PA7 (unidirectional enable) and PB0 (bidirectional enable). +// +// Active timers: +// - Timer1 CH1-4: PWM outputs 1-4 (PA8, PA9, PA10, PA11) +// - Timer2 CH1-4: PWM outputs 5-8 (PA5, PA1, PB10, PB11) +// +// Inactive timers (commented below): +// - Timer3/4/5: Alternative timer pins for PWM monitoring in bidirectional mode +// These are not currently used, but kept for potential future bidirectional support. + + +constexpr io_timers_t io_timers[MAX_IO_TIMERS] = { + initIOTimer(Timer::Timer1, DMA{DMA::Index2}), + initIOTimer(Timer::Timer2, DMA{DMA::Index2}), + //initIOTimer(Timer::Timer3), + //initIOTimer(Timer::Timer4), + //initIOTimer(Timer::Timer5), +}; + +constexpr timer_io_channels_t timer_io_channels[MAX_TIMER_IO_CHANNELS] = { + initIOTimerChannel(io_timers, {Timer::Timer1, Timer::Channel1}, {GPIO::PortA, GPIO::Pin8}), + initIOTimerChannel(io_timers, {Timer::Timer1, Timer::Channel2}, {GPIO::PortA, GPIO::Pin9}), + initIOTimerChannel(io_timers, {Timer::Timer1, Timer::Channel3}, {GPIO::PortA, GPIO::Pin10}), + initIOTimerChannel(io_timers, {Timer::Timer1, Timer::Channel4}, {GPIO::PortA, GPIO::Pin11}), + initIOTimerChannel(io_timers, {Timer::Timer2, Timer::Channel1}, {GPIO::PortA, GPIO::Pin5}), + initIOTimerChannel(io_timers, {Timer::Timer2, Timer::Channel2}, {GPIO::PortA, GPIO::Pin1}), + initIOTimerChannel(io_timers, {Timer::Timer2, Timer::Channel3}, {GPIO::PortB, GPIO::Pin10}), + initIOTimerChannel(io_timers, {Timer::Timer2, Timer::Channel4}, {GPIO::PortB, GPIO::Pin11}), + // Alternative timer channels for potential bidirectional PWM monitoring: + //initIOTimerChannel(io_timers, {Timer::Timer3, Timer::Channel4}, {GPIO::PortC, GPIO::Pin9}), + //initIOTimerChannel(io_timers, {Timer::Timer4, Timer::Channel1}, {GPIO::PortD, GPIO::Pin12}), + //initIOTimerChannel(io_timers, {Timer::Timer4, Timer::Channel2}, {GPIO::PortB, GPIO::Pin7}), + //initIOTimerChannel(io_timers, {Timer::Timer4, Timer::Channel3}, {GPIO::PortD, GPIO::Pin14}), + //initIOTimerChannel(io_timers, {Timer::Timer4, Timer::Channel4}, {GPIO::PortB, GPIO::Pin9}), + //initIOTimerChannel(io_timers, {Timer::Timer5, Timer::Channel1}, {GPIO::PortA, GPIO::Pin0}), + //initIOTimerChannel(io_timers, {Timer::Timer5, Timer::Channel3}, {GPIO::PortA, GPIO::Pin2}), + //initIOTimerChannel(io_timers, {Timer::Timer5, Timer::Channel4}, {GPIO::PortA, GPIO::Pin3}), +}; + +constexpr io_timers_channel_mapping_t io_timers_channel_mapping = + initIOTimerChannelMapping(io_timers, timer_io_channels); diff --git a/src/drivers/cubered_bridge/Kconfig b/src/drivers/cubered_bridge/Kconfig new file mode 100644 index 0000000000..13e0fd6ddc --- /dev/null +++ b/src/drivers/cubered_bridge/Kconfig @@ -0,0 +1,3 @@ +menu "CubeRed bridge" + rsource "*/Kconfig" +endmenu diff --git a/src/drivers/cubered_bridge/primary/CMakeLists.txt b/src/drivers/cubered_bridge/primary/CMakeLists.txt new file mode 100644 index 0000000000..453f90158c --- /dev/null +++ b/src/drivers/cubered_bridge/primary/CMakeLists.txt @@ -0,0 +1,49 @@ +############################################################################ +# +# 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__cubered_bridge_primary + MAIN cubered_bridge_primary + COMPILE_FLAGS + -Wno-cast-align # TODO: fix and enable + SRCS + cubered_bridge_primary.cpp + cubered_bridge_primary_serial.cpp + MODULE_CONFIG + module.yaml + cubered_bridge_primary_params.yaml + DEPENDS + arch_px4io_serial + button_publisher + circuit_breaker + mixer_module + ) diff --git a/src/drivers/cubered_bridge/primary/Kconfig b/src/drivers/cubered_bridge/primary/Kconfig new file mode 100644 index 0000000000..f13fd2a062 --- /dev/null +++ b/src/drivers/cubered_bridge/primary/Kconfig @@ -0,0 +1,8 @@ +menuconfig DRIVERS_CUBERED_BRIDGE_PRIMARY + bool "cubered_bridge_primary" + default n + depends on PLATFORM_NUTTX + ---help--- + Enable the CubeRed bridge driver running on the primary MCU. + Talks over the IO serial link to the cubered_bridge_secondary + running on the secondary MCU, using the PX4IO register protocol. diff --git a/src/drivers/cubered_bridge/primary/cubered_bridge_primary.cpp b/src/drivers/cubered_bridge/primary/cubered_bridge_primary.cpp new file mode 100644 index 0000000000..50f12e608d --- /dev/null +++ b/src/drivers/cubered_bridge/primary/cubered_bridge_primary.cpp @@ -0,0 +1,1584 @@ +/**************************************************************************** + * + * Copyright (c) 2012-2022 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file px4io.cpp + * Driver for the CuberedBridgePrimary board. + * + * CuberedBridgePrimary is connected via DMA enabled high-speed UART. + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "modules/dataman/dataman.h" + +#include "cubered_bridge_primary_driver.h" + +#define PX4IO_SET_DEBUG _IOC(0xff00, 0) + +static constexpr unsigned MIN_TOPIC_UPDATE_INTERVAL = 2500; // 2.5 ms -> 400 Hz + +using namespace time_literals; + +/** + * The CuberedBridgePrimary class. + * + * Encapsulates PX4FMU to CuberedBridgePrimary communications modeled as file operations. + */ +class CuberedBridgePrimary : public cdev::CDev, public ModuleBase, public OutputModuleInterface +{ +public: + static Descriptor desc; + + /** + * Constructor. + * + * Initialize all class variables. + */ + CuberedBridgePrimary() = delete; + explicit CuberedBridgePrimary(device::Device *interface); + + ~CuberedBridgePrimary() override; + + /** + * Initialize the CuberedBridgePrimary class. + * + * Retrieve relevant initial system parameters. Initialize CuberedBridgePrimary registers. + */ + int init() override; + + /** + * IO Control handler. + * + * Handle all IOCTL calls to the CuberedBridgePrimary file descriptor. + * + * @param[in] filp file handle (not used). This function is always called directly through object reference + * @param[in] cmd the IOCTL command + * @param[in] the IOCTL command parameter (optional) + */ + int ioctl(file *filp, int cmd, unsigned long arg) override; + + /** + * Print IO status. + * + * Print all relevant IO status information + * + */ + int print_status(); + + static int custom_command(int argc, char *argv[]); + + static int print_usage(const char *reason = nullptr); + + static int task_spawn(int argc, char *argv[]); + + /* + * To test what happens if IO stops receiving updates from FMU. + * + * @param is_fail true for failure condition, false for normal operation. + */ + void test_fmu_fail(bool is_fail) { _test_fmu_fail = is_fail; }; + + uint16_t system_status() const { return _status; } + + bool updateOutputs(float outputs[MAX_ACTUATORS], unsigned num_outputs, unsigned num_control_groups_updated) override; + +private: + void Run() override; + + void updateDisarmed(); + void updateFailsafe(); + void updateTimerRateGroups(); + + static int bind(int argc, char *argv[]); + + static constexpr int PX4IO_MAX_ACTUATORS = 8; + + device::Device *const _interface; + + uint16_t _hardware{0}; ///< Hardware revision + uint16_t _max_actuators{0}; ///< Maximum # of actuators supported by CuberedBridgePrimary + uint16_t _max_controls{0}; ///< Maximum # of controls supported by CuberedBridgePrimary + uint16_t _max_rc_input{0}; ///< Maximum receiver channels supported by CuberedBridgePrimary + uint16_t _max_transfer{16}; ///< Maximum number of I2C transfers supported by CuberedBridgePrimary + + uint16_t _group_channels[PX4IO_P_SETUP_PWM_RATE_GROUP3 - PX4IO_P_SETUP_PWM_RATE_GROUP0 + 1] {}; + + bool _first_update_cycle{true}; + + hrt_abstime _poll_last{0}; + + orb_advert_t _mavlink_log_pub{nullptr}; ///< mavlink log pub + + perf_counter_t _cycle_perf{perf_alloc(PC_ELAPSED, MODULE_NAME": cycle")}; + perf_counter_t _interval_perf{perf_alloc(PC_INTERVAL, MODULE_NAME": interval")}; + perf_counter_t _interface_read_perf{perf_alloc(PC_ELAPSED, MODULE_NAME": interface read")}; + perf_counter_t _interface_write_perf{perf_alloc(PC_ELAPSED, MODULE_NAME": interface write")}; + + /* cached IO state */ + uint16_t _status{0}; ///< Various IO status flags + uint16_t _alarms{0}; ///< Various IO alarms + uint16_t _setup_arming{0}; ///< last arming setup state + uint16_t _last_written_arming_s{0}; ///< the last written arming state reg + uint16_t _last_written_arming_c{0}; ///< the last written arming state reg + + uORB::Subscription _t_actuator_armed{ORB_ID(actuator_armed)}; ///< system armed control topic + uORB::Subscription _t_vehicle_command{ORB_ID(vehicle_command)}; ///< vehicle command topic + uORB::Subscription _t_vehicle_status{ORB_ID(vehicle_status)}; ///< vehicle status topic + + uORB::SubscriptionInterval _parameter_update_sub{ORB_ID(parameter_update), 1_s}; + + hrt_abstime _last_status_publish{0}; + + uint16_t _rc_valid_update_count{0}; + + bool _param_update_force{true}; ///< force a parameter update + bool _timer_rates_configured{false}; + + /* advertised topics */ + uORB::PublicationMulti _input_rc_pub{ORB_ID(input_rc)}; + uORB::Publication _px4io_status_pub{ORB_ID(px4io_status)}; + + ButtonPublisher _button_publisher; + bool _previous_safety_off{false}; + + bool _lockdown_override{false}; ///< override the safety lockdown + + int32_t _thermal_control{-1}; ///< thermal control state + bool _analog_rc_rssi_stable{false}; ///< true when analog RSSI input is stable + float _analog_rc_rssi_volt{-1.f}; ///< analog RSSI voltage + + bool _test_fmu_fail{false}; ///< To test what happens if IO loses FMU + bool _in_test_mode{false}; ///< true if PWM_SERVO_ENTER_TEST_MODE is active + + MixingOutput _mixing_output{"PWM_MAIN", PX4IO_MAX_ACTUATORS, *this, MixingOutput::SchedulingPolicy::Auto, true}; + + bool _pwm_min_configured{false}; + bool _pwm_max_configured{false}; + bool _pwm_fail_configured{false}; + bool _pwm_dis_configured{false}; + bool _pwm_rev_configured{false}; + + /** + * Update IO's arming-related state + */ + int io_set_arming_state(); + + /** + * Fetch status and alarms from IO + * + * Also publishes battery voltage/current. + */ + int io_get_status(); + + /** + * Fetch RC inputs from IO. + * + * @param input_rc Input structure to populate. + * @return OK if data was returned. + */ + int io_publish_raw_rc(); + + /** + * write registers + * + * @param page Register page to write to. + * @param offset Register offset to start writing at. + * @param values Pointer to array of values to write. + * @param num_values The number of values to write. + * @return OK if all values were successfully written. + */ + int io_regs_set(uint8_t page, uint8_t offset, const uint16_t *values, unsigned num_values); + + /** + * write a register + * + * @param page Register page to write to. + * @param offset Register offset to write to. + * @param value Value to write. + * @return OK if the value was written successfully. + */ + int io_reg_set(uint8_t page, uint8_t offset, uint16_t value); + + /** + * read registers + * + * @param page Register page to read from. + * @param offset Register offset to start reading from. + * @param values Pointer to array where values should be stored. + * @param num_values The number of values to read. + * @return OK if all values were successfully read. + */ + int io_regs_get(uint8_t page, uint8_t offset, uint16_t *values, unsigned num_values); + + /** + * read a register + * + * @param page Register page to read from. + * @param offset Register offset to start reading from. + * @param value Read register value. + * @return Ok if read was successful. + */ + int io_reg_get(uint8_t page, uint8_t offset, uint16_t &value); + + /** + * modify a register + * + * @param page Register page to modify. + * @param offset Register offset to modify. + * @param clearbits Bits to clear in the register. + * @param setbits Bits to set in the register. + */ + int io_reg_modify(uint8_t page, uint8_t offset, uint16_t clearbits, uint16_t setbits); + + /** + * Handle a status update from IO. + * + * Publish IO status information if necessary. + * + * @param status The status register + */ + int io_handle_status(uint16_t status); + + /** + * Handle issuing dsm bind ioctl to px4io. + * + * @param dsmMode DSM2_BIND_PULSES, DSMX_BIND_PULSES, DSMX8_BIND_PULSES + */ + int dsm_bind_ioctl(int dsmMode); + + /** + * Respond to a vehicle command with an ACK message + * + * @param cmd The command that was executed or denied (inbound) + * @param result The command result + */ + void answer_command(const vehicle_command_s &cmd, uint8_t result); + + void update_params(); + + DEFINE_PARAMETERS( + (ParamInt) _param_pwm_sbus_mode, + (ParamInt) _param_rc_rssi_pwm_chan, + (ParamInt) _param_rc_rssi_pwm_max, + (ParamInt) _param_rc_rssi_pwm_min, + (ParamInt) _param_sens_en_themal + ) +}; + +ModuleBase::Descriptor CuberedBridgePrimary::desc{task_spawn, custom_command, print_usage}; + +#define PX4IO_DEVICE_PATH "/dev/px4io" + +CuberedBridgePrimary::CuberedBridgePrimary(device::Device *interface) : + CDev(PX4IO_DEVICE_PATH), + OutputModuleInterface(MODULE_NAME, px4::serial_port_to_wq(PX4IO_SERIAL_DEVICE)), + _interface(interface) +{ + _mixing_output.setLowrateSchedulingInterval(20_ms); +} + +CuberedBridgePrimary::~CuberedBridgePrimary() +{ + delete _interface; + + /* deallocate perfs */ + perf_free(_cycle_perf); + perf_free(_interval_perf); + perf_free(_interface_read_perf); + perf_free(_interface_write_perf); +} + +bool CuberedBridgePrimary::updateOutputs(float outputs[MAX_ACTUATORS], unsigned num_outputs, unsigned num_control_groups_updated) +{ + uint16_t hw_outputs[MAX_ACTUATORS] {}; + + for (size_t i = 0; i < num_outputs; i++) { + if (!_mixing_output.isFunctionSet(i)) { + // do not run any signal on disabled channels + outputs[i] = 0; + } + + hw_outputs[i] = static_cast(lroundf(outputs[i])); + } + + if (!_test_fmu_fail) { + /* output to the servos */ + io_regs_set(PX4IO_PAGE_DIRECT_PWM, 0, hw_outputs, num_outputs); + } + + return true; +} + +int CuberedBridgePrimary::init() +{ + SmartLock lock_guard(_lock); + + /* do regular cdev init */ + int ret = CDev::init(); + + if (ret != OK) { + PX4_ERR("init failed %d", ret); + return ret; + } + + /* get some parameters */ + uint16_t protocol; + hrt_abstime start_try_time = hrt_absolute_time(); + + do { + px4_usleep(2000); + ret = io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_PROTOCOL_VERSION, protocol); + } while (ret != OK && (hrt_elapsed_time(&start_try_time) < 700U * 1000U)); + + /* if the error still persists after timing out, we give up */ + if (ret != OK) { + mavlink_log_emergency(&_mavlink_log_pub, "Failed to communicate with IO, abort.\t"); + events::send(events::ID("px4io_comm_failed"), events::Log::Emergency, + "Failed to communicate with IO, aborting initialization"); + return -1; + } + + if (protocol != PX4IO_PROTOCOL_VERSION) { + mavlink_log_emergency(&_mavlink_log_pub, "IO protocol/firmware mismatch, abort.\t"); + events::send(events::ID("px4io_proto_fw_mismatch"), events::Log::Emergency, + "IO protocol/firmware mismatch, aborting initialization"); + return -1; + } + + io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_HARDWARE_VERSION, _hardware); + io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_ACTUATOR_COUNT, _max_actuators); + io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_CONTROL_COUNT, _max_controls); + io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_MAX_TRANSFER, _max_transfer); + _max_transfer -= 2; + io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_RC_INPUT_COUNT, _max_rc_input); + + if ((_max_actuators < 1) || (_max_actuators > PX4IO_MAX_ACTUATORS) || + (_max_transfer < 16) || (_max_transfer > 255) || + (_max_rc_input < 1) || (_max_rc_input > 255)) { + + PX4_ERR("config read error"); + mavlink_log_emergency(&_mavlink_log_pub, "[IO] config read fail, abort.\t"); + events::send(events::ID("px4io_config_read_failed"), events::Log::Emergency, + "IO config read failed, aborting initialization"); + + // ask IO to reboot into bootloader as the failure may + // be due to mismatched firmware versions and we want + // the startup script to be able to load a new IO + // firmware + + // Now the reboot into bootloader mode should succeed. + io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_REBOOT_BL, PX4IO_REBOOT_BL_MAGIC); + return -1; + } + + + /* Set safety_off to false when FMU boot*/ + ret = io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_SAFETY_OFF, 0); + + if (ret != OK) { + return -1; + } + + if (_max_rc_input > input_rc_s::RC_INPUT_MAX_CHANNELS) { + _max_rc_input = input_rc_s::RC_INPUT_MAX_CHANNELS; + } + + uint16_t reg = 0; + + /* get IO's last seen FMU state */ + ret = io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING, reg); + + if (ret != OK) { + return ret; + } + + /* dis-arm IO before touching anything */ + ret = io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING, + PX4IO_P_SETUP_ARMING_FMU_ARMED | PX4IO_P_SETUP_ARMING_LOCKDOWN, + 0); + + if (ret != OK) { + mavlink_log_critical(&_mavlink_log_pub, "IO RC config upload fail\t"); + events::send(events::ID("px4io_io_rc_config_upload_failed"), events::Log::Critical, + "IO RC config upload failed, aborting initialization"); + return ret; + } + + /* initialize _group_channels */ + for (uint8_t group = PX4IO_P_SETUP_PWM_RATE_GROUP0; group <= PX4IO_P_SETUP_PWM_RATE_GROUP3; ++group) { + unsigned group_idx = group - PX4IO_P_SETUP_PWM_RATE_GROUP0; + ret = io_reg_get(PX4IO_PAGE_PWM_INFO, PX4IO_RATE_MAP_BASE + group_idx, _group_channels[group_idx]); + + if (ret != OK) { + return -1; + } + } + + /* try to claim the generic PWM output device node as well - it's OK if we fail at this */ + _mixing_output.setMaxTopicUpdateRate(MIN_TOPIC_UPDATE_INTERVAL); + + _px4io_status_pub.advertise(); + + update_params(); + + ScheduleNow(); + + return OK; +} + +void CuberedBridgePrimary::updateDisarmed() +{ + uint16_t values[PX4IO_MAX_ACTUATORS] {}; + + for (unsigned i = 0; i < _max_actuators; i++) { + values[i] = _mixing_output.disarmedValue(i); + } + + io_regs_set(PX4IO_PAGE_DISARMED_PWM, 0, values, _max_actuators); +} + +void CuberedBridgePrimary::updateFailsafe() +{ + uint16_t values[PX4IO_MAX_ACTUATORS] {}; + + for (unsigned i = 0; i < _max_actuators; i++) { + values[i] = static_cast(lroundf(_mixing_output.actualFailsafeValue(i))); + } + + io_regs_set(PX4IO_PAGE_FAILSAFE_PWM, 0, values, _max_actuators); +} + +void CuberedBridgePrimary::Run() +{ + if (should_exit()) { + ScheduleClear(); + _mixing_output.unregister(); + + exit_and_cleanup(desc); + return; + } + + SmartLock lock_guard(_lock); + + perf_begin(_cycle_perf); + perf_count(_interval_perf); + + /* if we have new control data from the ORB, handle it */ + _mixing_output.update(); + + if (hrt_elapsed_time(&_poll_last) >= 20_ms) { + /* run at 50 */ + _poll_last = hrt_absolute_time(); + + /* pull status and alarms from IO */ + io_get_status(); + + /* get raw R/C input from IO */ + io_publish_raw_rc(); + } + + /* check updates on uORB topics and handle it */ + if (_t_actuator_armed.updated()) { + io_set_arming_state(); + + // TODO: throttle + } + + if (!_mixing_output.armed().armed) { + /* vehicle command */ + if (_t_vehicle_command.updated()) { + vehicle_command_s cmd{}; + _t_vehicle_command.copy(&cmd); + + // Check for a DSM pairing command + if (((unsigned int)cmd.command == vehicle_command_s::VEHICLE_CMD_START_RX_PAIR) && ((int)cmd.param1 == 0)) { + int bind_arg; + + switch ((int)cmd.param2) { + case 0: + bind_arg = DSM2_BIND_PULSES; + break; + + case 1: + bind_arg = DSMX_BIND_PULSES; + break; + + case 2: + default: + bind_arg = DSMX8_BIND_PULSES; + break; + } + + int dsm_ret = dsm_bind_ioctl(bind_arg); + + /* publish ACK */ + if (dsm_ret == OK) { + answer_command(cmd, vehicle_command_ack_s::VEHICLE_CMD_RESULT_ACCEPTED); + + } else { + answer_command(cmd, vehicle_command_ack_s::VEHICLE_CMD_RESULT_FAILED); + } + } + } + + /* + * If parameters have changed, re-send RC mappings to IO + */ + + // check for parameter updates + if (_parameter_update_sub.updated() || _param_update_force) { + // clear update + parameter_update_s pupdate; + _parameter_update_sub.copy(&pupdate); + + _param_update_force = false; + + update_params(); + + /* Check if the flight termination circuit breaker has been updated */ + bool disable_flighttermination = circuit_breaker_enabled("CBRK_FLIGHTTERM", CBRK_FLIGHTTERM_KEY); + /* Tell IO that it can terminate the flight if FMU is not responding or if a failure has been reported by the FailureDetector logic */ + io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ENABLE_FLIGHTTERMINATION, !disable_flighttermination); + + if (_param_sens_en_themal.get() != _thermal_control || _param_update_force) { + + _thermal_control = _param_sens_en_themal.get(); + /* set power management state for thermal */ + uint16_t tctrl; + + if (_thermal_control < 0) { + tctrl = PX4IO_THERMAL_IGNORE; + + } else { + tctrl = PX4IO_THERMAL_OFF; + } + + io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_THERMAL, tctrl); + } + + /* S.BUS output */ + if (_param_pwm_sbus_mode.get() == 1) { + /* enable S.BUS 1 */ + io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_FEATURES, 0, PX4IO_P_SETUP_FEATURES_SBUS1_OUT); + + } else if (_param_pwm_sbus_mode.get() == 2) { + /* enable S.BUS 2 */ + io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_FEATURES, 0, PX4IO_P_SETUP_FEATURES_SBUS2_OUT); + + } else { + /* disable S.BUS */ + io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_FEATURES, + (PX4IO_P_SETUP_FEATURES_SBUS1_OUT | PX4IO_P_SETUP_FEATURES_SBUS2_OUT), 0); + } + } + } + + // minimal backup scheduling + ScheduleDelayed(20_ms); + + // check at end of cycle (updateSubscriptions() can potentially change to a different WorkQueue thread) + _mixing_output.updateSubscriptions(true); + + perf_end(_cycle_perf); + _first_update_cycle = false; +} + +void CuberedBridgePrimary::updateTimerRateGroups() +{ + if (_timer_rates_configured) { // avoid setting timer rates on each param update + return; + } + + _timer_rates_configured = true; + + int timer = 0; + + uint16_t timer_rates[PX4IO_P_SETUP_PWM_RATE_GROUP3 - PX4IO_P_SETUP_PWM_RATE_GROUP0 + 1] {}; + + for (uint8_t offset = PX4IO_P_SETUP_PWM_RATE_GROUP0; offset <= PX4IO_P_SETUP_PWM_RATE_GROUP3; ++offset) { + char param_name[17]; + snprintf(param_name, sizeof(param_name), "%s_TIM%u", _mixing_output.paramPrefix(), timer); + + int32_t tim_config = 0; + param_t handle = param_find(param_name); + + if (handle == PARAM_INVALID) { + break; + } + + param_get(handle, &tim_config); + + if (tim_config > 0) { + timer_rates[timer] = tim_config; + + } else if (tim_config == -1) { // OneShot + timer_rates[timer] = 0; + } + + ++timer; + } + + int ret = io_regs_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_PWM_RATE_GROUP0, timer_rates, timer); + + if (ret != 0) { + PX4_ERR("io_reg_set failed (%i)", ret); + } +} + +void CuberedBridgePrimary::update_params() +{ + uint32_t previously_set_functions = 0; + + for (size_t i = 0; i < _max_actuators; i++) { + previously_set_functions |= (uint32_t)_mixing_output.isFunctionSet(i) << i; + } + + updateParams(); + + if (!_mixing_output.armed().armed) { + + // Automatically set the PWM rate and disarmed value when a channel is first set to a servo + if (!_first_update_cycle) { + for (size_t i = 0; i < _max_actuators; i++) { + if ((previously_set_functions & (1u << i)) == 0 && _mixing_output.functionParamHandle(i) != PARAM_INVALID) { + int32_t output_function; + + if (param_get(_mixing_output.functionParamHandle(i), &output_function) == 0) { + if (output_function >= (int)OutputFunction::Servo1 + && output_function <= (int)OutputFunction::ServoMax) { // Function got set to a servo + int32_t val = 1500; + PX4_INFO("Setting channel %i disarmed to %i", (int)i + 1, (int)val); + param_set(_mixing_output.disarmedParamHandle(i), &val); + + // If the whole timer group was not set previously, then set the pwm rate to 50 Hz + for (int timer = 0; timer < (int)(sizeof(_group_channels) / sizeof(_group_channels[0])); ++timer) { + + uint32_t channels = _group_channels[timer]; + + if ((channels & (1u << i)) == 0) { + continue; + } + + if ((channels & previously_set_functions) == 0) { // None of the channels was set + char param_name[17]; + snprintf(param_name, sizeof(param_name), "%s_TIM%u", _mixing_output.paramPrefix(), timer); + + int32_t tim_config = 0; + param_t handle = param_find(param_name); + + if (param_get(handle, &tim_config) == 0 && tim_config == 400) { + tim_config = 50; + PX4_INFO("Setting timer %i to %i Hz", timer, (int)tim_config); + param_set(handle, &tim_config); + } + } + } + } + + // Motors need a minimum value that idles the motor + if (output_function >= (int)OutputFunction::Motor1 + && output_function <= (int)OutputFunction::MotorMax) { // Function got set to a motor + int32_t val = 1100; + PX4_INFO("Setting channel %i minimum to %i", (int)i + 1, (int)val); + param_set(_mixing_output.minParamHandle(i), &val); + val = 1900; + PX4_INFO("Setting channel %i maximum to %i", (int)i + 1, (int)val); + param_set(_mixing_output.maxParamHandle(i), &val); + } + } + } + } + } + + // sync params to IO + updateTimerRateGroups(); + updateFailsafe(); + updateDisarmed(); + } +} + +void CuberedBridgePrimary::answer_command(const vehicle_command_s &cmd, uint8_t result) +{ + /* publish ACK */ + uORB::Publication vehicle_command_ack_pub{ORB_ID(vehicle_command_ack)}; + vehicle_command_ack_s command_ack{}; + command_ack.command = cmd.command; + command_ack.result = result; + command_ack.target_system = cmd.source_system; + command_ack.target_component = cmd.source_component; + command_ack.timestamp = hrt_absolute_time(); + vehicle_command_ack_pub.publish(command_ack); +} + +int +CuberedBridgePrimary::io_set_arming_state() +{ + uint16_t set = 0; + uint16_t clear = 0; + + actuator_armed_s armed; + + if (_t_actuator_armed.copy(&armed)) { + if (armed.armed || armed.in_esc_calibration_mode) { + set |= PX4IO_P_SETUP_ARMING_FMU_ARMED; + + } else { + clear |= PX4IO_P_SETUP_ARMING_FMU_ARMED; + } + + if (armed.prearmed) { + set |= PX4IO_P_SETUP_ARMING_FMU_PREARMED; + + } else { + clear |= PX4IO_P_SETUP_ARMING_FMU_PREARMED; + } + + if ((armed.lockdown || armed.kill) && !_lockdown_override) { + set |= PX4IO_P_SETUP_ARMING_LOCKDOWN; + _lockdown_override = true; + + } else if (!(armed.lockdown || armed.kill) && _lockdown_override) { + clear |= PX4IO_P_SETUP_ARMING_LOCKDOWN; + _lockdown_override = false; + } + + if (armed.termination) { + set |= PX4IO_P_SETUP_ARMING_TERMINATION; + + } else { + clear |= PX4IO_P_SETUP_ARMING_TERMINATION; + } + + if (armed.ready_to_arm) { + set |= PX4IO_P_SETUP_ARMING_IO_ARM_OK; + + } else { + clear |= PX4IO_P_SETUP_ARMING_IO_ARM_OK; + } + } + + if (_last_written_arming_s != set || _last_written_arming_c != clear) { + _last_written_arming_s = set; + _last_written_arming_c = clear; + return io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING, clear, set); + } + + return 0; +} + +int CuberedBridgePrimary::io_handle_status(uint16_t status) +{ + int ret = 1; + /** + * WARNING: This section handles in-air resets. + */ + + /* check for IO reset - force it back to armed if necessary */ + if (!(status & PX4IO_P_STATUS_FLAGS_ARM_SYNC)) { + /* set the arming flag */ + ret = io_reg_modify(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_FLAGS, 0, PX4IO_P_STATUS_FLAGS_ARM_SYNC); + + /* set new status */ + _status = status; + + } else if (!(_status & PX4IO_P_STATUS_FLAGS_ARM_SYNC)) { + + /* set the sync flag */ + ret = io_reg_modify(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_FLAGS, 0, PX4IO_P_STATUS_FLAGS_ARM_SYNC); + /* set new status */ + _status = status; + + } else { + ret = 0; + + /* set new status */ + _status = status; + } + + /** + * Get and handle the safety button status + */ + const bool safety_button_pressed = status & PX4IO_P_STATUS_FLAGS_SAFETY_BUTTON_EVENT; + + if (safety_button_pressed) { + io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_SAFETY_BUTTON_ACK, 0); + _button_publisher.safetyButtonTriggerEvent(); + } + + /** + * Inform CuberedBridgePrimary board about safety_off state for LED control + */ + vehicle_status_s vehicle_status; + + if (_t_vehicle_status.update(&vehicle_status)) { + if (_previous_safety_off != vehicle_status.safety_off) { + io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_SAFETY_OFF, vehicle_status.safety_off); + _previous_safety_off = vehicle_status.safety_off; + } + } + + return ret; +} + +int CuberedBridgePrimary::dsm_bind_ioctl(int dsmMode) +{ + // Do not bind if invalid pulses are provided + if (dsmMode != DSM2_BIND_PULSES && + dsmMode != DSMX_BIND_PULSES && + dsmMode != DSMX8_BIND_PULSES) { + PX4_ERR("Unknown DSM mode: %d", dsmMode); + return -EINVAL; + } + + // Do not bind if armed + bool armed = (_status & PX4IO_P_SETUP_ARMING_FMU_ARMED); + + if (armed) { + PX4_ERR("Not binding DSM, system is armed."); + return -EINVAL; + } + + PX4_INFO("Binding DSM%s RX", (dsmMode == DSM2_BIND_PULSES) ? "2" : ((dsmMode == DSMX_BIND_PULSES) ? "-X" : "-X8")); + + int ret = OK; + ret |= io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_DSM, dsm_bind_power_down); + px4_usleep(500000); + ret |= io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_DSM, dsm_bind_set_rx_out); + ret |= io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_DSM, dsm_bind_power_up); + px4_usleep(72000); + ret |= io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_DSM, dsm_bind_send_pulses | (dsmMode << 4)); + px4_usleep(50000); + ret |= io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_DSM, dsm_bind_reinit_uart); + + if (ret != OK) { + PX4_INFO("Binding DSM failed"); + } + + return ret; +} + +int CuberedBridgePrimary::io_get_status() +{ + /* get + * STATUS_FLAGS, STATUS_ALARMS, STATUS_VBATT, STATUS_IBATT, + * STATUS_VSERVO, STATUS_VRSSI + * in that order */ + uint16_t regs[6] {}; + int ret = io_regs_get(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_FLAGS, ®s[0], sizeof(regs) / sizeof(regs[0])); + + if (ret != OK) { + return ret; + } + + const uint16_t STATUS_FLAGS = regs[0]; + const uint16_t STATUS_ALARMS = regs[1]; + const uint16_t STATUS_VSERVO = regs[4]; + const uint16_t STATUS_VRSSI = regs[5]; + + io_handle_status(STATUS_FLAGS); + + const float rssi_v = STATUS_VRSSI * 0.001f; // voltage is scaled to mV + + if (_analog_rc_rssi_volt < 0.f) { + _analog_rc_rssi_volt = rssi_v; + } + + _analog_rc_rssi_volt = _analog_rc_rssi_volt * 0.99f + rssi_v * 0.01f; + + if (_analog_rc_rssi_volt > 2.5f) { + _analog_rc_rssi_stable = true; + } + + uint16_t SETUP_ARMING; + io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_ARMING, SETUP_ARMING); + + if ((hrt_elapsed_time(&_last_status_publish) >= 1_s) + || (_status != STATUS_FLAGS) + || (_alarms != STATUS_ALARMS) + || (_setup_arming != SETUP_ARMING) + ) { + + px4io_status_s status{}; + + status.voltage_v = STATUS_VSERVO * 0.001f; // voltage is scaled to mV + status.rssi_v = rssi_v; + + io_reg_get(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_FREEMEM, status.free_memory_bytes); + + // PX4IO_P_STATUS_FLAGS + status.status_outputs_armed = STATUS_FLAGS & PX4IO_P_STATUS_FLAGS_OUTPUTS_ARMED; + status.status_rc_ok = STATUS_FLAGS & PX4IO_P_STATUS_FLAGS_RC_OK; + status.status_rc_ppm = STATUS_FLAGS & PX4IO_P_STATUS_FLAGS_RC_PPM; + status.status_rc_dsm = STATUS_FLAGS & PX4IO_P_STATUS_FLAGS_RC_DSM; + status.status_rc_sbus = STATUS_FLAGS & PX4IO_P_STATUS_FLAGS_RC_SBUS; + status.status_rc_st24 = STATUS_FLAGS & PX4IO_P_STATUS_FLAGS_RC_ST24; + status.status_rc_sumd = STATUS_FLAGS & PX4IO_P_STATUS_FLAGS_RC_SUMD; + status.status_fmu_initialized = STATUS_FLAGS & PX4IO_P_STATUS_FLAGS_FMU_INITIALIZED; + status.status_fmu_ok = STATUS_FLAGS & PX4IO_P_STATUS_FLAGS_FMU_OK; + status.status_raw_pwm = STATUS_FLAGS & PX4IO_P_STATUS_FLAGS_RAW_PWM; + status.status_arm_sync = STATUS_FLAGS & PX4IO_P_STATUS_FLAGS_ARM_SYNC; + status.status_init_ok = STATUS_FLAGS & PX4IO_P_STATUS_FLAGS_INIT_OK; + status.status_failsafe = STATUS_FLAGS & PX4IO_P_STATUS_FLAGS_FAILSAFE; + status.status_safety_button_event = STATUS_FLAGS & PX4IO_P_STATUS_FLAGS_SAFETY_BUTTON_EVENT; + + // PX4IO_P_STATUS_ALARMS + status.alarm_rc_lost = STATUS_ALARMS & PX4IO_P_STATUS_ALARMS_RC_LOST; + status.alarm_pwm_error = STATUS_ALARMS & PX4IO_P_STATUS_ALARMS_PWM_ERROR; + + // PX4IO_P_SETUP_ARMING + status.arming_io_arm_ok = SETUP_ARMING & PX4IO_P_SETUP_ARMING_IO_ARM_OK; + status.arming_fmu_armed = SETUP_ARMING & PX4IO_P_SETUP_ARMING_FMU_ARMED; + status.arming_fmu_prearmed = SETUP_ARMING & PX4IO_P_SETUP_ARMING_FMU_PREARMED; + status.arming_failsafe_custom = SETUP_ARMING & PX4IO_P_SETUP_ARMING_FAILSAFE_CUSTOM; + status.arming_lockdown = SETUP_ARMING & PX4IO_P_SETUP_ARMING_LOCKDOWN; + status.arming_termination = SETUP_ARMING & PX4IO_P_SETUP_ARMING_TERMINATION; + status.arming_termination_failsafe = SETUP_ARMING & PX4IO_P_SETUP_ARMING_TERMINATION_FAILSAFE; + + for (unsigned i = 0; i < _max_actuators; i++) { + io_reg_get(PX4IO_PAGE_SERVOS, i, status.pwm[i]); + io_reg_get(PX4IO_PAGE_DISARMED_PWM, i, status.pwm_disarmed[i]); + io_reg_get(PX4IO_PAGE_FAILSAFE_PWM, i, status.pwm_failsafe[i]); + } + + { + int i = 0; + + for (uint8_t offset = PX4IO_P_SETUP_PWM_RATE_GROUP0; offset <= PX4IO_P_SETUP_PWM_RATE_GROUP3; ++offset) { + // This is a bit different than below, setting the groups, not the channels + io_reg_get(PX4IO_PAGE_SETUP, offset, status.pwm_rate_hz[i++]); + } + } + + uint16_t raw_inputs = 0; + io_reg_get(PX4IO_PAGE_RAW_RC_INPUT, PX4IO_P_RAW_RC_COUNT, raw_inputs); + + for (unsigned i = 0; (i < raw_inputs) && (i < _max_rc_input); i++) { + io_reg_get(PX4IO_PAGE_RAW_RC_INPUT, PX4IO_P_RAW_RC_BASE + i, status.raw_inputs[i]); + } + + status.timestamp = hrt_absolute_time(); + _px4io_status_pub.publish(status); + + _last_status_publish = status.timestamp; + } + + _alarms = STATUS_ALARMS; + _setup_arming = SETUP_ARMING; + + return ret; +} + +int CuberedBridgePrimary::io_publish_raw_rc() +{ + uint16_t rc_valid_update_count = 0; + io_reg_get(PX4IO_PAGE_RAW_RC_INPUT, PX4IO_P_RAW_FRAME_COUNT, rc_valid_update_count); + const bool rc_updated = (rc_valid_update_count != _rc_valid_update_count); + _rc_valid_update_count = rc_valid_update_count; + + // only publish if the IO status indicates that the RC is OK + const uint16_t status_rc_ok = _status & PX4IO_P_STATUS_FLAGS_RC_OK; + + if (!rc_updated | !status_rc_ok) { + return 0; + } + + input_rc_s input_rc{}; + input_rc.timestamp_last_signal = hrt_absolute_time(); + + /* set the RC status flag ORDER MATTERS! */ + input_rc.rc_lost = !(_status & PX4IO_P_STATUS_FLAGS_RC_OK); + + /* we don't have the status bits, so input_source has to be set elsewhere */ + input_rc.input_source = input_rc_s::RC_INPUT_SOURCE_UNKNOWN; + + const unsigned prolog = (PX4IO_P_RAW_RC_BASE - PX4IO_P_RAW_RC_COUNT); + uint16_t regs[input_rc_s::RC_INPUT_MAX_CHANNELS + prolog]; + + /* + * Read the channel count and the first 9 channels. + * + * This should be the common case (9 channel R/C control being a reasonable upper bound). + */ + int ret = io_regs_get(PX4IO_PAGE_RAW_RC_INPUT, PX4IO_P_RAW_RC_COUNT, ®s[0], prolog + 9); + + if (ret != OK) { + return ret; + } + + /* + * Get the channel count any any extra channels. This is no more expensive than reading the + * channel count once. + */ + uint32_t channel_count = regs[PX4IO_P_RAW_RC_COUNT]; + + /* limit the channel count */ + if (channel_count > input_rc_s::RC_INPUT_MAX_CHANNELS) { + channel_count = input_rc_s::RC_INPUT_MAX_CHANNELS; + } + + input_rc.timestamp = hrt_absolute_time(); + + input_rc.rc_ppm_frame_length = regs[PX4IO_P_RAW_RC_DATA]; + + if (!_analog_rc_rssi_stable) { + input_rc.rssi = regs[PX4IO_P_RAW_RC_NRSSI]; + + } else { + float rssi_analog = ((_analog_rc_rssi_volt - 0.2f) / 3.0f) * 100.0f; + + if (rssi_analog > 100.0f) { + rssi_analog = 100.0f; + } + + if (rssi_analog < 0.0f) { + rssi_analog = 0.0f; + } + + input_rc.rssi = rssi_analog; + } + + input_rc.rc_failsafe = (regs[PX4IO_P_RAW_RC_FLAGS] & PX4IO_P_RAW_RC_FLAGS_FAILSAFE); + input_rc.rc_lost = !(regs[PX4IO_P_RAW_RC_FLAGS] & PX4IO_P_RAW_RC_FLAGS_RC_OK); + input_rc.rc_lost_frame_count = regs[PX4IO_P_RAW_LOST_FRAME_COUNT]; + input_rc.rc_total_frame_count = regs[PX4IO_P_RAW_FRAME_COUNT]; + input_rc.channel_count = channel_count; + + + /* FIELDS NOT SET HERE */ + /* input_rc.input_source is set after this call XXX we might want to mirror the flags in the RC struct */ + + if (channel_count > 9) { + ret = io_regs_get(PX4IO_PAGE_RAW_RC_INPUT, PX4IO_P_RAW_RC_BASE + 9, ®s[prolog + 9], channel_count - 9); + + if (ret != OK) { + return ret; + } + } + + /* last thing set are the actual channel values as 16 bit values */ + for (unsigned i = 0; i < channel_count; i++) { + input_rc.values[i] = regs[prolog + i]; + } + + /* zero the remaining fields */ + for (unsigned i = channel_count; i < (sizeof(input_rc.values) / sizeof(input_rc.values[0])); i++) { + input_rc.values[i] = 0; + } + + /* get RSSI from input channel */ + if (_param_rc_rssi_pwm_chan.get() > 0 && _param_rc_rssi_pwm_chan.get() <= input_rc_s::RC_INPUT_MAX_CHANNELS) { + const auto &min = _param_rc_rssi_pwm_min.get(); + const auto &max = _param_rc_rssi_pwm_max.get(); + + if (max - min != 0) { + int rssi = ((input_rc.values[_param_rc_rssi_pwm_chan.get() - 1] - min) * 100) / (max - min); + input_rc.rssi = math::constrain(rssi, 0, 100); + } + } + + /* sort out the source of the values */ + if (_status & PX4IO_P_STATUS_FLAGS_RC_PPM) { + input_rc.input_source = input_rc_s::RC_INPUT_SOURCE_PX4IO_PPM; + + } else if (_status & PX4IO_P_STATUS_FLAGS_RC_DSM) { + input_rc.input_source = input_rc_s::RC_INPUT_SOURCE_PX4IO_SPEKTRUM; + + } else if (_status & PX4IO_P_STATUS_FLAGS_RC_SBUS) { + input_rc.input_source = input_rc_s::RC_INPUT_SOURCE_PX4IO_SBUS; + + } else if (_status & PX4IO_P_STATUS_FLAGS_RC_ST24) { + input_rc.input_source = input_rc_s::RC_INPUT_SOURCE_PX4IO_ST24; + } + + if (input_rc.input_source != input_rc_s::RC_INPUT_SOURCE_UNKNOWN) { + + input_rc.link_quality = -1; + input_rc.rssi_dbm = NAN; + + _input_rc_pub.publish(input_rc); + } + + return ret; +} + +int CuberedBridgePrimary::io_regs_set(uint8_t page, uint8_t offset, const uint16_t *values, unsigned num_values) +{ + /* range check the transfer */ + if (num_values > ((_max_transfer) / sizeof(*values))) { + PX4_DEBUG("io_regs_set: too many registers (%u, max %u)", num_values, _max_transfer / 2); + return -EINVAL; + } + + perf_begin(_interface_write_perf); + int ret = _interface->write((page << 8) | offset, (void *)values, num_values); + perf_end(_interface_write_perf); + + if (ret != (int)num_values) { + PX4_DEBUG("io_regs_set(%" PRIu8 ",%" PRIu8 ",%u): error %d", page, offset, num_values, ret); + return -1; + } + + return OK; +} + +int CuberedBridgePrimary::io_reg_set(uint8_t page, uint8_t offset, uint16_t value) +{ + return io_regs_set(page, offset, &value, 1); +} + +int CuberedBridgePrimary::io_regs_get(uint8_t page, uint8_t offset, uint16_t *values, unsigned num_values) +{ + if (num_values > ((_max_transfer) / sizeof(*values))) { + PX4_DEBUG("io_regs_get: too many registers (%u, max %u)", num_values, _max_transfer / 2); + return -EINVAL; + } + + perf_begin(_interface_read_perf); + int ret = _interface->read((page << 8) | offset, reinterpret_cast(values), num_values); + perf_end(_interface_read_perf); + + if (ret != (int)num_values) { + PX4_DEBUG("io_reg_get(%" PRIu8 ",%" PRIu8 ",%u): data error %d", page, offset, num_values, ret); + return -1; + } + + return OK; +} + +int CuberedBridgePrimary::io_reg_get(uint8_t page, uint8_t offset, uint16_t &value) +{ + return io_regs_get(page, offset, &value, 1); +} + +int CuberedBridgePrimary::io_reg_modify(uint8_t page, uint8_t offset, uint16_t clearbits, uint16_t setbits) +{ + uint16_t value = 0; + int ret = io_regs_get(page, offset, &value, 1); + + if (ret != OK) { + return ret; + } + + value &= ~clearbits; + value |= setbits; + + return io_reg_set(page, offset, value); +} + +int CuberedBridgePrimary::print_status() +{ + uint16_t protocol, hardware, bootloader, buffer, crc1, crc2; + io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_PROTOCOL_VERSION, protocol); + io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_HARDWARE_VERSION, hardware); + io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_BOOTLOADER_VERSION, bootloader); + io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_MAX_TRANSFER, buffer); + io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_CRC, crc1); + io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_CRC + 1, crc2); + + /* basic configuration */ + printf("protocol %" PRIu16 " hardware %" PRIu16 " bootloader %" PRIu16 " buffer %" PRIu16 "B crc 0x%04" PRIx16 "%04" PRIx16 "\n", + protocol, hardware, bootloader, buffer, crc1, crc2); + + uint16_t controls, actuators, rc_inputs, adc_input_count; + io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_CONTROL_COUNT, controls); + io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_ACTUATOR_COUNT, actuators); + io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_RC_INPUT_COUNT, rc_inputs); + io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_ADC_INPUT_COUNT, adc_input_count); + printf("%" PRIu16 " controls %" PRIu16 " actuators %" PRIu16 " R/C inputs %" PRIu16 " analog inputs\n", + controls, actuators, rc_inputs, adc_input_count); + + /* status */ + uORB::SubscriptionData status_sub{ORB_ID(px4io_status)}; + status_sub.update(); + + print_message(ORB_ID(px4io_status), status_sub.get()); + + /* now clear alarms */ + io_reg_set(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_ALARMS, 0x0000); + + printf("\n"); + + uint16_t raw_inputs; + io_reg_get(PX4IO_PAGE_RAW_RC_INPUT, PX4IO_P_RAW_RC_COUNT, raw_inputs); + printf("%" PRIu16 " raw R/C inputs", raw_inputs); + + for (unsigned i = 0; i < raw_inputs; i++) { + uint16_t value = 0; + io_reg_get(PX4IO_PAGE_RAW_RC_INPUT, PX4IO_P_RAW_RC_BASE + i, value); + printf(" %" PRIu16, value); + } + + printf("\n"); + uint16_t adc_inputs; + io_reg_get(PX4IO_PAGE_CONFIG, PX4IO_P_CONFIG_ADC_INPUT_COUNT, adc_inputs); + printf("ADC inputs"); + + for (unsigned i = 0; i < adc_inputs; i++) { + uint16_t value = 0; + io_reg_get(PX4IO_PAGE_RAW_ADC_INPUT, i, value); + printf(" %" PRIu16, value); + } + + printf("\n"); + + /* setup and state */ + uint16_t features; + io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_FEATURES, features); + printf("features 0x%04" PRIx16 "%s%s%s\n", features, + ((features & PX4IO_P_SETUP_FEATURES_SBUS1_OUT) ? " S.BUS1_OUT" : ""), + ((features & PX4IO_P_SETUP_FEATURES_SBUS2_OUT) ? " S.BUS2_OUT" : ""), + ((features & PX4IO_P_SETUP_FEATURES_ADC_RSSI) ? " RSSI_ADC" : "") + ); + + uint16_t sbus_rate; + io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_SBUS_RATE, sbus_rate); + printf("sbus rate %" PRIu16 "\n", sbus_rate); + + uint16_t debug_level; + io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_SET_DEBUG, debug_level); + printf("debuglevel %" PRIu16 "\n", debug_level); + + /* IMU heater (Pixhawk 2.1) */ + uint16_t heater_level; + io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_THERMAL, heater_level); + + if (heater_level != UINT16_MAX) { + if (heater_level == PX4IO_THERMAL_OFF) { + printf("\nIMU heater off"); + + } else { + printf("\nIMU heater level %d", heater_level); + } + } + + printf("\n"); + + _mixing_output.printStatus(); + return 0; +} + +int CuberedBridgePrimary::ioctl(file *filep, int cmd, unsigned long arg) +{ + SmartLock lock_guard(_lock); + int ret = OK; + + /* regular ioctl? */ + switch (cmd) { + case DSM_BIND_START: + /* bind a DSM receiver */ + ret = dsm_bind_ioctl(arg); + break; + + case PX4IO_SET_DEBUG: + PX4_DEBUG("PX4IO_SET_DEBUG"); + + /* set the debug level */ + ret = io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_SET_DEBUG, arg); + break; + + case SBUS_SET_PROTO_VERSION: + PX4_DEBUG("SBUS_SET_PROTO_VERSION"); + + if (arg == 1) { + ret = io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_FEATURES, 0, PX4IO_P_SETUP_FEATURES_SBUS1_OUT); + + } else if (arg == 2) { + ret = io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_FEATURES, 0, PX4IO_P_SETUP_FEATURES_SBUS2_OUT); + + } else { + ret = io_reg_modify(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_FEATURES, + (PX4IO_P_SETUP_FEATURES_SBUS1_OUT | PX4IO_P_SETUP_FEATURES_SBUS2_OUT), 0); + } + + break; + + case PX4IO_HEATER_CONTROL: + if (arg == (unsigned long)HEATER_MODE_DISABLED) { + io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_THERMAL, PX4IO_THERMAL_IGNORE); + + } else if (arg == 1) { + io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_THERMAL, PX4IO_THERMAL_FULL); + + } else { + io_reg_set(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_THERMAL, PX4IO_THERMAL_OFF); + + } + + break; + + default: + /* see if the parent class can make any use of it */ + ret = CDev::ioctl(filep, cmd, arg); + break; + } + + return ret; +} + +static device::Device *get_interface() +{ + device::Device *interface = PX4IO_serial_interface(); + + if (interface != nullptr) { + if (interface->init() != OK) { + PX4_ERR("interface init failed"); + delete interface; + interface = nullptr; + } + } + + return interface; +} + +int CuberedBridgePrimary::bind(int argc, char *argv[]) +{ + int pulses; + + if (argc < 1) { + PX4_ERR("needs argument, use dsm2, dsmx or dsmx8"); + return 1; + } + + if (!strcmp(argv[0], "dsm2")) { + pulses = DSM2_BIND_PULSES; + + } else if (!strcmp(argv[0], "dsmx")) { + pulses = DSMX_BIND_PULSES; + + } else if (!strcmp(argv[0], "dsmx8")) { + pulses = DSMX8_BIND_PULSES; + + } else { + PX4_ERR("unknown parameter %s, use dsm2, dsmx or dsmx8", argv[0]); + return 1; + } + + // Test for custom pulse parameter + if (argc > 1) { + pulses = atoi(argv[1]); + } + + get_instance(desc)->ioctl(nullptr, DSM_BIND_START, pulses); + + return 0; +} + +int CuberedBridgePrimary::task_spawn(int argc, char *argv[]) +{ + device::Device *interface = get_interface(); + + if (interface == nullptr) { + PX4_ERR("Failed to create interface"); + return -1; + } + + CuberedBridgePrimary *instance = new CuberedBridgePrimary(interface); + + if (instance) { + desc.object.store(instance); + desc.task_id = task_id_is_work_queue; + + if (instance->init() == PX4_OK) { + return PX4_OK; + } + + } else { + PX4_ERR("alloc failed"); + } + + delete instance; + desc.object.store(nullptr); + desc.task_id = -1; + + return PX4_ERROR; +} + +int CuberedBridgePrimary::custom_command(int argc, char *argv[]) +{ + const char *verb = argv[0]; + + if (!strcmp(verb, "supported")) { + return 0; + } + + /* commands below here require a started driver */ + if (!is_running(desc)) { + PX4_ERR("not running"); + return 1; + } + + if (!strcmp(verb, "debug")) { + if (argc <= 1) { + PX4_ERR("usage: px4io debug LEVEL"); + return 1; + } + + uint8_t level = atoi(argv[1]); + int ret = get_instance(desc)->ioctl(nullptr, PX4IO_SET_DEBUG, level); + + if (ret != 0) { + PX4_ERR("SET_DEBUG failed: %d", ret); + return 1; + } + + PX4_INFO("SET_DEBUG %" PRIu8 " OK", level); + return 0; + } + + if (!strcmp(verb, "bind")) { + if (!is_running(desc)) { + PX4_ERR("io must be running"); + return 1; + } + + return bind(argc - 1, argv + 1); + } + + if (!strcmp(verb, "sbus1_out")) { + int ret = get_instance(desc)->ioctl(nullptr, SBUS_SET_PROTO_VERSION, 1); + + if (ret != 0) { + PX4_ERR("S.BUS v1 failed (%i)", ret); + return 1; + } + + return 0; + } + + if (!strcmp(verb, "sbus2_out")) { + int ret = get_instance(desc)->ioctl(nullptr, SBUS_SET_PROTO_VERSION, 2); + + if (ret != 0) { + PX4_ERR("S.BUS v2 failed (%i)", ret); + return 1; + } + + return 0; + } + + if (!strcmp(verb, "test_fmu_fail")) { + get_instance(desc)->test_fmu_fail(true); + return 0; + } + + if (!strcmp(verb, "test_fmu_ok")) { + get_instance(desc)->test_fmu_fail(false); + return 0; + } + + return print_usage("unknown command"); +} + +int CuberedBridgePrimary::print_usage(const char *reason) +{ + if (reason) { + PX4_WARN("%s\n", reason); + } + + PRINT_MODULE_DESCRIPTION( + R"DESCR_STR( +### Description +CubeRed bridge driver running on the primary MCU. Talks over the IO +serial link to cubered_bridge_secondary on the secondary MCU using +the PX4IO register protocol. Unlike px4io, the secondary cannot be +flashed via the primary; flash it directly with its own build target. +)DESCR_STR"); + + PRINT_MODULE_USAGE_NAME("cubered_bridge_primary", "driver"); + PRINT_MODULE_USAGE_COMMAND("start"); + + PRINT_MODULE_USAGE_COMMAND_DESCR("debug", "set IO debug level"); + PRINT_MODULE_USAGE_ARG("", "0=disabled, 9=max verbosity", false); + PRINT_MODULE_USAGE_COMMAND_DESCR("bind", "DSM bind"); + PRINT_MODULE_USAGE_ARG("dsm2|dsmx|dsmx8", "protocol", false); + PRINT_MODULE_USAGE_COMMAND_DESCR("sbus1_out", "enable sbus1 out"); + PRINT_MODULE_USAGE_COMMAND_DESCR("sbus2_out", "enable sbus2 out"); + PRINT_MODULE_USAGE_COMMAND_DESCR("supported", "Returns 0 if supported"); + PRINT_MODULE_USAGE_COMMAND_DESCR("test_fmu_fail", "test: turn off IO updates"); + PRINT_MODULE_USAGE_COMMAND_DESCR("test_fmu_ok", "re-enable IO updates"); + + PRINT_MODULE_USAGE_DEFAULT_COMMANDS(); + + return 0; +} + + +extern "C" __EXPORT int cubered_bridge_primary_main(int argc, char *argv[]) +{ + if (!PX4_MFT_HW_SUPPORTED(PX4_MFT_PX4IO)) { + PX4_INFO("CuberedBridgePrimary Not Supported"); + return -1; + } + return ModuleBase::main(CuberedBridgePrimary::desc, argc, argv); +} diff --git a/src/drivers/cubered_bridge/primary/cubered_bridge_primary_driver.h b/src/drivers/cubered_bridge/primary/cubered_bridge_primary_driver.h new file mode 100644 index 0000000000..2da2d0e05c --- /dev/null +++ b/src/drivers/cubered_bridge/primary/cubered_bridge_primary_driver.h @@ -0,0 +1,48 @@ +/**************************************************************************** + * + * Copyright (c) 2015 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file px4io_driver.h + * + * Interface for PX4IO + */ + +#pragma once + +#include + +#ifdef PX4IO_SERIAL_BASE +#include + +device::Device *PX4IO_serial_interface(); +#endif diff --git a/src/drivers/cubered_bridge/primary/cubered_bridge_primary_params.yaml b/src/drivers/cubered_bridge/primary/cubered_bridge_primary_params.yaml new file mode 100644 index 0000000000..4da2480ba2 --- /dev/null +++ b/src/drivers/cubered_bridge/primary/cubered_bridge_primary_params.yaml @@ -0,0 +1,10 @@ +module_name: px4io +parameters: +- group: PWM Outputs + definitions: + PWM_SBUS_MODE: + description: + short: S.BUS out + long: Set to 1 to enable S.BUS version 1 output instead of RSSI. + type: boolean + default: 0 diff --git a/src/drivers/cubered_bridge/primary/cubered_bridge_primary_serial.cpp b/src/drivers/cubered_bridge/primary/cubered_bridge_primary_serial.cpp new file mode 100644 index 0000000000..f6c4e8c52a --- /dev/null +++ b/src/drivers/cubered_bridge/primary/cubered_bridge_primary_serial.cpp @@ -0,0 +1,223 @@ +/**************************************************************************** + * + * Copyright (c) 2013-2015 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file px4io_serial.cpp + * + * Serial interface for PX4IO + */ + +#include "cubered_bridge_primary_driver.h" + +#include + +static PX4IO_serial *g_interface; + +device::Device +*PX4IO_serial_interface() +{ + return new ArchPX4IOSerial(); +} + +PX4IO_serial::PX4IO_serial() : + Device("PX4IO_serial"), + _pc_txns(perf_alloc(PC_ELAPSED, MODULE_NAME": txns")), + _pc_retries(perf_alloc(PC_COUNT, MODULE_NAME": retries")), + _pc_timeouts(perf_alloc(PC_COUNT, MODULE_NAME": timeouts")), + _pc_crcerrs(perf_alloc(PC_COUNT, MODULE_NAME": crcerrs")), + _pc_protoerrs(perf_alloc(PC_COUNT, MODULE_NAME": protoerrs")), + _pc_uerrs(perf_alloc(PC_COUNT, MODULE_NAME": uarterrs")), + _pc_idle(perf_alloc(PC_COUNT, MODULE_NAME": idle")), + _pc_badidle(perf_alloc(PC_COUNT, MODULE_NAME": badidle")), + _bus_semaphore(SEM_INITIALIZER(0)) +{ + g_interface = this; +} + +PX4IO_serial::~PX4IO_serial() +{ + /* kill our semaphores */ + px4_sem_destroy(&_bus_semaphore); + + perf_free(_pc_txns); + perf_free(_pc_retries); + perf_free(_pc_timeouts); + perf_free(_pc_crcerrs); + perf_free(_pc_protoerrs); + perf_free(_pc_uerrs); + perf_free(_pc_idle); + perf_free(_pc_badidle); + + if (g_interface == this) { + g_interface = nullptr; + } +} + +int +PX4IO_serial::init(IOPacket *io_buffer) +{ + _io_buffer_ptr = io_buffer; + /* create semaphores */ + // in case the sub-class impl fails, the semaphore is cleaned up by destructor. + px4_sem_init(&_bus_semaphore, 0, 1); + + return 0; +} + +int +PX4IO_serial::write(unsigned address, void *data, unsigned count) +{ + uint8_t page = address >> 8; + uint8_t offset = address & 0xff; + const uint16_t *values = reinterpret_cast(data); + + if (count > PKT_MAX_REGS) { + return -EINVAL; + } + + px4_sem_wait(&_bus_semaphore); + + int result; + + for (unsigned retries = 0; retries < 3; retries++) { + _io_buffer_ptr->count_code = count | PKT_CODE_WRITE; + _io_buffer_ptr->page = page; + _io_buffer_ptr->offset = offset; + memcpy((void *)&_io_buffer_ptr->regs[0], (void *)values, (2 * count)); + + for (unsigned i = count; i < PKT_MAX_REGS; i++) { + _io_buffer_ptr->regs[i] = 0x55aa; + } + + _io_buffer_ptr->crc = 0; + _io_buffer_ptr->crc = crc_packet(_io_buffer_ptr); + + /* start the transaction and wait for it to complete */ + result = _bus_exchange(_io_buffer_ptr); + + /* successful transaction? */ + if (result == OK) { + + /* check result in packet */ + if (PKT_CODE(*_io_buffer_ptr) == PKT_CODE_ERROR) { + + /* IO didn't like it - no point retrying */ + result = -EINVAL; + perf_count(_pc_protoerrs); + } + + break; + } + + perf_count(_pc_retries); + } + + px4_sem_post(&_bus_semaphore); + + if (result == OK) { + result = count; + } + + return result; +} + +int +PX4IO_serial::read(unsigned address, void *data, unsigned count) +{ + uint8_t page = address >> 8; + uint8_t offset = address & 0xff; + uint16_t *values = reinterpret_cast(data); + + if (count > PKT_MAX_REGS) { + return -EINVAL; + } + + px4_sem_wait(&_bus_semaphore); + + int result; + + for (unsigned retries = 0; retries < 3; retries++) { + + /* Clear the entire packet to ensure no stale data */ + memset(_io_buffer_ptr, 0, sizeof(IOPacket)); + + _io_buffer_ptr->count_code = count | PKT_CODE_READ; + _io_buffer_ptr->page = page; + _io_buffer_ptr->offset = offset; + + _io_buffer_ptr->crc = 0; + _io_buffer_ptr->crc = crc_packet(_io_buffer_ptr); + + /* start the transaction and wait for it to complete */ + result = _bus_exchange(_io_buffer_ptr); + + /* successful transaction? */ + if (result == OK) { + + /* check result in packet */ + if (PKT_CODE(*_io_buffer_ptr) == PKT_CODE_ERROR) { + + /* IO didn't like it - no point retrying */ + result = -EINVAL; + perf_count(_pc_protoerrs); + + /* compare the received count with the expected count */ + + } else if (PKT_COUNT(*_io_buffer_ptr) != count) { + + /* IO returned the wrong number of registers - no point retrying */ + result = -EIO; + perf_count(_pc_protoerrs); + + /* successful read */ + + } else { + + /* copy back the result */ + memcpy(values, &_io_buffer_ptr->regs[0], (2 * count)); + } + + break; + } + + perf_count(_pc_retries); + } + + px4_sem_post(&_bus_semaphore); + + if (result == OK) { + result = count; + } + + return result; +} diff --git a/src/drivers/cubered_bridge/primary/module.yaml b/src/drivers/cubered_bridge/primary/module.yaml new file mode 100644 index 0000000000..d2c2f8960b --- /dev/null +++ b/src/drivers/cubered_bridge/primary/module.yaml @@ -0,0 +1,30 @@ +module_name: PWM MAIN +actuator_output: + output_groups: + - generator: pwm + param_prefix: PWM_MAIN + channel_labels: ['MAIN', 'Capture'] + channel_label_module_name_prefix: false + timer_config_file: "boards/cubepilot/cubered-secondary/src/timer_config.cpp" + standard_params: + disarmed: { min: 800, max: 2200, default: 1000 } + min: { min: 800, max: 1400, default: 1000 } + center: { min: 800, max: 2200} + max: { min: 1600, max: 2200, default: 2000 } + failsafe: { min: 800, max: 2200 } + pwm_timer_param: + description: + short: Output Protocol Configuration for ${label} + long: | + Select which Output Protocol to use for outputs ${label}. + + Custom PWM rates can be used by directly setting any value >0. + type: enum + default: 400 + values: + -1: OneShot + 50: PWM 50 Hz + 100: PWM 100 Hz + 200: PWM 200 Hz + 400: PWM 400 Hz + reboot_required: true diff --git a/src/drivers/cubered_bridge/secondary/CMakeLists.txt b/src/drivers/cubered_bridge/secondary/CMakeLists.txt new file mode 100644 index 0000000000..100d00ead6 --- /dev/null +++ b/src/drivers/cubered_bridge/secondary/CMakeLists.txt @@ -0,0 +1,41 @@ +############################################################################ +# +# 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__cubered_bridge_secondary + MAIN cubered_bridge_secondary + COMPILE_FLAGS + SRCS + cubered_bridge_secondary.cpp + cubered_bridge_secondary.h +) diff --git a/src/drivers/cubered_bridge/secondary/Kconfig b/src/drivers/cubered_bridge/secondary/Kconfig new file mode 100644 index 0000000000..a48ef6ab03 --- /dev/null +++ b/src/drivers/cubered_bridge/secondary/Kconfig @@ -0,0 +1,5 @@ +menuconfig DRIVERS_CUBERED_BRIDGE_SECONDARY + bool "cubered_bridge_secondary" + default n + ---help--- + Enable support for CubeRed IO module - PX4IO simulation for CubeRed Secondary diff --git a/src/drivers/cubered_bridge/secondary/cubered_bridge_secondary.cpp b/src/drivers/cubered_bridge/secondary/cubered_bridge_secondary.cpp new file mode 100644 index 0000000000..d6430a87e9 --- /dev/null +++ b/src/drivers/cubered_bridge/secondary/cubered_bridge_secondary.cpp @@ -0,0 +1,840 @@ +/**************************************************************************** + * + * 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. + * + ****************************************************************************/ + +/** + * @file cubered_bridge_secondary.cpp + * + * CubeRed IO Module - PX4IO simulation for CubeRed Secondary + * + * This module simulates PX4IO functionality on the CubeRed Secondary + * by providing low-latency serial communication on ttyS4. + */ + +#include "cubered_bridge_secondary.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// Include PX4IO protocol definitions +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace time_literals; + +ModuleBase::Descriptor CuberedBridgeSecondary::desc {CuberedBridgeSecondary::task_spawn, CuberedBridgeSecondary::custom_command, CuberedBridgeSecondary::print_usage}; + +#undef PX4_DEBUG +#define PX4_DEBUG PX4_INFO + +// Configuration page data (simulating PX4IO) +static const uint16_t config_page[] = { + PX4IO_PROTOCOL_VERSION, // PX4IO_P_CONFIG_PROTOCOL_VERSION + 2, // PX4IO_P_CONFIG_HARDWARE_VERSION (Simulate PX4IOv2) + 5, // PX4IO_P_CONFIG_BOOTLOADER_VERSION + PX4IO_MAX_TRANSFER_LEN, // PX4IO_P_CONFIG_MAX_TRANSFER + PX4IO_PROTOCOL_MAX_CONTROL_COUNT,// PX4IO_P_CONFIG_CONTROL_COUNT + 8, // PX4IO_P_CONFIG_ACTUATOR_COUNT + 18, // PX4IO_P_CONFIG_RC_INPUT_COUNT + 3, // PX4IO_P_CONFIG_ADC_INPUT_COUNT +}; + +// Status page data +static uint16_t status_page[8] = { + 0, // PX4IO_P_STATUS_FREEMEM + 0, // PX4IO_P_STATUS_CPULOAD + PX4IO_P_STATUS_FLAGS_INIT_OK | PX4IO_P_STATUS_FLAGS_ARM_SYNC, // PX4IO_P_STATUS_FLAGS + 0, // PX4IO_P_STATUS_ALARMS + 0, // PX4IO_P_STATUS_VSERVO + 0, // PX4IO_P_STATUS_VRSSI + 0, // PX4IO_P_STATUS_PRSSI + 0, // PX4IO_P_STATUS_MIXER +}; + +// Servo PWM values (microseconds) +static uint16_t servos_page[8] = {0}; + +// Direct PWM values (microseconds) +static uint16_t direct_pwm_page[8] = {0}; + +// Raw RC input values +static uint16_t raw_rc_input_page[] = { + 0, // PX4IO_P_RAW_RC_COUNT + 0, // PX4IO_P_RAW_RC_FLAGS + 0, // PX4IO_P_RAW_RC_NRSSI + 0, // PX4IO_P_RAW_RC_DATA + 0, // PX4IO_P_RAW_FRAME_COUNT + 0, // PX4IO_P_RAW_LOST_FRAME_COUNT + // PX4IO_P_RAW_RC_BASE + channels will be added dynamically +}; + +// Raw ADC input values +static uint16_t raw_adc_input_page[3] = {0}; // Support up to 3 ADC inputs + +// PWM rate group information +static uint16_t pwm_info_page[8] = {0}; + +// PWM disarmed values that are active even when SAFETY_SAFE +static uint16_t disarmed_pwm_page[8] = {0}; + +// PWM failsafe values - zero disables the output +static uint16_t failsafe_pwm_page[8] = {0}; + +// Setup page data (simulating PX4IO) +static uint16_t setup_page[] = { + PX4IO_P_SETUP_FEATURES_ADC_RSSI, // PX4IO_P_SETUP_FEATURES + 0, // PX4IO_P_SETUP_ARMING + 0, // PX4IO_P_SETUP_PWM_RATES + 50, // PX4IO_P_SETUP_PWM_DEFAULTRATE + 200, // PX4IO_P_SETUP_PWM_ALTRATE + 72, // PX4IO_P_SETUP_SBUS_RATE + 10000, // PX4IO_P_SETUP_VSERVO_SCALE + 0, // PX4IO_P_SETUP_SET_DEBUG + 0, // PX4IO_P_SETUP_REBOOT_BL + 0, // PX4IO_P_SETUP_CRC + 0, // PX4IO_P_SETUP_CRC + 1 + PX4IO_THERMAL_IGNORE, // PX4IO_P_SETUP_THERMAL + 0, // PX4IO_P_SETUP_ENABLE_FLIGHTTERMINATION + 0, // PX4IO_P_SETUP_PWM_RATE_GROUP0 + 0, // PX4IO_P_SETUP_PWM_RATE_GROUP1 + 0, // PX4IO_P_SETUP_PWM_RATE_GROUP2 + 0, // PX4IO_P_SETUP_PWM_RATE_GROUP3 + 0, // PX4IO_P_SETUP_SAFETY_BUTTON_ACK + 0, // PX4IO_P_SETUP_SAFETY_OFF +}; + +CuberedBridgeSecondary::CuberedBridgeSecondary() +{ +} + +CuberedBridgeSecondary::~CuberedBridgeSecondary() +{ + if (_serial_fd >= 0) { + ::close(_serial_fd); + } + + // Clean up PWM outputs + if (_pwm_initialized) { + up_pwm_servo_deinit(_pwm_mask); + } + + perf_free(_loop_perf); + perf_free(_loop_interval_perf); +} + +int CuberedBridgeSecondary::task_spawn(int argc, char *argv[]) +{ + int task_id = px4_task_spawn_cmd("cubered_bridge_secondary", + SCHED_DEFAULT, + SCHED_PRIORITY_MAX - 5, // High priority for low latency + 2048, + (px4_main_t) &run_trampoline, + (char *const *)argv); + + if (task_id < 0) { + return -errno; + } + + desc.task_id = task_id; + return 0; +} + +int CuberedBridgeSecondary::run_trampoline(int argc, char *argv[]) +{ + return ModuleBase::run_trampoline_impl(desc, [](int ac, char *av[]) -> ModuleBase * { + return CuberedBridgeSecondary::instantiate(ac, av); + }, argc, argv); +} + +CuberedBridgeSecondary *CuberedBridgeSecondary::instantiate(int argc, char *argv[]) +{ + CuberedBridgeSecondary *instance = new CuberedBridgeSecondary(); + + if (instance && !instance->init()) { + delete instance; + return nullptr; + } + + return instance; +} + +bool CuberedBridgeSecondary::init() +{ + if (init_serial() != PX4_OK) { + PX4_ERR("Failed to initialize serial port"); + return false; + } + + if (init_pwm() != PX4_OK) { + PX4_ERR("Failed to initialize PWM outputs"); + return false; + } + + PX4_INFO("CuberedBridgeSecondary initialized on %s with PWM outputs", DEVICE_NAME); + return true; +} + +int CuberedBridgeSecondary::init_serial() +{ + // Open serial port + _serial_fd = ::open(DEVICE_NAME, O_RDWR | O_NOCTTY | O_NONBLOCK); + + if (_serial_fd < 0) { + PX4_ERR("Failed to open %s: %s", DEVICE_NAME, strerror(errno)); + return PX4_ERROR; + } + + // Configure serial port + termios uart_config; + + if (tcgetattr(_serial_fd, &uart_config) < 0) { + PX4_ERR("Failed to get termios config: %s", strerror(errno)); + ::close(_serial_fd); + _serial_fd = -1; + return PX4_ERROR; + } + + // Set baud rate + if (cfsetispeed(&uart_config, BAUDRATE) < 0 || cfsetospeed(&uart_config, BAUDRATE) < 0) { + PX4_ERR("Failed to set baudrate: %s", strerror(errno)); + ::close(_serial_fd); + _serial_fd = -1; + return PX4_ERROR; + } + + // Configure for raw mode + uart_config.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + uart_config.c_oflag &= ~OPOST; + uart_config.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + uart_config.c_cflag &= ~(CSIZE | PARENB); + uart_config.c_cflag |= CS8; + + // Set timeouts for non-blocking read + uart_config.c_cc[VMIN] = 6; + uart_config.c_cc[VTIME] = 1; + + if (tcsetattr(_serial_fd, TCSANOW, &uart_config) < 0) { + PX4_ERR("Failed to set termios config: %s", strerror(errno)); + ::close(_serial_fd); + _serial_fd = -1; + return PX4_ERROR; + } + + // Flush any existing data + tcflush(_serial_fd, TCIOFLUSH); + + return PX4_OK; +} + +int CuberedBridgeSecondary::init_pwm() +{ + // Initialize PWM channels (similar to pwm_out module) + _pwm_mask = ((1u << DIRECT_PWM_OUTPUT_CHANNELS) - 1); + + // Initialize timer rates + for (int timer = 0; timer < MAX_IO_TIMERS; ++timer) { + _timer_rates[timer] = -1; + + uint32_t channels = io_timer_get_group(timer); + + if (channels == 0) { + continue; + } + + // Set default PWM rate (400Hz like PX4IO) + _timer_rates[timer] = 400; + } + + // Initialize PWM hardware + printf("CuberedBridgeSecondary: Attempting PWM init with mask 0x%02" PRIx32 "\n", _pwm_mask); + int ret = up_pwm_servo_init(_pwm_mask); + + if (ret < 0) { + printf("CuberedBridgeSecondary: up_pwm_servo_init failed (%i)\n", ret); + return PX4_ERROR; + } + + printf("CuberedBridgeSecondary: up_pwm_servo_init returned mask 0x%02x\n", ret); + _pwm_mask = ret; + + // Set the timer rates + for (int timer = 0; timer < MAX_IO_TIMERS; ++timer) { + uint32_t channels = _pwm_mask & up_pwm_servo_get_rate_group(timer); + + if (channels == 0) { + printf("CuberedBridgeSecondary: Timer %d has no channels\n", timer); + continue; + } + + printf("CuberedBridgeSecondary: Setting timer %d rate to %d Hz for channels 0x%02" PRIx32 "\n", timer, _timer_rates[timer], + channels); + ret = up_pwm_servo_set_rate_group_update(timer, _timer_rates[timer]); + + if (ret != 0) { + printf("CuberedBridgeSecondary: up_pwm_servo_set_rate_group_update failed for timer %i, rate %i (%i)\n", timer, _timer_rates[timer], + ret); + _timer_rates[timer] = -1; + _pwm_mask &= ~channels; + + } else { + printf("CuberedBridgeSecondary: Timer %d configured successfully\n", timer); + } + } + + _pwm_initialized = true; + + // Always arm PWM hardware (like PWMOut does with pwm_on = true) + // The armed/disarmed state will control values, not hardware state + up_pwm_servo_arm(true, _pwm_mask); + + // Debug: Read back GPIO states to verify direction control + bool bidir_state = px4_arch_gpioread(GPIO_BIDIR_DISABLED); + bool unidir_state = px4_arch_gpioread(GPIO_UNIDIR_ENABLED); + printf("CuberedBridgeSecondary: PWM direction control - BIDIR_DISABLED=%s, UNIDIR_ENABLED=%s\n", + bidir_state ? "HIGH" : "LOW", unidir_state ? "HIGH" : "LOW"); + + PX4_INFO("PWM initialized with mask 0x%02" PRIx32, _pwm_mask); + return PX4_OK; +} + +void CuberedBridgeSecondary::run() +{ + PX4_INFO("CuberedBridgeSecondary task started - simulating PX4IO on CubeRed Secondary"); + + while (!should_exit()) { + perf_begin(_loop_perf); + perf_count(_loop_interval_perf); + + poll_and_process(); + + perf_end(_loop_perf); + } + + PX4_INFO("CuberedBridgeSecondary task exiting"); +} + +void CuberedBridgeSecondary::poll_and_process() +{ + const size_t min_packet_size = 6; // Minimum PX4IO packet size + + // Always start fresh with clean buffer + IOPacket packet {}; + size_t bytes_read = 0; + size_t expected_packet_size = min_packet_size; + + while (bytes_read < expected_packet_size) { + pollfd fds[1]; + fds[0].fd = _serial_fd; + fds[0].events = POLLIN; + + int ret = poll(fds, 1, POLL_TIMEOUT_MS); + + if (ret > 0) { + if (fds[0].revents & POLLIN) { + // Data available to read from CubeRed Primary + int read_ret = ::read(_serial_fd, (reinterpret_cast(&packet)) + bytes_read, sizeof(IOPacket) - bytes_read); + + if (read_ret > 0) { + bytes_read += read_ret; + + // Once we have at least min packet, try to determine actual size + if (bytes_read >= min_packet_size && expected_packet_size == min_packet_size) { + expected_packet_size = PKT_SIZE(packet); + } + + // Check CRC when we have the complete packet + if (bytes_read >= expected_packet_size) { + + if (validate_crc(packet)) { + //printf("CRC OK at %zu bytes\n", bytes_read); + process_received_data(packet); + return; + + } else { + printf("CRC failed at %zu bytes - restarting\n", bytes_read); + // CRC failed - start fresh + bytes_read = 0; + expected_packet_size = min_packet_size; + packet = {}; + continue; + } + } + + } else if (read_ret < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { + PX4_ERR("Read error: %s", strerror(errno)); + return; + } + } + + } else if (ret < 0 && errno != EINTR) { + PX4_ERR("Poll error: %s", strerror(errno)); + return; + + } else { + // Timeout, start fresh with clean buffer + bytes_read = 0; + expected_packet_size = min_packet_size; + packet = {}; + return; + } + } +} + +void CuberedBridgeSecondary::process_received_data(IOPacket &packet) +{ + uint8_t code = PKT_CODE(packet); + //uint8_t count = PKT_COUNT(packet); + + if (code == PKT_CODE_READ) { + handle_read_request(packet); + + } else if (code == PKT_CODE_WRITE) { + handle_write_request(packet); + + } else { + PX4_DEBUG("Unknown packet code: 0x%02x", code); + send_error_response(); + } + + //PX4_DEBUG("Received packet: page=%u, offset=%u, code=0x%02x, count=%u", + // packet.page, packet.offset, code, count); + +} + +void CuberedBridgeSecondary::send_response(IOPacket &packet) +{ + if (_serial_fd >= 0) { + size_t packet_size = PKT_SIZE(packet); + ssize_t bytes_written = ::write(_serial_fd, &packet, packet_size); + + if (bytes_written != (ssize_t)packet_size) { + if (bytes_written < 0) { + PX4_ERR("Write error: %s", strerror(errno)); + + } else { + PX4_WARN("Partial write: %zd of %zu bytes", bytes_written, packet_size); + } + } + } +} + +int CuberedBridgeSecondary::print_usage(const char *reason) +{ + if (reason) { + PX4_WARN("%s\n", reason); + } + + PRINT_MODULE_DESCRIPTION( + R"DESCR_STR( +### Description +CubeRed IO Module - PX4IO simulation for CubeRed Secondary. + +This module simulates PX4IO functionality on the CubeRed Secondary by providing +low-latency serial communication on ttyS4 with the CubeRed Primary. + +The module runs as a dedicated task (not in work queue) to provide low-latency +polling and response on the serial port, mimicking the behavior of a real PX4IO +coprocessor. + +### Implementation +The module runs in its own high-priority task and uses poll() with a short timeout +to achieve low latency communication with the CubeRed Primary. It processes +incoming commands and responds according to the PX4IO protocol. + +### Examples +Start the cubered-io module: +$ cubered_bridge_secondary start + +Stop the cubered-io module: +$ cubered_bridge_secondary stop + +Check status: +$ cubered_bridge_secondary status +)DESCR_STR"); + + PRINT_MODULE_USAGE_NAME("cubered_bridge_secondary", "driver"); + PRINT_MODULE_USAGE_COMMAND("start"); + PRINT_MODULE_USAGE_DEFAULT_COMMANDS(); + + return 0; +} + +bool CuberedBridgeSecondary::validate_crc(IOPacket &packet) +{ + uint8_t expected_crc = packet.crc; + packet.crc = 0; + uint8_t calculated_crc = calculate_crc(packet); + packet.crc = expected_crc; + + return expected_crc == calculated_crc; +} + +uint8_t CuberedBridgeSecondary::calculate_crc(IOPacket &packet) +{ + return crc_packet(&packet); +} + +void CuberedBridgeSecondary::handle_read_request(IOPacket &packet) +{ + //PX4_INFO("Read request: page=%u, offset=%u, count=%u", packet.page, packet.offset, PKT_COUNT(packet)); + + uint8_t offset = packet.offset; + uint8_t count = PKT_COUNT(packet); + + // Prepare response packet + IOPacket response; + memset(&response, 0, sizeof(response)); + response.count_code = count | PKT_CODE_SUCCESS; + response.page = packet.page; + response.offset = packet.offset; + + // Handle different pages + switch (packet.page) { + case PX4IO_PAGE_CONFIG: + // Copy requested config data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(config_page)/sizeof(config_page[0]); i++) { + response.regs[i] = config_page[offset + i]; + } + break; + + case PX4IO_PAGE_STATUS: + //PX4_INFO("status_page size: %zu", sizeof(status_page)/sizeof(status_page[0])); + for (uint8_t i = 0; i < count && (offset + i) < sizeof(status_page)/sizeof(status_page[0]); i++) { + response.regs[i] = status_page[offset + i]; + //PX4_INFO(" status_page[%u] = %u (0x%04x)", offset + i, status_page[offset + i], status_page[offset + i]); + } + //printf("responding with count %u\n", count); + break; + + case PX4IO_PAGE_DIRECT_PWM: + // Copy requested direct PWM data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(direct_pwm_page)/sizeof(direct_pwm_page[0]); i++) { + response.regs[i] = direct_pwm_page[offset + i]; + } + break; + + case PX4IO_PAGE_SERVOS: + // Copy requested servo data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(servos_page)/sizeof(servos_page[0]); i++) { + response.regs[i] = servos_page[offset + i]; + } + break; + + case PX4IO_PAGE_RAW_RC_INPUT: + // Copy requested RC input data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(raw_rc_input_page)/sizeof(raw_rc_input_page[0]); i++) { + response.regs[i] = raw_rc_input_page[offset + i]; + } + break; + + case PX4IO_PAGE_RAW_ADC_INPUT: + // Copy requested ADC input data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(raw_adc_input_page)/sizeof(raw_adc_input_page[0]); i++) { + response.regs[i] = raw_adc_input_page[offset + i]; + } + break; + + case PX4IO_PAGE_PWM_INFO: + // Copy requested PWM info data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(pwm_info_page)/sizeof(pwm_info_page[0]); i++) { + response.regs[i] = pwm_info_page[offset + i]; + } + break; + + case PX4IO_PAGE_SETUP: + // Copy requested setup data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(setup_page)/sizeof(setup_page[0]); i++) { + response.regs[i] = setup_page[offset + i]; + } + break; + + case PX4IO_PAGE_DISARMED_PWM: + // Copy requested disarmed PWM data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(disarmed_pwm_page)/sizeof(disarmed_pwm_page[0]); i++) { + response.regs[i] = disarmed_pwm_page[offset + i]; + } + break; + + case PX4IO_PAGE_FAILSAFE_PWM: + // Copy requested failsafe PWM data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(failsafe_pwm_page)/sizeof(failsafe_pwm_page[0]); i++) { + response.regs[i] = failsafe_pwm_page[offset + i]; + } + break; + + default: + // Unsupported page + PX4_DEBUG("Unsupported page: %u", packet.page); + send_error_response(); + return; + } + + send_packet(response); +} + +void CuberedBridgeSecondary::handle_write_request(IOPacket &packet) +{ + //PX4_DEBUG("Write request: page=%u, offset=%u, count=%u", + // packet.page, packet.offset, PKT_COUNT(packet)); + + // Only print unsupported pages + if (packet.page != PX4IO_PAGE_SETUP && + packet.page != PX4IO_PAGE_DIRECT_PWM && + packet.page != PX4IO_PAGE_FAILSAFE_PWM && + packet.page != PX4IO_PAGE_DISARMED_PWM) { + } + + uint8_t offset = packet.offset; + uint8_t count = PKT_COUNT(packet); + + // Handle different pages + switch (packet.page) { + case PX4IO_PAGE_STATUS: + // Update status data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(status_page)/sizeof(status_page[0]); i++) { + status_page[offset + i] = packet.regs[i]; + } + // Check if arming status changed + if (offset <= PX4IO_P_STATUS_FLAGS && (offset + count) > PX4IO_P_STATUS_FLAGS) { + bool armed = (status_page[PX4IO_P_STATUS_FLAGS] & PX4IO_P_STATUS_FLAGS_OUTPUTS_ARMED) != 0; + set_pwm_armed(armed); + } + break; + + case PX4IO_PAGE_DIRECT_PWM: + { + static unsigned debug_counter = 0; + + // Update direct PWM data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(direct_pwm_page)/sizeof(direct_pwm_page[0]); i++) { + direct_pwm_page[offset + i] = packet.regs[i]; + } + + // Debug print every 400th call + if (++debug_counter >= 400) { + debug_counter = 0; + printf("CuberedBridgeSecondary PWM in (offset=%u, count=%u, %s): ", offset, count, _pwm_armed ? "ARMED" : "DISARMED"); + for (uint8_t i = 0; i < 8 && i < sizeof(direct_pwm_page)/sizeof(direct_pwm_page[0]); i++) { + printf("%u ", direct_pwm_page[i]); + } + printf("\n"); + } + + // Drive actual PWM outputs + update_pwm_outputs(); + } + break; + + case PX4IO_PAGE_SERVOS: + // Update servo data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(servos_page)/sizeof(servos_page[0]); i++) { + servos_page[offset + i] = packet.regs[i]; + } + break; + + case PX4IO_PAGE_RAW_RC_INPUT: + // Update RC input data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(raw_rc_input_page)/sizeof(raw_rc_input_page[0]); i++) { + raw_rc_input_page[offset + i] = packet.regs[i]; + } + break; + + case PX4IO_PAGE_RAW_ADC_INPUT: + // Update ADC input data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(raw_adc_input_page)/sizeof(raw_adc_input_page[0]); i++) { + raw_adc_input_page[offset + i] = packet.regs[i]; + } + break; + + case PX4IO_PAGE_PWM_INFO: + // Update PWM info data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(pwm_info_page)/sizeof(pwm_info_page[0]); i++) { + pwm_info_page[offset + i] = packet.regs[i]; + } + break; + + case PX4IO_PAGE_SETUP: + // Update setup data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(setup_page)/sizeof(setup_page[0]); i++) { + setup_page[offset + i] = packet.regs[i]; + } + break; + + case PX4IO_PAGE_DISARMED_PWM: + // Update disarmed PWM data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(disarmed_pwm_page)/sizeof(disarmed_pwm_page[0]); i++) { + disarmed_pwm_page[offset + i] = packet.regs[i]; + } + break; + + case PX4IO_PAGE_FAILSAFE_PWM: + // Update failsafe PWM data + for (uint8_t i = 0; i < count && (offset + i) < sizeof(failsafe_pwm_page)/sizeof(failsafe_pwm_page[0]); i++) { + failsafe_pwm_page[offset + i] = packet.regs[i]; + } + break; + + default: + // For now, just acknowledge other write requests + // TODO: Implement actual register writes as needed + break; + } + + // Send success response + IOPacket response; + memset(&response, 0, sizeof(response)); + response.count_code = 0 | PKT_CODE_SUCCESS; + response.page = packet.page; + response.offset = packet.offset; + + send_packet(response); +} + +void CuberedBridgeSecondary::send_corrupt_response() +{ + IOPacket response; + memset(&response, 0, sizeof(response)); + response.count_code = 0 | PKT_CODE_CORRUPT; + send_packet(response); +} + +void CuberedBridgeSecondary::send_error_response() +{ + IOPacket response; + memset(&response, 0, sizeof(response)); + response.count_code = 0 | PKT_CODE_ERROR; + send_packet(response); +} + +void CuberedBridgeSecondary::send_packet(IOPacket &packet) +{ + // Calculate packet size + //size_t packet_size = 4 + (PKT_COUNT(packet) * 2); // header + registers + + // Calculate and set CRC + packet.crc = 0; // Clear CRC before calculation + packet.crc = crc_packet(&packet); + + send_response(packet); +} + +int CuberedBridgeSecondary::print_status() +{ + PX4_INFO("CuberedBridgeSecondary Status:"); + PX4_INFO(" Setup Page (50):"); + PX4_INFO(" Features: 0x%04x", setup_page[PX4IO_P_SETUP_FEATURES]); + PX4_INFO(" Arming: 0x%04x", setup_page[PX4IO_P_SETUP_ARMING]); + PX4_INFO(" PWM Rates: 0x%04x", setup_page[PX4IO_P_SETUP_PWM_RATES]); + PX4_INFO(" Default Rate: %u Hz", setup_page[PX4IO_P_SETUP_PWM_DEFAULTRATE]); + PX4_INFO(" Alt Rate: %u Hz", setup_page[PX4IO_P_SETUP_PWM_ALTRATE]); + PX4_INFO(" SBUS Rate: %u Hz", setup_page[PX4IO_P_SETUP_SBUS_RATE]); + PX4_INFO(" VServo Scale: %u", setup_page[PX4IO_P_SETUP_VSERVO_SCALE]); + PX4_INFO(" Debug Level: %u", setup_page[PX4IO_P_SETUP_SET_DEBUG]); + PX4_INFO(" Thermal: %u", setup_page[PX4IO_P_SETUP_THERMAL]); + PX4_INFO(" Flight Termination: %u", setup_page[PX4IO_P_SETUP_ENABLE_FLIGHTTERMINATION]); + + PX4_INFO(" Direct PWM Page (54):"); + for (int i = 0; i < 8; i++) { + PX4_INFO(" Channel %d: %u", i, pwm_info_page[i]); + } + + PX4_INFO(" Failsafe PWM Page (55):"); + for (int i = 0; i < 8; i++) { + PX4_INFO(" Channel %d: %u", i, failsafe_pwm_page[i]); + } + + PX4_INFO(" Disarmed PWM Page (109):"); + for (int i = 0; i < 8; i++) { + PX4_INFO(" Channel %d: %u", i, disarmed_pwm_page[i]); + } + + return 0; +} + +void CuberedBridgeSecondary::update_pwm_outputs() +{ + static unsigned update_counter = 0; + + if (!_pwm_initialized) { + if (++update_counter % 400 == 0) { + printf("CuberedBridgeSecondary: update_pwm_outputs called but PWM not initialized\n"); + } + return; + } + + // Output PWM values to hardware + for (unsigned i = 0; i < DIRECT_PWM_OUTPUT_CHANNELS && i < sizeof(direct_pwm_page)/sizeof(direct_pwm_page[0]); i++) { + if (_pwm_mask & (1 << i)) { + int ret = up_pwm_servo_set(i, direct_pwm_page[i]); + if (ret < 0 && update_counter % 400 == 0) { + printf("CuberedBridgeSecondary: up_pwm_servo_set(%u, %u) failed: %d\n", i, direct_pwm_page[i], ret); + } + } else if (update_counter % 400 == 0) { + printf("CuberedBridgeSecondary: Channel %u not in PWM mask (0x%02" PRIx32 ")\n", i, _pwm_mask); + } + } + + if (++update_counter % 400 == 0) { + printf("CuberedBridgeSecondary: update_pwm_outputs called (%u times)\n", update_counter); + } +} + +void CuberedBridgeSecondary::set_pwm_armed(bool armed) +{ + if (_pwm_initialized && _pwm_armed != armed) { + _pwm_armed = armed; + // Don't change hardware arm state - PWM hardware stays always enabled + // The flight control system sends appropriate values (disarmed/test/active) + printf("CuberedBridgeSecondary: Flight control %s (mask=0x%02" PRIx32 ")\n", armed ? "ARMED" : "DISARMED", _pwm_mask); + } +} + +extern "C" __EXPORT int cubered_bridge_secondary_main(int argc, char *argv[]) +{ + return ModuleBase::main(CuberedBridgeSecondary::desc, argc, argv); +} diff --git a/src/drivers/cubered_bridge/secondary/cubered_bridge_secondary.h b/src/drivers/cubered_bridge/secondary/cubered_bridge_secondary.h new file mode 100644 index 0000000000..179af5d6f9 --- /dev/null +++ b/src/drivers/cubered_bridge/secondary/cubered_bridge_secondary.h @@ -0,0 +1,132 @@ +/**************************************************************************** + * + * 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. + * + ****************************************************************************/ + +/** + * @file cubered_bridge_secondary.h + * + * CubeRed IO Module - PX4IO simulation for CubeRed Secondary + * + * This module simulates PX4IO functionality on the CubeRed Secondary + * by providing low-latency serial communication on ttyS4. + * + * @author PX4 Development Team + */ + +#pragma once + + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +// Include PX4IO protocol definitions +#include + +#include +#include +#include +#include + +using namespace time_literals; + +class CuberedBridgeSecondary : public ModuleBase +{ +public: + static Descriptor desc; + + CuberedBridgeSecondary(); + ~CuberedBridgeSecondary() override; + + /** @see ModuleBase */ + static int task_spawn(int argc, char *argv[]); + + static int run_trampoline(int argc, char *argv[]); + + static CuberedBridgeSecondary *instantiate(int argc, char *argv[]); + + /** @see ModuleBase */ + static int custom_command(int argc, char *argv[]) + { + return print_usage("unknown command"); + } + + /** @see ModuleBase */ + static int print_usage(const char *reason = nullptr); + + /** @see ModuleBase */ + int print_status() override; + + bool init(); + void run() override; + +private: + static constexpr const char *DEVICE_NAME = "/dev/ttyS1"; + static constexpr speed_t BAUDRATE = B1500000; + static constexpr int POLL_TIMEOUT_MS = 1; // 1ms timeout for low latency + + int _serial_fd{-1}; + + perf_counter_t _loop_perf{perf_alloc(PC_ELAPSED, MODULE_NAME": loop")}; + perf_counter_t _loop_interval_perf{perf_alloc(PC_INTERVAL, MODULE_NAME": loop interval")}; + + // PWM output state + bool _pwm_initialized{false}; + bool _pwm_armed{false}; + uint32_t _pwm_mask{0}; + int _timer_rates[MAX_IO_TIMERS] {}; + + void poll_and_process(); + void process_received_data(IOPacket &packet); + void send_response(IOPacket &packet); + void send_packet(IOPacket &packet); + void send_error_response(); + void send_corrupt_response(); + void handle_read_request(IOPacket &packet); + void handle_write_request(IOPacket &packet); + bool validate_crc(IOPacket &packet); + uint8_t calculate_crc(IOPacket &packet); + + int init_serial(); + int init_pwm(); + void update_pwm_outputs(); + void set_pwm_armed(bool armed); +}; diff --git a/src/lib/metadata/CMakeLists.txt b/src/lib/metadata/CMakeLists.txt index 28f50c214a..49ee24c289 100644 --- a/src/lib/metadata/CMakeLists.txt +++ b/src/lib/metadata/CMakeLists.txt @@ -33,7 +33,7 @@ # actuator metadata generation get_property(module_config_files GLOBAL PROPERTY PX4_MODULE_CONFIG_FILES) -if(CONFIG_BOARD_IO) +if(CONFIG_BOARD_IO OR CONFIG_DRIVERS_CUBERED_BRIDGE_PRIMARY) set(board_with_io_arg --board-with-io) endif() set(generated_actuators_metadata_file ${PX4_BINARY_DIR}/actuators.json) diff --git a/src/lib/parameters/CMakeLists.txt b/src/lib/parameters/CMakeLists.txt index 9cb776e0df..61cc7f7883 100644 --- a/src/lib/parameters/CMakeLists.txt +++ b/src/lib/parameters/CMakeLists.txt @@ -72,7 +72,7 @@ endif() if(PX4_ETHERNET) set(added_arguments --ethernet) endif() -if(CONFIG_BOARD_IO) +if(CONFIG_BOARD_IO OR CONFIG_DRIVERS_CUBERED_BRIDGE_PRIMARY) set(board_with_io_arg --board-with-io) endif() diff --git a/src/systemcmds/uart8_test/CMakeLists.txt b/src/systemcmds/uart8_test/CMakeLists.txt new file mode 100644 index 0000000000..9bccdefd60 --- /dev/null +++ b/src/systemcmds/uart8_test/CMakeLists.txt @@ -0,0 +1,6 @@ +px4_add_module( + MODULE systemcmds__uart8_test + MAIN uart8_test + SRCS + uart8_test.cpp +) \ No newline at end of file diff --git a/src/systemcmds/uart8_test/Kconfig b/src/systemcmds/uart8_test/Kconfig new file mode 100644 index 0000000000..48575cf300 --- /dev/null +++ b/src/systemcmds/uart8_test/Kconfig @@ -0,0 +1,5 @@ +menuconfig SYSTEMCMDS_UART8_TEST + bool "uart8_test" + default n + ---help--- + Enable support for uart8_test command \ No newline at end of file diff --git a/src/systemcmds/uart8_test/uart8_test.cpp b/src/systemcmds/uart8_test/uart8_test.cpp new file mode 100644 index 0000000000..7ad5789fc8 --- /dev/null +++ b/src/systemcmds/uart8_test/uart8_test.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** + * + * 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. + * + ****************************************************************************/ + +/** + * @file uart8_test.cpp + * + * UART8 test command - debug UART8 transmission issues + * + * @author PX4 Development Team + */ + +#include +#include +#include + +#include +#include +#include +#include + +static void debug_uart8_registers(); + +extern "C" __EXPORT int uart8_test_main(int argc, char *argv[]); + +int uart8_test_main(int argc, char *argv[]) +{ + if (argc < 2) { + PX4_INFO("Usage: uart8_test "); + PX4_INFO(" or: uart8_test debug"); + return 1; + } + + if (strcmp(argv[1], "debug") == 0) { + debug_uart8_registers(); + return 0; + } + + // Test UART8 transmission with provided message + PX4_INFO("=== UART8 Test Command ==="); + + // Check GPIO/clock state before test + debug_uart8_registers(); + + int fd = ::open("/dev/ttyS2", O_WRONLY | O_NOCTTY); + + if (fd < 0) { + PX4_ERR("Failed to open /dev/ttyS2: %s", strerror(errno)); + return 1; + } + + // Prepare message + char message[256]; + snprintf(message, sizeof(message), "UART8_CMD_TEST: %s\n", argv[1]); + + // Check clock before write + const uint32_t RCC_BASE = 0x58024400; + volatile uint32_t *rcc_apb1lenr = (volatile uint32_t *)(RCC_BASE + 0xE8); + uint32_t clock_before = (*rcc_apb1lenr >> 31) & 1; + + ssize_t bytes_written = ::write(fd, message, strlen(message)); + + uint32_t clock_after = (*rcc_apb1lenr >> 31) & 1; + + PX4_INFO("Wrote %d bytes to UART8: '%s'", (int)bytes_written, message); + PX4_INFO("Clock before/after write: %lu/%lu", clock_before, clock_after); + + ::fsync(fd); + ::close(fd); + + // Check GPIO/clock state after test + debug_uart8_registers(); + + return 0; +} + +static void debug_uart8_registers() +{ + // STM32H7 register addresses + const uint32_t UART8_BASE = 0x40007c00; + const uint32_t GPIOE_BASE = 0x58020000; + const uint32_t RCC_BASE = 0x58024400; + + // Read registers + volatile uint32_t *uart8_cr1 = (volatile uint32_t *)(UART8_BASE + 0x00); + volatile uint32_t *uart8_isr = (volatile uint32_t *)(UART8_BASE + 0x1C); + volatile uint32_t *gpioe_afrl = (volatile uint32_t *)(GPIOE_BASE + 0x20); + volatile uint32_t *gpioe_moder = (volatile uint32_t *)(GPIOE_BASE + 0x00); + volatile uint32_t *rcc_apb1lenr = (volatile uint32_t *)(RCC_BASE + 0xE8); + + uint32_t afrl_val = *gpioe_afrl; + uint32_t pe0_af = (afrl_val >> 0) & 0xF; + uint32_t pe1_af = (afrl_val >> 4) & 0xF; + uint32_t moder_val = *gpioe_moder; + uint32_t pe0_mode = (moder_val >> 0) & 3; + uint32_t pe1_mode = (moder_val >> 2) & 3; + uint32_t uart8_clock = (*rcc_apb1lenr >> 31) & 1; + + PX4_INFO("=== UART8 Debug ==="); + PX4_INFO("PE0: mode=%lu, af=%lu %s", pe0_mode, pe0_af, (pe0_af == 8) ? "(UART8_RX)" : ""); + PX4_INFO("PE1: mode=%lu, af=%lu %s", pe1_mode, pe1_af, (pe1_af == 8) ? "(UART8_TX)" : ""); + PX4_INFO("UART8 clock: %lu %s", uart8_clock, uart8_clock ? "(enabled)" : "(disabled)"); + PX4_INFO("UART8 CR1: 0x%08lx, ISR: 0x%08lx", *uart8_cr1, *uart8_isr); +}