feat: Radiomaster TX15 support (#6484)

Co-authored-by: Malte Langermann <54738901+gagarinlg@users.noreply.github.com>
Co-authored-by: 3djc <3djc@gh.com>
Co-authored-by: raphaelcoeffic <1050031+raphaelcoeffic@users.noreply.github.com>
Co-authored-by: philmoz <phil.a.mitchell@gmail.com>
Co-authored-by: Peter Feerick <peter.feerick@gmail.com>
This commit is contained in:
3djc
2025-08-20 09:13:30 +10:00
committed by GitHub
co-authored by Malte Langermann 3djc raphaelcoeffic philmoz Peter Feerick
parent 3a00c0812b
commit 324b2c7761
82 changed files with 5745 additions and 201 deletions
+2
View File
@@ -43,6 +43,7 @@ jobs:
matrix:
target:
- x9dp2019
- tx15
- tx16s
- nv14
- el18
@@ -99,6 +100,7 @@ jobs:
- tprov2;tpros;bumblebee
- t20;t20v2;t14
- tx12mk2;boxer;gx12
- tx15
- tx16s
- f16
- v12;v14;v16
+1
View File
@@ -36,6 +36,7 @@ jobs:
- mt12
- nb4p
- st16
- tx15
container:
image: ghcr.io/edgetx/edgetx-dev:latest
volumes:
+12 -4
View File
@@ -135,6 +135,8 @@ uint32_t Boards::getFourCC(Type board)
return 0x4078746F;
case BOARD_RADIOMASTER_TX16S:
return 0x3878746F;
case BOARD_RADIOMASTER_TX15:
return 0x4978746F;
case BOARD_RADIOMASTER_TX12:
return 0x4178746F;
case BOARD_RADIOMASTER_TX12_MK2:
@@ -210,6 +212,7 @@ int Boards::getEEpromSize(Board::Type board)
case BOARD_JUMPER_T16:
case BOARD_JUMPER_T18:
case BOARD_RADIOMASTER_TX16S:
case BOARD_RADIOMASTER_TX15:
case BOARD_FLYSKY_NV14:
case BOARD_FLYSKY_EL18:
case BOARD_FLYSKY_PA01:
@@ -269,6 +272,7 @@ int Boards::getFlashSize(Type board)
case BOARD_JUMPER_T16:
case BOARD_JUMPER_T18:
case BOARD_RADIOMASTER_TX16S:
case BOARD_RADIOMASTER_TX15:
case BOARD_FLYSKY_NV14:
case BOARD_FLYSKY_EL18:
case BOARD_FLYSKY_PA01: // 8MB SDRAM
@@ -380,7 +384,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
case LcdHeight:
if (IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board))
return 480;
else if (IS_FAMILY_PL18(board) || IS_JUMPER_T15(board) || IS_FLYSKY_ST16(board))
else if (IS_FAMILY_PL18(board) || IS_JUMPER_T15(board) || IS_FLYSKY_ST16(board) || IS_RADIOMASTER_TX15(board))
return 320;
else if (IS_FLYSKY_PA01(board))
return 240;
@@ -390,11 +394,11 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
return 64;
case LcdWidth:
if (IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board) || IS_FLYSKY_PA01(board))
if (IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board) || IS_FLYSKY_PA01(board))
return 320;
else if (IS_FAMILY_PL18(board) || IS_FLYSKY_ST16(board))
return 480;
else if (IS_FAMILY_HORUS_OR_T16(board))
else if (IS_FAMILY_HORUS_OR_T16(board) || IS_RADIOMASTER_TX15(board))
return 480;
else if (IS_TARANIS_SMALL(board))
return 128;
@@ -418,7 +422,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
return IS_RADIOMASTER_MT12(board);
case FunctionSwitchColors:
return IS_RADIOMASTER_GX12(board) || IS_FLYSKY_ST16(board) || IS_FLYSKY_PA01(board);
return IS_RADIOMASTER_GX12(board) || IS_FLYSKY_ST16(board) || IS_FLYSKY_PA01(board) || IS_RADIOMASTER_TX15(board);
default:
return getBoardJson(board)->getCapability(capability);
@@ -648,6 +652,8 @@ QString Boards::getBoardName(Board::Type board)
return "Radiomaster TX12 Mark II";
case BOARD_RADIOMASTER_TX16S:
return "Radiomaster TX16S";
case BOARD_RADIOMASTER_TX15:
return "Radiomaster TX15";
case BOARD_RADIOMASTER_ZORRO:
return "Radiomaster Zorro";
case BOARD_RADIOMASTER_GX12:
@@ -782,6 +788,7 @@ int Boards::getDefaultInternalModules(Board::Type board)
case BOARD_FATFISH_F16:
case BOARD_HELLORADIOSKY_V14:
case BOARD_HELLORADIOSKY_V16:
case BOARD_RADIOMASTER_TX15:
case BOARD_IFLIGHT_COMMANDO8:
case BOARD_JUMPER_BUMBLEBEE:
case BOARD_JUMPER_T12MAX:
@@ -848,6 +855,7 @@ void Boards::getBattRange(Board::Type board, int& vmin, int& vmax, unsigned int&
case BOARD_X10:
case BOARD_X10_EXPRESS:
case BOARD_RADIOMASTER_TX16S:
case BOARD_RADIOMASTER_TX15:
case BOARD_JUMPER_T16:
case BOARD_JUMPER_T18:
case BOARD_JUMPER_T20:
+9 -2
View File
@@ -64,6 +64,7 @@ namespace Board {
BOARD_JUMPER_T15,
BOARD_JUMPER_T16,
BOARD_RADIOMASTER_TX16S,
BOARD_RADIOMASTER_TX15,
BOARD_JUMPER_T18,
BOARD_JUMPER_T20,
BOARD_RADIOMASTER_TX12,
@@ -561,6 +562,11 @@ inline bool IS_RADIOMASTER_TX16S(Board::Type board)
return board == Board::BOARD_RADIOMASTER_TX16S;
}
inline bool IS_RADIOMASTER_TX15(Board::Type board)
{
return board == Board::BOARD_RADIOMASTER_TX15;
}
inline bool IS_RADIOMASTER_TX12(Board::Type board)
{
return board == Board::BOARD_RADIOMASTER_TX12;
@@ -618,12 +624,13 @@ inline bool IS_HELLORADIOSKY_V16(Board::Type board)
inline bool IS_FAMILY_T16(Board::Type board)
{
return board == Board::BOARD_JUMPER_T15 ||
return board == Board::BOARD_JUMPER_T15 ||
board == Board::BOARD_JUMPER_T16 ||
board == Board::BOARD_JUMPER_T18 ||
board == Board::BOARD_RADIOMASTER_TX16S ||
board == Board::BOARD_FATFISH_F16 ||
board == Board::BOARD_HELLORADIOSKY_V16;
board == Board::BOARD_HELLORADIOSKY_V16 ||
board == Board::BOARD_RADIOMASTER_TX15;
}
inline bool IS_FAMILY_T12(Board::Type board)
@@ -233,6 +233,8 @@ void GeneralSettings::init()
strcpy(bluetoothName, "pl18u");
else if (IS_FLYSKY_ST16(board))
strcpy(bluetoothName, "st16");
else if (IS_RADIOMASTER_TX15(board))
strcpy(bluetoothName, "tx15");
else if (IS_FAMILY_HORUS_OR_T16(board))
strcpy(bluetoothName, "horus");
else if (IS_TARANIS_X9E(board) || IS_TARANIS_SMALL(board))
@@ -326,7 +326,7 @@ int OpenTxFirmware::getCapability(::Capability capability)
IS_JUMPER_T15(board) || IS_JUMPER_T18(board) || IS_JUMPER_T20(board) || IS_JUMPER_TPRO(board) ||
IS_RADIOMASTER_BOXER(board) || IS_RADIOMASTER_GX12(board) || IS_RADIOMASTER_MT12(board) ||
IS_RADIOMASTER_POCKET(board) || IS_RADIOMASTER_TX12(board) || IS_RADIOMASTER_TX12_MK2(board) ||
IS_RADIOMASTER_TX16S(board) || IS_RADIOMASTER_ZORRO(board));
IS_RADIOMASTER_TX16S(board) || IS_RADIOMASTER_ZORRO(board) || IS_RADIOMASTER_TX15(board));
case HasSoftwareSerialPower:
return IS_RADIOMASTER_TX16S(board);
case HasIntModuleMulti:
@@ -818,6 +818,13 @@ void registerOpenTxFirmwares()
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, FLEX);
/* Radiomaster TX15 board */
firmware = new OpenTxFirmware(FIRMWAREID("tx15"), Firmware::tr("Radiomaster TX15"), BOARD_RADIOMASTER_TX15);
addOpenTxFrskyOptions(firmware);
addOpenTxRfOptions(firmware, FLEX);
firmware->addOptionsGroup({opt_bt, opt_internal_gps});
registerOpenTxFirmware(firmware);
/* Radiomaster TX16S board */
firmware = new OpenTxFirmware(FIRMWAREID("tx16s"), Firmware::tr("Radiomaster TX16S / SE / Hall / Masterfire"), BOARD_RADIOMASTER_TX16S);
addOpenTxFrskyOptions(firmware);
+2 -1
View File
@@ -31,12 +31,13 @@
["Jumper T-Pro V2", "tprov2-"],
["Jumper T-Pro S", "tpros-"],
["RadioMaster Boxer", "boxer-"],
["RadioMaster GX12", "gx12-"]
["RadioMaster MT12","mt12-"],
["RadioMaster Pocket", "pocket-"],
["RadioMaster TX12MK2", "tx12mk2-"],
["RadioMaster TX15", "tx15s-"],
["RadioMaster TX16S", "tx16s-"],
["RadioMaster Zorro","zorro-"],
["RadioMaster GX12", "gx12-"]
],
"changelog": "- Major initial bug fixes"
}
+9 -1
View File
@@ -1,7 +1,7 @@
include(CMakeForceCompiler)
include(Bitmaps)
set(PCB_TYPES X9LITE X9LITES X7 XLITE XLITES X9D X9D+ X9E X10 X12S NV14 PL18 ST16 PA01)
set(PCB_TYPES X9LITE X9LITES X7 XLITE XLITES X9D X9D+ X9E X10 X12S NV14 PL18 ST16 PA01 TX15)
set(RADIO_LANGUAGES CN CZ DA DE EN ES FI FR HE HU IT JP KO NL PL PT RU SE SK TW UA)
set(TTS_LANGUAGES CN CZ DA DE EN ES FR HE HU IT JP KO NL PL PT RU SE SK UA)
@@ -90,6 +90,8 @@ elseif(PCB STREQUAL ST16)
include(targets/st16/CMakeLists.txt)
elseif(PCB STREQUAL PA01)
include(targets/pa01/CMakeLists.txt)
elseif(PCB STREQUAL TX15)
include(targets/tx15/CMakeLists.txt)
elseif(PCB STREQUAL STM32H7S78_DK)
include(targets/stm32h7s78-dk/CMakeLists.txt)
elseif(PCB STREQUAL X9E OR PCB STREQUAL X9D+ OR PCB STREQUAL X9D OR PCB STREQUAL X7 OR PCB STREQUAL X9LITE OR PCB STREQUAL X9LITES OR PCB STREQUAL XLITE OR PCB STREQUAL XLITES)
@@ -626,6 +628,12 @@ if (DEFINED TARGET_EXTRAM_SIZE)
)
endif()
if (DEFINED TARGET_PSRAM_START)
target_link_options(firmware PRIVATE
-Wl,--defsym=__PSRAM_START__=${TARGET_PSRAM_START}
)
endif()
if (LUA)
# Lua needs %g and %f
target_link_options(firmware PRIVATE
+3 -1
View File
@@ -79,7 +79,9 @@ static void rgbLedStart()
LED_STRIP_REFRESH_PERIOD, true);
}
timer_start(&_refresh_timer);
if (timer_start(&_refresh_timer) != 0) {
TRACE("Failed to start RGB LED refresh timer");
};
}
void rgbLedStop()
+6
View File
@@ -83,6 +83,12 @@ if (DEFINED TARGET_EXTRAM_SIZE)
)
endif()
if (DEFINED TARGET_PSRAM_START)
target_link_options(bootloader PRIVATE
-Wl,--defsym=__PSRAM_START__=${TARGET_PSRAM_START}
)
endif()
if (ENABLE_BOOTLOADER_DEBUG)
target_compile_definitions(board_bl PRIVATE -DDEBUG)
target_compile_definitions(bootloader PRIVATE -DDEBUG)
-4
View File
@@ -114,10 +114,6 @@ void bootloaderInitApp()
rotaryEncoderInit();
#endif
#if defined(DEBUG)
initSerialPorts();
#endif
__enable_irq();
TRACE("\nBootloader started :)");
+3 -1
View File
@@ -88,7 +88,7 @@ static inline void check_struct()
#if defined(PCBXLITES)
CHKSIZE(RadioData, 945);
#elif defined(RADIO_ST16) || defined(PCBPA01)
#elif defined(RADIO_ST16) || defined(PCBPA01) || defined(RADIO_TX15)
CHKSIZE(RadioData, 1159);
#elif defined(COLORLCD)
CHKSIZE(RadioData, 1039);
@@ -126,6 +126,8 @@ static inline void check_struct()
CHKSIZE(ModelData, 27522);
#elif defined(RADIO_T15)
CHKSIZE(ModelData, 27683);
#elif defined(RADIO_TX15)
CHKSIZE(ModelData, 27761);
#elif defined(RADIO_H7RS)
// CHKSIZE()
#elif defined(PCBHORUS)
+182
View File
@@ -0,0 +1,182 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/*
WARNING: while this ICM42607C belong to the ICM426xx familly, it is NOT compatible
with code for generic ICM4267XX. All register have different addresses
*/
#include "edgetx.h"
#include "hal/i2c_driver.h"
#include "stm32_i2c_driver.h"
#include "icm42607C.h"
#include "imu_filter.h"
#include "stm32_gpio.h"
#include "inactivity_timer.h"
#include "hal.h"
int16_t getGyroTemperature()
{
uint8_t reg = TEMP_DATA_X0_REG;
uint8_t buf[2] = {0};
if (stm32_i2c_read(IMU_I2C_BUS, ICM426xx_I2C_ADDR, reg, 1, buf, 2, 1000) < 0) {
TRACE("ICM426xx ERROR: TEMP_DATA_X0_REG i2c read error");
return -1;
}
return (((buf[0] << 8) | buf[1]) / 128) + 25;
}
int write_cmd(uint8_t reg, uint8_t val)
{
return i2c_write(IMU_I2C_BUS, ICM426xx_I2C_ADDR, reg, 1, &val, 1);
}
#if defined(IMU_INT_GPIO)
static void imu_exti_isr(void)
{
inactivityTimerReset(ActivitySource::MainControls);
}
#endif
static int write_mreg1(uint8_t reg, uint8_t val) {
if (write_cmd(BLK_SEL_W_REG, 0x00) < 0) return -1;
if (write_cmd(MADDR_W_REG, reg) < 0) return -1;
if (write_cmd(M_W_REG, val) < 0) return -1;
delay_us(10); //42627-pdf p12“Accessing MREG1, MREG2 And MREG3 Registers
return 0;
}
int gyroInit(void)
{
TRACE("ICM426xx I2C Init");
if (i2c_init(IMU_I2C_BUS) < 0) {
TRACE("ICM426xx ERROR: i2c_init bus error");
return -1;
}
if (i2c_dev_ready(IMU_I2C_BUS, ICM426xx_I2C_ADDR) < 0) {
TRACE("ICM426xx device init error");
return -1;
}
uint8_t data = 0;
if (stm32_i2c_read(IMU_I2C_BUS, ICM426xx_I2C_ADDR, 0x75, 1, &data, 1, 1000) < 0) {
TRACE("ICM426xx ERROR: i2c read error");
return -1;
}
if (data != 0x61) {
TRACE("ICM426xx ERROR: this code only works on ICM42607C");
return -1;
}
if(write_cmd(SIGNAL_PATH_RESET, SOFT_RESET_CMD) < 0) {
TRACE("ICM426xx ERROR: SOFT_RESET_CMD error");
return -1;
}
delay_ms(100);
if(write_cmd(PWR_MGMT0_REG, PWR_MGMT0_ENABLE) < 0) {
TRACE("ICM426xx ERROR: PWR_MGMT0_REG error");
return -1;
}
delay_ms(10);
// Set gyro to 2000 dps, 1kHz ODR
if(write_cmd(GYRO_CONFIG0_REG, GYRO_ODR_1KHZ) < 0) {
TRACE("ICM426xx ERROR: GYRO_CONFIG0_REG error");
return -1;
}
delay_ms(1);
// Set accel to ±4g, 1kHz ODR
if (write_cmd(ACCEL_CONFIG0_REG, ACCEL_ODR_1KHZ) < 0) {
TRACE("ICM426xx ERROR: ACCEL_CONFIG0_REG error");
return -1;
}
delay_ms(1);
if (write_cmd(INT_CONFIG_REG, 0x00) < 0) {
TRACE("ICM426xx ERROR: INT_CONFIG_REG error");
return -1;
}
delay_ms(1);
#if defined(IMU_INT_GPIO)
// CCEL_WOM_X_THR:0-255(0-1g),0x10--16mg
if (write_mreg1(ACCEL_WOM_X_THR_REG, 0xFE) < 0) return -1;
if (write_mreg1(ACCEL_WOM_Y_THR_REG, 0xFE) < 0) return -1;
if (write_mreg1(ACCEL_WOM_Z_THR_REG, 0xFE) < 0) return -1;
delay_ms(1);
// config WoM
if (write_cmd(WOM_CONFIG_REG, 0x03) < 0) return -1; // OR mode
delay_ms(1);
// enable INT1
if (write_cmd(INT_SOURCE1_REG, 0x07) < 0) return -1; // XYZ interrupt
delay_ms(1);
// config INT1 pin
if (write_cmd(INT_CONFIG_REG, 0x00) < 0) return -1;
gpio_init_int(IMU_INT_GPIO, GPIO_IN_PU, GPIO_FALLING, imu_exti_isr);
#endif
return 0;
}
int gyroRead(uint8_t buffer[IMU_BUFFER_LENGTH])
{
IMU_RawData_t imu_raw;
IMU_FilteredData_t *filtered;
uint8_t buf[6];
uint8_t reg = GYRO_DATA_X0_REG;
if (stm32_i2c_read(IMU_I2C_BUS, ICM426xx_I2C_ADDR, reg, 1, buf, 6, 1000) < 0) {
TRACE("ICM426xx ERROR: i2c read error");
return -1;
}
imu_raw.gyro_x = -((int16_t)(buf[0] << 8) | buf[1]); // x
imu_raw.gyro_y = -((int16_t)(buf[2] << 8) | buf[3]); // y
imu_raw.gyro_z = ((int16_t)(buf[4] << 8) | buf[5]); // z
reg = ACCEL_DATA_X0_REG;
if (stm32_i2c_read(IMU_I2C_BUS, ICM426xx_I2C_ADDR, reg, 1, buf, 6, 1000) < 0) {
TRACE("ICM426xx ERROR: i2c read error");
return -1;
}
imu_raw.accel_x = ((int16_t)(buf[0] << 8) | buf[1]); // x
imu_raw.accel_y = ((int16_t)(buf[2] << 8) | buf[3]); // y
imu_raw.accel_z = ((int16_t)(buf[4] << 8) | buf[5]); // z
// Process through filters
process_imu_data(&imu_raw);
filtered = get_filtered_imu_data();
*(int16_t*)&buffer[6] = -(int16_t)filtered->accel_x; // x
*(int16_t*)&buffer[8] = -(int16_t)filtered->accel_y; // y
*(int16_t*)&buffer[10] = (int16_t)filtered->accel_z; // z
return 0;
}
+70
View File
@@ -0,0 +1,70 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/*
WARNING: while this ICM42607C belong to the ICM426xx familly, it is NOT compatible
with code for generic ICM4267XX. All register have different addresses
*/
#pragma once
#define ICM426xx_I2C_ADDR 0x68
// Register addresses
#define WHO_AM_I_REG 0x75
#define PWR_MGMT0_REG 0x1F
#define SIGNAL_PATH_RESET 0x02
#define ACCEL_CONFIG0_REG 0x21
#define GYRO_CONFIG0_REG 0x20
#define INT_CONFIG_REG 0x06
#define TEMP_DATA_X0_REG 0x09
// Config values
#define SOFT_RESET_CMD 0x10
#define PWR_MGMT0_ENABLE 0x0F // ACCEL_LNM + GYRO_LNM
#define ACCEL_ODR_1KHZ 0x45 // Accel 1 kHz ±4g
#define GYRO_ODR_1KHZ 0x05 // Gyro 1 kHz ±2000 dps
#define GYRO_DATA_X0_REG 0x11
#define ACCEL_DATA_X0_REG 0x0B
#define BLK_SEL_W_REG 0x79
#define MADDR_W_REG 0x7A
#define M_W_REG 0x7B
#define ACCEL_WOM_X_THR_REG 0x4B
#define ACCEL_WOM_Y_THR_REG 0x4C
#define ACCEL_WOM_Z_THR_REG 0x4D
#define WOM_CONFIG_REG 0x27
#define INT_SOURCE1_REG 0x2C
#define INT_CONFIG_REG 0x06
#define INT_STATUS2_REG 0x3B
typedef struct {
float fTemperatureDegC; //°C
float fAccX, fAccY, fAccZ; // m/s^2
float fGyroXradps, fGyroYradps, fGyroZradps; // rad/s
} sIMUoutput;
extern sIMUoutput IMUoutput;
int gyroInit(void);
int gyroRead(unsigned char*);
+180
View File
@@ -0,0 +1,180 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "edgetx.h"
#include "imu_filter.h"
#include <math.h>
#include <string.h>
// Filter parameters
#define COMPLEMENTARY_ALPHA 0.92f // Complementary filter coefficient
#define LP_FILTER_ALPHA 0.9f // Low-pass filter coefficient
#define SAMPLE_TIME_S 0.005f // Gyro is read every 5ms as part of execMixerFrequentActions()
#define RAD_TO_DEG 57.2958f
#define DEG_TO_RAD 0.0174533f
// Filter state variables
static IMU_FilteredData_t filtered_data = {0};
static float prev_accel[3] = {0};
static float prev_gyro[3] = {0};
static uint8_t filter_initialized = 0;
// Low-pass filter implementation
float low_pass_filter(float new_value, float prev_value, float alpha) {
return alpha * prev_value + (1.0f - alpha) * new_value;
}
// Calculate roll and pitch from accelerometer data
void calculate_accel_angles(float ax, float ay, float az, float *roll, float *pitch) {
// Normalize accelerometer data
float norm = sqrtf(ax*ax + ay*ay + az*az);
if (norm == 0.0f) return;
ax /= norm;
ay /= norm;
az /= norm;
// Calculate angles
*roll = atan2f(ay, sqrtf(ax*ax + az*az));
*pitch = atan2f(-ax, sqrtf(ay*ay + az*az));
}
// Complementary filter for attitude estimation
void complementary_filter(IMU_RawData_t *raw_data, float dt) {
float accel_roll, accel_pitch;
// Calculate angles from accelerometer
calculate_accel_angles(raw_data->accel_x, raw_data->accel_y, raw_data->accel_z,
&accel_roll, &accel_pitch);
if (!filter_initialized) {
// Initialize filter with accelerometer angles
filtered_data.roll = accel_roll;
filtered_data.pitch = accel_pitch;
filtered_data.yaw = 0.0f;
filter_initialized = 1;
} else {
// Integrate gyroscope data
float gyro_roll = filtered_data.roll + raw_data->gyro_x * dt;
float gyro_pitch = filtered_data.pitch + raw_data->gyro_y * dt;
float gyro_yaw = filtered_data.yaw + raw_data->gyro_z * dt;
// Apply complementary filter
filtered_data.roll = COMPLEMENTARY_ALPHA * gyro_roll +
(1.0f - COMPLEMENTARY_ALPHA) * accel_roll;
filtered_data.pitch = COMPLEMENTARY_ALPHA * gyro_pitch +
(1.0f - COMPLEMENTARY_ALPHA) * accel_pitch;
filtered_data.yaw = gyro_yaw; // No magnetometer correction in this example
// Keep yaw within -π to π range
while (filtered_data.yaw > M_PI) filtered_data.yaw -= 2.0f * M_PI;
while (filtered_data.yaw < -M_PI) filtered_data.yaw += 2.0f * M_PI;
}
}
// Apply low-pass filter to raw sensor data
void apply_lowpass_filter(IMU_RawData_t *raw_data) {
// Filter accelerometer data
filtered_data.accel_x = low_pass_filter(raw_data->accel_x, prev_accel[0], LP_FILTER_ALPHA);
filtered_data.accel_y = low_pass_filter(raw_data->accel_y, prev_accel[1], LP_FILTER_ALPHA);
filtered_data.accel_z = low_pass_filter(raw_data->accel_z, prev_accel[2], LP_FILTER_ALPHA);
// Filter gyroscope data
filtered_data.gyro_x = low_pass_filter(raw_data->gyro_x, prev_gyro[0], LP_FILTER_ALPHA);
filtered_data.gyro_y = low_pass_filter(raw_data->gyro_y, prev_gyro[1], LP_FILTER_ALPHA);
filtered_data.gyro_z = low_pass_filter(raw_data->gyro_z, prev_gyro[2], LP_FILTER_ALPHA);
// Update previous values
prev_accel[0] = filtered_data.accel_x;
prev_accel[1] = filtered_data.accel_y;
prev_accel[2] = filtered_data.accel_z;
prev_gyro[0] = filtered_data.gyro_x;
prev_gyro[1] = filtered_data.gyro_y;
prev_gyro[2] = filtered_data.gyro_z;
}
// Main IMU filter processing function
void process_imu_data(IMU_RawData_t *raw_data) {
// Apply low-pass filtering to raw data
apply_lowpass_filter(raw_data);
// Apply complementary filter for attitude estimation
complementary_filter(raw_data, SAMPLE_TIME_S);
}
// Get filtered IMU data
IMU_FilteredData_t* get_filtered_imu_data(void) {
return &filtered_data;
}
// Reset filter state
void reset_imu_filter(void) {
memset(&filtered_data, 0, sizeof(filtered_data));
memset(prev_accel, 0, sizeof(prev_accel));
memset(prev_gyro, 0, sizeof(prev_gyro));
filter_initialized = 0;
}
// Advanced Kalman filter structure (optional implementation)
typedef struct {
float Q_angle; // Process noise variance for accelerometer
float Q_bias; // Process noise variance for gyro bias
float R_measure; // Measurement noise variance
float angle; // Estimated angle
float bias; // Estimated bias
float rate; // Unbiased rate
float P[2][2]; // Error covariance matrix
} kalman_state_t;
// Kalman filter implementation (more advanced option)
float kalman_filter(kalman_state_t *state, float new_angle, float new_rate, float dt) {
// Prediction step
state->rate = new_rate - state->bias;
state->angle += dt * state->rate;
// Update error covariance
state->P[0][0] += dt * (dt * state->P[1][1] - state->P[0][1] - state->P[1][0] + state->Q_angle);
state->P[0][1] -= dt * state->P[1][1];
state->P[1][0] -= dt * state->P[1][1];
state->P[1][1] += state->Q_bias * dt;
// Innovation
float S = state->P[0][0] + state->R_measure;
float K[2] = {state->P[0][0] / S, state->P[1][0] / S};
float y = new_angle - state->angle;
// Update step
state->angle += K[0] * y;
state->bias += K[1] * y;
// Update error covariance
float P00_temp = state->P[0][0];
float P01_temp = state->P[0][1];
state->P[0][0] -= K[0] * P00_temp;
state->P[0][1] -= K[0] * P01_temp;
state->P[1][0] -= K[1] * P00_temp;
state->P[1][1] -= K[1] * P01_temp;
return state->angle;
}
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#pragma once
// IMU data structure
typedef struct {
float accel_x, accel_y, accel_z; // Accelerometer data (m/s²)
float gyro_x, gyro_y, gyro_z; // Gyroscope data (rad/s)
float mag_x, mag_y, mag_z; // Magnetometer data (optional)
} IMU_RawData_t;
typedef struct {
float roll, pitch, yaw; // Filtered attitude (radians)
float accel_x, accel_y, accel_z; // Filtered acceleration
float gyro_x, gyro_y, gyro_z; // Filtered gyroscope
} IMU_FilteredData_t;
void process_imu_data(IMU_RawData_t *raw_data);
IMU_FilteredData_t* get_filtered_imu_data(void);
+3
View File
@@ -20,6 +20,7 @@
*/
#include "pca95xx.h"
#include "debug.h"
#define REG_INPUT 0x00
#define REG_OUTPUT 0x02
@@ -46,10 +47,12 @@ int pca95xx_init(pca95xx_t* dev, etx_i2c_bus_t bus, uint16_t addr)
dev->output = 0;
if (i2c_init(bus) < 0) {
TRACE("PCA95 bus init error");
return -1;
}
if (i2c_dev_ready(bus, addr) < 0) {
TRACE("PCA95 device init error");
return -1;
}
+22
View File
@@ -23,6 +23,11 @@
#include "hal/i2c_driver.h"
/* WARNING
Ti PCA95 chip do NOT number pin sequentially, it goes PIN0 to PIN7 then PIN10 to PIN17.
So when schematic indicate P10, it is PIN_8 in the following table
*/
#define PCA95XX_PIN_0 (1 << 0)
#define PCA95XX_PIN_1 (1 << 1)
#define PCA95XX_PIN_2 (1 << 2)
@@ -40,6 +45,23 @@
#define PCA95XX_PIN_14 (1 << 14)
#define PCA95XX_PIN_15 (1 << 15)
#define PCA95XX_P0 PCA95XX_PIN_0
#define PCA95XX_P1 PCA95XX_PIN_1
#define PCA95XX_P2 PCA95XX_PIN_2
#define PCA95XX_P3 PCA95XX_PIN_3
#define PCA95XX_P4 PCA95XX_PIN_4
#define PCA95XX_P5 PCA95XX_PIN_5
#define PCA95XX_P6 PCA95XX_PIN_6
#define PCA95XX_P7 PCA95XX_PIN_7
#define PCA95XX_P10 PCA95XX_PIN_8
#define PCA95XX_P11 PCA95XX_PIN_9
#define PCA95XX_P12 PCA95XX_PIN_10
#define PCA95XX_P13 PCA95XX_PIN_11
#define PCA95XX_P14 PCA95XX_PIN_12
#define PCA95XX_P15 PCA95XX_PIN_13
#define PCA95XX_P16 PCA95XX_PIN_14
#define PCA95XX_P17 PCA95XX_PIN_15
typedef struct {
etx_i2c_bus_t bus;
uint16_t addr;
+23
View File
@@ -22,6 +22,7 @@
#include "tas2505.h"
#include "stm32_i2s.h"
#include "timers_driver.h"
#include "hal/audio_driver.h"
#include "debug.h"
@@ -126,3 +127,25 @@ int tas2505_init(tas2505_t* dev)
return 0;
}
// adjust this value for a volume level just above the silence
// values is attenuation in dB, higher value - less volume
// max value is 126
#define VOLUME_MIN_DB 60
void tas2505_set_volume(tas2505_t* dev, uint8_t volume)
{
if (volume > VOLUME_LEVEL_MAX) {
volume = VOLUME_LEVEL_MAX;
}
// maximum volume is 0x00 and total silence is 0xFE
if (volume == 0) {
tas2505_write_reg(dev, TAS2505_SPKVOL1, 0xFE);
tas2505_write_reg(dev, TAS2505_HP_VOL, 0xFE);
} else {
uint32_t vol = (VOLUME_MIN_DB * 2) -
((uint32_t)volume * (VOLUME_MIN_DB * 2)) / VOLUME_LEVEL_MAX;
tas2505_write_reg(dev, TAS2505_SPKVOL1, vol);
tas2505_write_reg(dev, TAS2505_HP_VOL, vol);
}
}
+1
View File
@@ -94,3 +94,4 @@ typedef struct {
int tas2505_probe(tas2505_t* dev, etx_i2c_bus_t bus, uint16_t addr);
int tas2505_init(tas2505_t* dev);
void tas2505_set_volume(tas2505_t* dev, uint8_t volume);
+1 -1
View File
@@ -477,7 +477,7 @@ int uf2_fat_write_block(uint32_t block_no, uint8_t *data)
wr_st->written_mask[pos] |= mask;
wr_st->num_written++;
TRACE_DEBUG("[UF2] wr #%d (%d / %d)\n", bl->blockNo,
state->num_written, bl->numBlocks);
wr_st->num_written, bl->numBlocks);
}
if (wr_st->num_written >= wr_st->num_blocks) {
TRACE_DEBUG("[UF2] done: reboot\n");
+8
View File
@@ -36,6 +36,7 @@
#include "hal/abnormal_reboot.h"
#include "hal/usb_driver.h"
#include "hal/audio_driver.h"
#include "hal/rgbleds.h"
#include "timers_driver.h"
@@ -401,6 +402,9 @@ void generalDefault()
#if defined(MANUFACTURER_RADIOMASTER)
g_eeGeneral.audioMuteEnable = 1;
#if defined(RADIO_TX15)
g_eeGeneral.backlightBright = 50; // Screen looks off if not set high enough
#endif
#endif
// disable Custom Script
@@ -1123,6 +1127,10 @@ void edgeTxClose(uint8_t shutdown)
#endif
sdDone();
#if defined(FUNCTION_SWITCHES_RGB_LEDS)
turnOffRGBLeds();
#endif
}
void edgeTxResume()
+30 -12
View File
@@ -34,8 +34,8 @@
#if LANDSCAPE
static const lv_coord_t col_dsc[] = {
LV_GRID_FR(32), LV_GRID_FR(40), LV_GRID_FR(40), LV_GRID_FR(40), LV_GRID_FR(40),
LV_GRID_FR(32), LV_GRID_FR(40), LV_GRID_FR(40), LV_GRID_FR(40), LV_GRID_FR(40),
LV_GRID_FR(34), LV_GRID_FR(40), LV_GRID_FR(40), LV_GRID_FR(40), LV_GRID_FR(40),
LV_GRID_FR(34), LV_GRID_FR(40), LV_GRID_FR(40), LV_GRID_FR(40), LV_GRID_FR(40),
LV_GRID_TEMPLATE_LAST
};
@@ -91,16 +91,15 @@ class AnaViewWindow : public Window
new StaticText(line, rect_t{}, s);
auto lbl = new DynamicText(
line, rect_t{},
auto lbl = new DynamicText(line, rect_t{},
[=]() {
return std::to_string((int16_t)calibratedAnalogs[i] * 25 / 256);
});
etx_obj_add_style(lbl->getLvObj(), styles->text_align_right, LV_PART_MAIN);
}, COLOR_THEME_PRIMARY1_INDEX, RIGHT);
lbl = new DynamicText(
line, rect_t{}, [=]() { return std::to_string((int16_t)column3(i)); });
etx_obj_add_style(lbl->getLvObj(), styles->text_align_right, LV_PART_MAIN);
lbl = new DynamicText(line, rect_t{},
[=]() {
return std::to_string((int16_t)column3(i));
}, COLOR_THEME_PRIMARY1_INDEX, RIGHT);
if (column4size() > 0) {
lbl = new DynamicText(
@@ -108,8 +107,7 @@ class AnaViewWindow : public Window
[=]() {
return std::string(column4prefix()) +
std::to_string((int16_t)column4(i));
});
etx_obj_add_style(lbl->getLvObj(), (column4size() == 2) ? styles->text_align_left : styles->text_align_right, LV_PART_MAIN);
}, COLOR_THEME_PRIMARY1_INDEX, (column4size() == 2) ? 0 : RIGHT);
#if LANDSCAPE
lv_obj_set_grid_cell(lbl->getLvObj(), LV_GRID_ALIGN_STRETCH,
3 + (i & 1) * 5, column4size(),
@@ -126,11 +124,31 @@ class AnaViewWindow : public Window
lbl = new DynamicText(
line, rect_t{},
[=]() { return std::to_string((int16_t)column5(i)); });
etx_obj_add_style(lbl->getLvObj(), styles->text_align_left, LV_PART_MAIN);
} else {
grid.nextCell();
}
}
#if defined(IMU_ICM4207C) && LANDSCAPE
line = newLine(grid);
lv_obj_set_style_pad_column(line->getLvObj(), PAD_SMALL, LV_PART_MAIN);
new StaticText(line, rect_t{}, "Tilt X");
new DynamicText(
line, rect_t{},
[=]() {
return std::to_string((int16_t) gyro.scaledX());
}, COLOR_THEME_PRIMARY1_INDEX, RIGHT);
for (int i = 0; i < 3; i++) {grid.nextCell();}
new StaticText(line, rect_t{}, "Tilt Y");
new DynamicText(
line, rect_t{},
[=]() {
return std::to_string((int16_t) gyro.scaledY());
}, COLOR_THEME_PRIMARY1_INDEX, RIGHT);
#endif
}
void checkEvents() override { Window::checkEvents(); }
+30 -3
View File
@@ -20,6 +20,8 @@
*/
#include "edgetx.h"
#include "hal.h"
#include "debug.h"
#define _USE_MATH_DEFINES
#include <math.h>
@@ -59,14 +61,24 @@ void Gyro::wakeup()
// stopping the sensor forever
errors = 0;
int16_t gx = values[0];
int16_t gy = values[1];
// int16_t gz = values[2];
#if defined(IMU_ICM4207C)
raw_ax = values[3];
raw_ay = values[4];
int16_t ax = raw_ax - offset_x;
int16_t ay = raw_ay - offset_y;
// Use only ACC value, they are really reliable
outputs[0] = (ax * float(RESX)) / range_x;
outputs[1] = (ay * float(RESX)) / range_y;
#else
int16_t ax = values[3];
int16_t ay = values[4];
int16_t az = values[5];
int16_t gx = values[0];
int16_t gy = values[1];
int16_t gz = values[2];
// integrate gyro
roll -= gx * SCALE_FACT_GYRO * DT;
pitch += gy * SCALE_FACT_GYRO * DT;
@@ -85,6 +97,7 @@ void Gyro::wakeup()
outputs[0] = deg2RESX(roll);
outputs[1] = deg2RESX(pitch);
#endif
}
int16_t Gyro::scaledX()
@@ -103,3 +116,17 @@ int16_t Gyro::scaledY()
// RESX);
return limit<int16_t>(-RESX, outputs[1], RESX);
}
void Gyro::setIMU_X(int16_t offset, int16_t range)
{
if (offset == -1) offset_x = raw_ax;
else offset_x = offset;
range_x = range * 8192 / 180;
}
void Gyro::setIMU_Y(int16_t offset, int16_t range)
{
if (offset == -1) offset_y = raw_ay;
else offset_y = offset;
range_y = range * 8192 / 180;
}
+8
View File
@@ -39,11 +39,19 @@ class Gyro
uint8_t errors = 0;
float roll = 0.0;
float pitch = 0.0;
int16_t offset_x = 0;
int16_t offset_y = 0;
int16_t range_x = 8192;
int16_t range_y = 8192;
int16_t raw_ax = 0;
int16_t raw_ay = 0;
public:
int16_t outputs[2];
void wakeup();
void setIMU_X(int16_t, int16_t);
void setIMU_Y(int16_t, int16_t);
int16_t scaledX();
int16_t scaledY();
+6 -1
View File
@@ -63,7 +63,7 @@ bool getFSLedState(uint8_t index) {
uint32_t getFSLedRGBColor(uint8_t index)
{
return fsGetLedRGB(index);
return fsGetLedRGB(index);
}
#else
void setFSLedOFF(uint8_t index) {
@@ -81,3 +81,8 @@ bool getFSLedState(uint8_t index) {
return fsLedState(index);
}
#endif
void turnOffRGBLeds()
{
rgbLedClearAll();
}
+1
View File
@@ -30,3 +30,4 @@ void setFSLedOFF(uint8_t index);
void setFSLedON(uint8_t index);
bool getFSLedState(uint8_t index);
uint32_t getFSLedRGBColor(uint8_t index);
void turnOffRGBLeds();
+4
View File
@@ -150,6 +150,7 @@ static uint8_t* skipUF2Extensions(uint8_t* data) {
#if defined(STM32) && !defined(SIMU)
void writeUF2FirmwareVersion(void* block)
{
#if !defined(SIMU)
UF2_Block* uf2 = (UF2_Block*)block;
uint8_t* end_data = skipUF2Extensions(uf2->data + uf2->payloadSize);
@@ -189,10 +190,12 @@ void writeUF2FirmwareVersion(void* block)
memcpy(end_data, version, version_len);
}
}
#endif
}
void writeUF2RebootBlock(void* block)
{
#if !defined(SIMU)
extern uint32_t _reboot_cmd;
UF2_Block* uf2 = (UF2_Block*)block;
@@ -209,5 +212,6 @@ void writeUF2RebootBlock(void* block)
uint32_t reboot_addr = BOOTLOADER_ADDRESS;
memcpy(end_data, &reboot_addr, sizeof(reboot_addr));
#endif
}
#endif
+4 -1
View File
@@ -66,6 +66,7 @@ void UF2FirmwareUpdate::flashFirmware(const char* filename,
uint32_t sect_len = drv->get_sector_size(sector);
if (drv->erase_sector(addr) < 0) break;
last_erased = block.targetAddr + sect_len - 1;
TRACE("[UF2] erased %dKB @ 0x%08X", sect_len / 1024, addr);
}
}
@@ -92,7 +93,9 @@ void UF2FirmwareUpdate::flashFirmware(const char* filename,
if (drv) {
uint32_t len = block.payloadSize;
uint8_t* data = (uint8_t*)block.data;
drv->program(addr, data, len);
if (drv->program(addr, data, len) < 0) break;
TRACE("[UF2] written %d bytes @ 0x%08X (%d of %d)", len, addr,
block.blockNo + 1, block.numBlocks);
}
}
+65
View File
@@ -2989,6 +2989,69 @@ static int luaGetStickMode(lua_State* const L)
return 1;
}
/*luadoc
@function setIMU_X(offset, range)
@param offset: integer, offset in angular degree. -1 to offset to current X position
@param range: integer, range in angular degree. 180° max.90 means min/max value will be reached at 45° from offset position
@status current Introduced in 3.0
*/
static int luaSetIMU_X(lua_State* const L)
{
#if defined(IMU)
int16_t offset = luaL_checkinteger(L, 1);
int16_t range = luaL_checkinteger(L, 2);
if (offset < -180 || offset > 180) {
lua_pushboolean(L, false);
return 1;
}
if (range < 0 || range > 180) {
lua_pushboolean(L, false);
return 1;
}
gyro.setIMU_X(offset, range);
#endif
lua_pushboolean(L, true);
return 1;
}
/*luadoc
@function setIMU_Y(offset, range)
@param offset: integer, offset in angular degree. -1 to offset to current Y position
@param range: integer, range in angular degree, 180° max. 90 means min/max value will be reached at 45° from offset position
@status current Introduced in 3.0
*/
static int luaSetIMU_Y(lua_State* const L)
{
#if defined(IMU)
int16_t offset = luaL_checkinteger(L, 1);
int16_t range = luaL_checkinteger(L, 2);
if (offset < -180 || offset > 180) {
lua_pushboolean(L, false);
return 1;
}
if (range < 0 || range > 180) {
lua_pushboolean(L, false);
return 1;
}
gyro.setIMU_Y(offset, range);
#endif
lua_pushboolean(L, true);
return 1;
}
#define KEY_EVENTS(xxx, yyy) \
{ "EVT_"#xxx"_FIRST", LRO_NUMVAL(EVT_KEY_FIRST(yyy)) }, \
{ "EVT_"#xxx"_BREAK", LRO_NUMVAL(EVT_KEY_BREAK(yyy)) }, \
@@ -3084,6 +3147,8 @@ LROT_BEGIN(etxlib, NULL, 0)
LROT_FUNCENTRY( setCFSLedColor, luaSetCFSLedColor )
#endif
LROT_FUNCENTRY( getStickMode, luaGetStickMode )
LROT_FUNCENTRY( setIMU_X, luaSetIMU_X )
LROT_FUNCENTRY( setIMU_Y, luaSetIMU_Y )
LROT_END(etxlib, NULL, 0)
LROT_BEGIN(etxcst, NULL, 0)
+2
View File
@@ -38,6 +38,8 @@ elseif(PCB STREQUAL ST16)
set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_st16.cpp)
elseif(PCB STREQUAL PA01)
set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_pa01.cpp)
elseif(PCB STREQUAL TX15)
set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_tx15.cpp)
elseif(PCB STREQUAL X7)
if(PCBREV STREQUAL TPRO)
set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_tpro.cpp)
+3 -1
View File
@@ -36,10 +36,12 @@
#else
#include "yaml_datastructs_x10.cpp"
#endif
#elif defined(PCBTX15)
#include "yaml_datastructs_tx15.cpp"
#elif defined(PCBPL18)
#if defined(RADIO_NB4P)
#include "yaml_datastructs_nb4p.cpp"
#elif defined(RADIO_NV14_FAMILY)
#elif defined(RADIO_NV14_FAMILY)
#include "yaml_datastructs_nv14_family.cpp"
#elif defined(RADIO_PL18U)
#include "yaml_datastructs_pl18u.cpp"
@@ -0,0 +1,985 @@
// generated by generate_yaml.py
//
// Enums first
//
const struct YamlIdStr enum_BacklightMode[] = {
{ e_backlight_mode_off, "backlight_mode_off" },
{ e_backlight_mode_keys, "backlight_mode_keys" },
{ e_backlight_mode_sticks, "backlight_mode_sticks" },
{ e_backlight_mode_all, "backlight_mode_all" },
{ e_backlight_mode_on, "backlight_mode_on" },
{ 0, NULL }
};
const struct YamlIdStr enum_AntennaModes[] = {
{ ANTENNA_MODE_INTERNAL, "MODE_INTERNAL" },
{ ANTENNA_MODE_ASK, "MODE_ASK" },
{ ANTENNA_MODE_PER_MODEL, "MODE_PER_MODEL" },
{ ANTENNA_MODE_EXTERNAL, "MODE_EXTERNAL" },
{ 0, NULL }
};
const struct YamlIdStr enum_ModuleType[] = {
{ MODULE_TYPE_NONE, "TYPE_NONE" },
{ MODULE_TYPE_PPM, "TYPE_PPM" },
{ MODULE_TYPE_XJT_PXX1, "TYPE_XJT_PXX1" },
{ MODULE_TYPE_ISRM_PXX2, "TYPE_ISRM_PXX2" },
{ MODULE_TYPE_DSM2, "TYPE_DSM2" },
{ MODULE_TYPE_CROSSFIRE, "TYPE_CROSSFIRE" },
{ MODULE_TYPE_MULTIMODULE, "TYPE_MULTIMODULE" },
{ MODULE_TYPE_R9M_PXX1, "TYPE_R9M_PXX1" },
{ MODULE_TYPE_R9M_PXX2, "TYPE_R9M_PXX2" },
{ MODULE_TYPE_R9M_LITE_PXX1, "TYPE_R9M_LITE_PXX1" },
{ MODULE_TYPE_R9M_LITE_PXX2, "TYPE_R9M_LITE_PXX2" },
{ MODULE_TYPE_GHOST, "TYPE_GHOST" },
{ MODULE_TYPE_R9M_LITE_PRO_PXX2, "TYPE_R9M_LITE_PRO_PXX2" },
{ MODULE_TYPE_SBUS, "TYPE_SBUS" },
{ MODULE_TYPE_XJT_LITE_PXX2, "TYPE_XJT_LITE_PXX2" },
{ MODULE_TYPE_FLYSKY_AFHDS2A, "TYPE_FLYSKY_AFHDS2A" },
{ MODULE_TYPE_FLYSKY_AFHDS3, "TYPE_FLYSKY_AFHDS3" },
{ MODULE_TYPE_LEMON_DSMP, "TYPE_LEMON_DSMP" },
{ 0, NULL }
};
const struct YamlIdStr enum_TrainerMultiplex[] = {
{ TRAINER_OFF, "OFF" },
{ TRAINER_ADD, "ADD" },
{ TRAINER_REPL, "REPL" },
{ 0, NULL }
};
const struct YamlIdStr enum_BeeperMode[] = {
{ e_mode_quiet, "mode_quiet" },
{ e_mode_alarms, "mode_alarms" },
{ e_mode_nokeys, "mode_nokeys" },
{ e_mode_all, "mode_all" },
{ 0, NULL }
};
const struct YamlIdStr enum_BluetoothModes[] = {
{ BLUETOOTH_OFF, "OFF" },
{ BLUETOOTH_TELEMETRY, "TELEMETRY" },
{ BLUETOOTH_TRAINER, "TRAINER" },
{ 0, NULL }
};
const struct YamlIdStr enum_Functions[] = {
{ FUNC_OVERRIDE_CHANNEL, "OVERRIDE_CHANNEL" },
{ FUNC_TRAINER, "TRAINER" },
{ FUNC_INSTANT_TRIM, "INSTANT_TRIM" },
{ FUNC_RESET, "RESET" },
{ FUNC_SET_TIMER, "SET_TIMER" },
{ FUNC_ADJUST_GVAR, "ADJUST_GVAR" },
{ FUNC_VOLUME, "VOLUME" },
{ FUNC_SET_FAILSAFE, "SET_FAILSAFE" },
{ FUNC_RANGECHECK, "RANGECHECK" },
{ FUNC_BIND, "BIND" },
{ FUNC_PLAY_SOUND, "PLAY_SOUND" },
{ FUNC_PLAY_TRACK, "PLAY_TRACK" },
{ FUNC_PLAY_VALUE, "PLAY_VALUE" },
{ FUNC_PLAY_SCRIPT, "PLAY_SCRIPT" },
{ FUNC_BACKGND_MUSIC, "BACKGND_MUSIC" },
{ FUNC_BACKGND_MUSIC_PAUSE, "BACKGND_MUSIC_PAUSE" },
{ FUNC_VARIO, "VARIO" },
{ FUNC_HAPTIC, "HAPTIC" },
{ FUNC_LOGS, "LOGS" },
{ FUNC_BACKLIGHT, "BACKLIGHT" },
{ FUNC_SCREENSHOT, "SCREENSHOT" },
{ FUNC_RACING_MODE, "RACING_MODE" },
{ FUNC_DISABLE_TOUCH, "DISABLE_TOUCH" },
{ FUNC_SET_SCREEN, "SET_SCREEN" },
{ FUNC_DISABLE_AUDIO_AMP, "DISABLE_AUDIO_AMP" },
{ FUNC_RGB_LED, "RGB_LED" },
{ FUNC_PUSH_CUST_SWITCH, "PUSH_CUST_SWITCH" },
{ FUNC_TEST, "TEST" },
{ 0, NULL }
};
const struct YamlIdStr enum_SwitchConfig[] = {
{ SWITCH_NONE, "NONE" },
{ SWITCH_TOGGLE, "TOGGLE" },
{ SWITCH_2POS, "2POS" },
{ SWITCH_3POS, "3POS" },
{ SWITCH_GLOBAL, "GLOBAL" },
{ SWITCH_none, "none" },
{ SWITCH_toggle, "toggle" },
{ SWITCH_2pos, "2pos" },
{ SWITCH_3pos, "3pos" },
{ 0, NULL }
};
const struct YamlIdStr enum_fsStartPositionType[] = {
{ FS_START_OFF, "START_OFF" },
{ FS_START_ON, "START_ON" },
{ FS_START_PREVIOUS, "START_PREVIOUS" },
{ 0, NULL }
};
const struct YamlIdStr enum_booleanEnum[] = {
{ BOOL_OFF, "OFF" },
{ BOOL_ON, "ON" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
{ TMRMODE_OFF, "OFF" },
{ TMRMODE_ON, "ON" },
{ TMRMODE_START, "START" },
{ TMRMODE_THR, "THR" },
{ TMRMODE_THR_REL, "THR_REL" },
{ TMRMODE_THR_START, "THR_START" },
{ 0, NULL }
};
const struct YamlIdStr enum_MixerMultiplex[] = {
{ MLTPX_ADD, "ADD" },
{ MLTPX_MUL, "MUL" },
{ MLTPX_REPL, "REPL" },
{ 0, NULL }
};
const struct YamlIdStr enum_MixSources[] = {
{ MIXSRC_NONE, "NONE" },
{ MIXSRC_TILT_X, "TILT_X" },
{ MIXSRC_TILT_Y, "TILT_Y" },
{ MIXSRC_SPACEMOUSE_A, "SPACEMOUSE_A" },
{ MIXSRC_SPACEMOUSE_B, "SPACEMOUSE_B" },
{ MIXSRC_SPACEMOUSE_C, "SPACEMOUSE_C" },
{ MIXSRC_SPACEMOUSE_D, "SPACEMOUSE_D" },
{ MIXSRC_SPACEMOUSE_E, "SPACEMOUSE_E" },
{ MIXSRC_SPACEMOUSE_F, "SPACEMOUSE_F" },
{ MIXSRC_MIN, "MIN" },
{ MIXSRC_MAX, "MAX" },
{ MIXSRC_TX_VOLTAGE, "TX_VOLTAGE" },
{ MIXSRC_TX_TIME, "TX_TIME" },
{ MIXSRC_TX_GPS, "TX_GPS" },
{ 0, NULL }
};
const struct YamlIdStr enum_LogicalSwitchesFunctions[] = {
{ LS_FUNC_NONE, "FUNC_NONE" },
{ LS_FUNC_VEQUAL, "FUNC_VEQUAL" },
{ LS_FUNC_VALMOSTEQUAL, "FUNC_VALMOSTEQUAL" },
{ LS_FUNC_VPOS, "FUNC_VPOS" },
{ LS_FUNC_VNEG, "FUNC_VNEG" },
{ LS_FUNC_APOS, "FUNC_APOS" },
{ LS_FUNC_ANEG, "FUNC_ANEG" },
{ LS_FUNC_AND, "FUNC_AND" },
{ LS_FUNC_OR, "FUNC_OR" },
{ LS_FUNC_XOR, "FUNC_XOR" },
{ LS_FUNC_EDGE, "FUNC_EDGE" },
{ LS_FUNC_EQUAL, "FUNC_EQUAL" },
{ LS_FUNC_GREATER, "FUNC_GREATER" },
{ LS_FUNC_LESS, "FUNC_LESS" },
{ LS_FUNC_DIFFEGREATER, "FUNC_DIFFEGREATER" },
{ LS_FUNC_ADIFFEGREATER, "FUNC_ADIFFEGREATER" },
{ LS_FUNC_TIMER, "FUNC_TIMER" },
{ LS_FUNC_STICKY, "FUNC_STICKY" },
{ 0, NULL }
};
const struct YamlIdStr enum_SwashType[] = {
{ SWASH_TYPE_NONE, "TYPE_NONE" },
{ SWASH_TYPE_120, "TYPE_120" },
{ SWASH_TYPE_120X, "TYPE_120X" },
{ SWASH_TYPE_140, "TYPE_140" },
{ SWASH_TYPE_90, "TYPE_90" },
{ 0, NULL }
};
const struct YamlIdStr enum_SwitchSources[] = {
{ SWSRC_NONE, "NONE" },
{ SWSRC_ON, "ON" },
{ SWSRC_ONE, "ONE" },
{ SWSRC_TELEMETRY_STREAMING, "TELEMETRY_STREAMING" },
{ SWSRC_RADIO_ACTIVITY, "RADIO_ACTIVITY" },
{ SWSRC_TRAINER_CONNECTED, "TRAINER_CONNECTED" },
{ SWSRC_OFF, "OFF" },
{ 0, NULL }
};
const struct YamlIdStr enum_PotsWarnMode[] = {
{ POTS_WARN_OFF, "WARN_OFF" },
{ POTS_WARN_MANUAL, "WARN_MANUAL" },
{ POTS_WARN_AUTO, "WARN_AUTO" },
{ 0, NULL }
};
const struct YamlIdStr enum_ModelOverridableEnable[] = {
{ OVERRIDE_GLOBAL, "GLOBAL" },
{ OVERRIDE_OFF, "OFF" },
{ OVERRIDE_ON, "ON" },
{ 0, NULL }
};
const struct YamlIdStr enum_FailsafeModes[] = {
{ FAILSAFE_NOT_SET, "NOT_SET" },
{ FAILSAFE_HOLD, "HOLD" },
{ FAILSAFE_CUSTOM, "CUSTOM" },
{ FAILSAFE_NOPULSES, "NOPULSES" },
{ FAILSAFE_RECEIVER, "RECEIVER" },
{ 0, NULL }
};
const struct YamlIdStr enum_TelemetrySensorFormula[] = {
{ TELEM_FORMULA_ADD, "FORMULA_ADD" },
{ TELEM_FORMULA_AVERAGE, "FORMULA_AVERAGE" },
{ TELEM_FORMULA_MIN, "FORMULA_MIN" },
{ TELEM_FORMULA_MAX, "FORMULA_MAX" },
{ TELEM_FORMULA_MULTIPLY, "FORMULA_MULTIPLY" },
{ TELEM_FORMULA_TOTALIZE, "FORMULA_TOTALIZE" },
{ TELEM_FORMULA_CELL, "FORMULA_CELL" },
{ TELEM_FORMULA_CONSUMPTION, "FORMULA_CONSUMPTION" },
{ TELEM_FORMULA_DIST, "FORMULA_DIST" },
{ 0, NULL }
};
const struct YamlIdStr enum_TelemetrySensorType[] = {
{ TELEM_TYPE_CUSTOM, "TYPE_CUSTOM" },
{ TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" },
{ 0, NULL }
};
const struct YamlIdStr enum_ZoneOptionValueEnum[] = {
{ ZOV_Unsigned, "Unsigned" },
{ ZOV_Signed, "Signed" },
{ ZOV_Bool, "Bool" },
{ ZOV_String, "String" },
{ ZOV_Source, "Source" },
{ ZOV_Color, "Color" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickIfMode[] = {
{ USBJOYS_JOYSTICK, "JOYSTICK" },
{ USBJOYS_GAMEPAD, "GAMEPAD" },
{ USBJOYS_MULTIAXIS, "MULTIAXIS" },
{ 0, NULL }
};
const struct YamlIdStr enum_USBJoystickCh[] = {
{ USBJOYS_CH_NONE, "CH_NONE" },
{ USBJOYS_CH_BUTTON, "CH_BUTTON" },
{ USBJOYS_CH_AXIS, "CH_AXIS" },
{ USBJOYS_CH_SIM, "CH_SIM" },
{ 0, NULL }
};
//
// Structs last
//
static const struct YamlNode struct_CalibData[] = {
YAML_IDX_CUST("calib",r_calib,w_calib),
YAML_SIGNED( "mid", 16 ),
YAML_SIGNED( "spanNeg", 16 ),
YAML_SIGNED( "spanPos", 16 ),
YAML_END
};
static const struct YamlNode struct_signed_16[] = {
YAML_IDX,
YAML_SIGNED( "val", 16 ),
YAML_END
};
static const struct YamlNode struct_TrainerMix[] = {
YAML_IDX,
YAML_UNSIGNED( "srcChn", 6 ),
YAML_ENUM("mode", 2, enum_TrainerMultiplex, NULL),
YAML_SIGNED( "studWeight", 8 ),
YAML_END
};
static const struct YamlNode struct_TrainerData[] = {
YAML_ARRAY("calib", 16, 4, struct_signed_16, NULL),
YAML_ARRAY("mix", 16, 4, struct_TrainerMix, NULL),
YAML_END
};
static const struct YamlNode struct_anonymous_1[] = {
YAML_STRING("name", 8),
YAML_END
};
static const struct YamlNode struct_anonymous_2[] = {
YAML_SIGNED( "val", 16 ),
YAML_UNSIGNED( "mode", 8 ),
YAML_UNSIGNED( "param", 8 ),
YAML_SIGNED( "val2", 32 ),
YAML_END
};
static const struct YamlNode struct_anonymous_3[] = {
YAML_SIGNED( "val1", 32 ),
YAML_SIGNED( "val2", 32 ),
YAML_END
};
static const struct YamlNode union_anonymous_0_elmts[] = {
YAML_STRUCT("play", 64, struct_anonymous_1, NULL),
YAML_STRUCT("all", 64, struct_anonymous_2, NULL),
YAML_STRUCT("clear", 64, struct_anonymous_3, NULL),
YAML_END
};
static const struct YamlNode struct_CustomFunctionData[] = {
YAML_IDX,
YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ),
YAML_ENUM("func", 6, enum_Functions, NULL),
YAML_CUSTOM("def",r_customFn,w_customFn),
YAML_PADDING( 64 ),
YAML_PADDING( 1 ),
YAML_PADDING( 7 ),
YAML_END
};
static const struct YamlNode struct_RGBLedColor[] = {
YAML_UNSIGNED( "r", 8 ),
YAML_UNSIGNED( "g", 8 ),
YAML_UNSIGNED( "b", 8 ),
YAML_END
};
static const struct YamlNode struct_switchDef[] = {
YAML_IDX_CUST("sw",sw_idx_read,sw_idx_write),
YAML_STRING("name", 3),
YAML_ENUM("type", 3, enum_SwitchConfig, NULL),
YAML_ENUM("start", 2, enum_fsStartPositionType, switch_is_cfs),
YAML_ENUM("onColorLuaOverride", 1, enum_booleanEnum, switch_is_cfs),
YAML_ENUM("offColorLuaOverride", 1, enum_booleanEnum, switch_is_cfs),
YAML_PADDING( 1 ),
YAML_STRUCT("onColor", 24, struct_RGBLedColor, switch_is_cfs),
YAML_STRUCT("offColor", 24, struct_RGBLedColor, switch_is_cfs),
YAML_END
};
static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "manuallyEdited", 1 ),
YAML_SIGNED( "timezoneMinutes", 3 ),
YAML_UNSIGNED( "ppmunit", 2 ),
YAML_PADDING( 2 ),
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_CUSTOM("board",nullptr,w_board),
YAML_ARRAY("calib", 48, 20, struct_CalibData, NULL),
YAML_PADDING( 16 ),
YAML_UNSIGNED( "vBatWarn", 8 ),
YAML_SIGNED( "txVoltageCalibration", 8 ),
YAML_ENUM("backlightMode", 3, enum_BacklightMode, NULL),
YAML_ENUM("antennaMode", 2, enum_AntennaModes, NULL),
YAML_UNSIGNED( "disableRtcWarning", 1 ),
YAML_UNSIGNED( "keysBacklight", 1 ),
YAML_UNSIGNED( "dontPlayHello", 1 ),
YAML_ENUM("internalModule", 8, enum_ModuleType, NULL),
YAML_STRUCT("trainer", 128, struct_TrainerData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_PADDING( 2 ),
YAML_UNSIGNED( "fai", 1 ),
YAML_SIGNED_CUST( "beepMode", 2, r_beeperMode, w_beeperMode ),
YAML_UNSIGNED( "alarmsFlash", 1 ),
YAML_UNSIGNED( "disableMemoryWarning", 1 ),
YAML_UNSIGNED( "disableAlarmWarning", 1 ),
YAML_UNSIGNED( "stickMode", 2 ),
YAML_SIGNED( "timezone", 5 ),
YAML_UNSIGNED( "adjustRTC", 1 ),
YAML_UNSIGNED( "inactivityTimer", 8 ),
YAML_CUSTOM("telemetryBaudrate",r_telemetryBaudrate,nullptr),
YAML_UNSIGNED( "internalModuleBaudrate", 3 ),
YAML_SIGNED( "splashMode", 3 ),
YAML_SIGNED_CUST( "hapticMode", 2, r_beeperMode, w_beeperMode ),
YAML_SIGNED( "switchesDelay", 8 ),
YAML_UNSIGNED( "lightAutoOff", 8 ),
YAML_UNSIGNED( "templateSetup", 8 ),
YAML_SIGNED( "PPM_Multiplier", 8 ),
YAML_SIGNED_CUST( "hapticLength", 8, r_5pos, w_5pos ),
YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ),
YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ),
YAML_UNSIGNED( "gpsFormat", 1 ),
YAML_UNSIGNED( "audioMuteEnable", 1 ),
YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ),
YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ),
YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ),
YAML_SIGNED_CUST( "vBatMax", 8, r_vbat_max, w_vbat_max ),
YAML_UNSIGNED( "backlightBright", 8 ),
YAML_UNSIGNED( "globalTimer", 32 ),
YAML_UNSIGNED( "bluetoothBaudrate", 4 ),
YAML_ENUM("bluetoothMode", 4, enum_BluetoothModes, NULL),
YAML_UNSIGNED( "countryCode", 2 ),
YAML_SIGNED( "pwrOnSpeed", 3 ),
YAML_SIGNED( "pwrOffSpeed", 3 ),
YAML_CUSTOM("jitterFilter",r_jitterFilter,nullptr),
YAML_UNSIGNED( "noJitterFilter", 1 ),
YAML_UNSIGNED( "imperial", 1 ),
YAML_UNSIGNED( "disableRssiPoweroffAlarm", 1 ),
YAML_UNSIGNED( "USBMode", 2 ),
YAML_UNSIGNED( "jackMode", 2 ),
YAML_PADDING( 1 ),
YAML_STRING("ttsLanguage", 2),
YAML_SIGNED_CUST( "beepVolume", 4, r_5pos, w_5pos ),
YAML_SIGNED_CUST( "wavVolume", 4, r_5pos, w_5pos ),
YAML_SIGNED_CUST( "varioVolume", 4, r_5pos, w_5pos ),
YAML_SIGNED_CUST( "backgroundVolume", 4, r_5pos, w_5pos ),
YAML_SIGNED_CUST( "varioPitch", 8, r_vPitch, w_vPitch ),
YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active),
YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr),
YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr),
YAML_ARRAY("serialPort", 8, 4, struct_serialConfig, nullptr),
YAML_ARRAY("sticksConfig", 0, MAX_STICKS, struct_stickConfig, stick_name_valid),
YAML_ARRAY("slidersConfig", 0, MAX_POTS, struct_sliderConfig, nullptr),
YAML_PADDING( 8 ),
YAML_ARRAY("potsConfig", 4, 16, struct_potConfig, nullptr),
YAML_ARRAY("switchConfig", 80, 20, struct_switchDef, switchIsActive),
YAML_ARRAY("flexSwitches", 0, MAX_FLEX_SWITCHES, struct_flexSwitch, flex_sw_valid),
YAML_STRING("currModelFilename", 17),
YAML_UNSIGNED( "modelQuickSelect", 1 ),
YAML_UNSIGNED( "blOffBright", 7 ),
YAML_STRING("bluetoothName", 10),
YAML_STRING("ownerRegistrationID", 8),
YAML_CUSTOM("rotEncDirection",r_rotEncDirection,nullptr),
YAML_UNSIGNED( "rotEncMode", 3 ),
YAML_SIGNED( "uartSampleMode", 2 ),
YAML_UNSIGNED( "stickDeadZone", 3 ),
YAML_SIGNED( "imuMax", 8 ),
YAML_SIGNED( "imuOffset", 8 ),
YAML_STRING("selectedTheme", 26),
YAML_UNSIGNED( "labelSingleSelect", 1 ),
YAML_UNSIGNED( "labelMultiMode", 1 ),
YAML_UNSIGNED( "favMultiMode", 1 ),
YAML_UNSIGNED( "modelSelectLayout", 2 ),
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
YAML_UNSIGNED( "radioGFDisabled", 1 ),
YAML_UNSIGNED( "radioTrainerDisabled", 1 ),
YAML_UNSIGNED( "modelHeliDisabled", 1 ),
YAML_UNSIGNED( "modelFMDisabled", 1 ),
YAML_UNSIGNED( "modelCurvesDisabled", 1 ),
YAML_UNSIGNED( "modelGVDisabled", 1 ),
YAML_UNSIGNED( "modelLSDisabled", 1 ),
YAML_UNSIGNED( "modelSFDisabled", 1 ),
YAML_UNSIGNED( "modelCustomScriptsDisabled", 1 ),
YAML_UNSIGNED( "modelTelemetryDisabled", 1 ),
YAML_UNSIGNED( "disableTrainerPoweroffAlarm", 1 ),
YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ),
YAML_PADDING( 6 ),
YAML_UNSIGNED( "pwrOffIfInactive", 8 ),
YAML_END
};
static const struct YamlNode struct_unsigned_8[] = {
YAML_IDX,
YAML_UNSIGNED( "val", 8 ),
YAML_END
};
static const struct YamlNode struct_ModelHeader[] = {
YAML_STRING("name", 15),
YAML_ARRAY("modelId", 8, 2, struct_unsigned_8, NULL),
YAML_STRING("bitmap", 14),
YAML_STRING("labels", 100),
YAML_END
};
static const struct YamlNode struct_TimerData[] = {
YAML_IDX,
YAML_UNSIGNED( "start", 22 ),
YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ),
YAML_SIGNED( "value", 22 ),
YAML_ENUM("mode", 3, enum_TimerModes, NULL),
YAML_UNSIGNED( "countdownBeep", 2 ),
YAML_UNSIGNED( "minuteBeep", 1 ),
YAML_UNSIGNED( "persistent", 2 ),
YAML_SIGNED( "countdownStart", 2 ),
YAML_UNSIGNED( "showElapsed", 1 ),
YAML_UNSIGNED( "extraHaptic", 1 ),
YAML_PADDING( 6 ),
YAML_STRING("name", 8),
YAML_END
};
static const struct YamlNode struct_CurveRef[] = {
YAML_UNSIGNED( "type", 5 ),
YAML_UNSIGNED_CUST( "value", 11, r_sourceNumVal, w_sourceNumVal ),
YAML_END
};
static const struct YamlNode struct_MixData[] = {
YAML_UNSIGNED( "destCh", 5 ),
YAML_SIGNED_CUST( "srcRaw", 10, r_mixSrcRawEx, w_mixSrcRawEx ),
YAML_UNSIGNED( "carryTrim", 1 ),
YAML_UNSIGNED( "mixWarn", 2 ),
YAML_ENUM("mltpx", 2, enum_MixerMultiplex, NULL),
YAML_UNSIGNED( "delayPrec", 1 ),
YAML_UNSIGNED( "speedPrec", 1 ),
YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ),
YAML_PADDING( 1 ),
YAML_UNSIGNED_CUST( "weight", 11, r_sourceNumVal, w_sourceNumVal ),
YAML_UNSIGNED_CUST( "offset", 11, r_sourceNumVal, w_sourceNumVal ),
YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ),
YAML_STRUCT("curve", 16, struct_CurveRef, NULL),
YAML_UNSIGNED( "delayUp", 8 ),
YAML_UNSIGNED( "delayDown", 8 ),
YAML_UNSIGNED( "speedUp", 8 ),
YAML_UNSIGNED( "speedDown", 8 ),
YAML_STRING("name", 6),
YAML_END
};
static const struct YamlNode struct_LimitData[] = {
YAML_IDX,
YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ),
YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ),
YAML_SIGNED( "ppmCenter", 10 ),
YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ),
YAML_UNSIGNED( "symetrical", 1 ),
YAML_UNSIGNED( "revert", 1 ),
YAML_PADDING( 3 ),
YAML_SIGNED( "curve", 8 ),
YAML_STRING("name", 6),
YAML_END
};
static const struct YamlNode struct_ExpoData[] = {
YAML_UNSIGNED( "mode", 2 ),
YAML_UNSIGNED( "scale", 14 ),
YAML_CUSTOM("carryTrim",r_carryTrim,nullptr),
YAML_SIGNED( "trimSource", 6 ),
YAML_SIGNED_CUST( "srcRaw", 10, r_mixSrcRawEx, w_mixSrcRawEx ),
YAML_UNSIGNED_CUST( "weight", 11, r_sourceNumVal, w_sourceNumVal ),
YAML_UNSIGNED_CUST( "offset", 11, r_sourceNumVal, w_sourceNumVal ),
YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ),
YAML_STRUCT("curve", 16, struct_CurveRef, NULL),
YAML_UNSIGNED( "chn", 5 ),
YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ),
YAML_PADDING( 2 ),
YAML_STRING("name", 6),
YAML_END
};
static const struct YamlNode struct_CurveHeader[] = {
YAML_IDX,
YAML_UNSIGNED( "type", 1 ),
YAML_UNSIGNED( "smooth", 1 ),
YAML_SIGNED( "points", 6 ),
YAML_STRING("name", 3),
YAML_END
};
static const struct YamlNode struct_signed_8[] = {
YAML_IDX,
YAML_SIGNED( "val", 8 ),
YAML_END
};
static const struct YamlNode struct_LogicalSwitchData[] = {
YAML_IDX,
YAML_ENUM("func", 8, enum_LogicalSwitchesFunctions, NULL),
YAML_CUSTOM("def",r_logicSw,w_logicSw),
YAML_PADDING( 10 ),
YAML_PADDING( 10 ),
YAML_SIGNED_CUST( "andsw", 10, r_swtchSrc, w_swtchSrc ),
YAML_UNSIGNED( "lsPersist", 1 ),
YAML_UNSIGNED( "lsState", 1 ),
YAML_PADDING( 16 ),
YAML_UNSIGNED( "delay", 8 ),
YAML_UNSIGNED( "duration", 8 ),
YAML_END
};
static const struct YamlNode struct_SwashRingData[] = {
YAML_ENUM("type", 8, enum_SwashType, NULL),
YAML_UNSIGNED( "value", 8 ),
YAML_UNSIGNED_CUST( "collectiveSource", 8, r_mixSrcRaw, w_mixSrcRaw ),
YAML_UNSIGNED_CUST( "aileronSource", 8, r_mixSrcRaw, w_mixSrcRaw ),
YAML_UNSIGNED_CUST( "elevatorSource", 8, r_mixSrcRaw, w_mixSrcRaw ),
YAML_SIGNED( "collectiveWeight", 8 ),
YAML_SIGNED( "aileronWeight", 8 ),
YAML_SIGNED( "elevatorWeight", 8 ),
YAML_END
};
static const struct YamlNode struct_trim_t[] = {
YAML_IDX,
YAML_SIGNED( "value", 11 ),
YAML_UNSIGNED( "mode", 5 ),
YAML_END
};
static const struct YamlNode struct_FlightModeData[] = {
YAML_IDX,
YAML_ARRAY("trim", 16, 8, struct_trim_t, NULL),
YAML_STRING("name", 10),
YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ),
YAML_PADDING( 6 ),
YAML_UNSIGNED( "fadeIn", 8 ),
YAML_UNSIGNED( "fadeOut", 8 ),
YAML_ARRAY("gvars", 16, 9, struct_signed_16, gvar_is_active),
YAML_END
};
static const struct YamlNode struct_GVarData[] = {
YAML_IDX,
YAML_STRING("name", 3),
YAML_UNSIGNED( "min", 12 ),
YAML_UNSIGNED( "max", 12 ),
YAML_UNSIGNED( "popup", 1 ),
YAML_UNSIGNED( "prec", 1 ),
YAML_UNSIGNED( "unit", 2 ),
YAML_PADDING( 4 ),
YAML_END
};
static const struct YamlNode struct_VarioData[] = {
YAML_UNSIGNED_CUST( "source", 7, r_tele_sensor, w_tele_sensor ),
YAML_UNSIGNED( "centerSilent", 1 ),
YAML_SIGNED( "centerMax", 8 ),
YAML_SIGNED( "centerMin", 8 ),
YAML_SIGNED( "min", 8 ),
YAML_SIGNED( "max", 8 ),
YAML_END
};
static const struct YamlNode struct_RssiAlarmData[] = {
YAML_CUSTOM("disabled",r_rssiDisabled,nullptr),
YAML_CUSTOM("warning",r_rssiWarning,nullptr),
YAML_CUSTOM("critical",r_rssiCritical,nullptr),
YAML_END
};
static const struct YamlNode struct_RFAlarmData[] = {
YAML_SIGNED( "warning", 8 ),
YAML_SIGNED( "critical", 8 ),
YAML_END
};
static const struct YamlNode struct_PpmModule[] = {
YAML_SIGNED( "delay", 6 ),
YAML_UNSIGNED( "pulsePol", 1 ),
YAML_UNSIGNED( "outputType", 1 ),
YAML_SIGNED( "frameLength", 8 ),
YAML_END
};
static const struct YamlNode struct_anonymous_5[] = {
YAML_PADDING( 8 ),
YAML_UNSIGNED( "disableTelemetry", 1 ),
YAML_UNSIGNED( "disableMapping", 1 ),
YAML_UNSIGNED( "autoBindMode", 1 ),
YAML_UNSIGNED( "lowPowerMode", 1 ),
YAML_UNSIGNED( "receiverTelemetryOff", 1 ),
YAML_UNSIGNED( "receiverHigherChannels", 1 ),
YAML_PADDING( 2 ),
YAML_SIGNED( "optionValue", 8 ),
YAML_END
};
static const struct YamlNode struct_anonymous_6[] = {
YAML_UNSIGNED( "power", 2 ),
YAML_PADDING( 2 ),
YAML_UNSIGNED( "receiverTelemetryOff", 1 ),
YAML_UNSIGNED( "receiverHigherChannels", 1 ),
YAML_SIGNED( "antennaMode", 2 ),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_anonymous_7[] = {
YAML_PADDING( 6 ),
YAML_UNSIGNED( "noninverted", 1 ),
YAML_PADDING( 1 ),
YAML_SIGNED( "refreshRate", 8 ),
YAML_END
};
static const struct YamlNode struct_string_64[] = {
YAML_IDX,
YAML_STRING("val", 8),
YAML_END
};
static const struct YamlNode struct_anonymous_8[] = {
YAML_UNSIGNED( "receivers", 7 ),
YAML_UNSIGNED( "racingMode", 1 ),
YAML_ARRAY("receiverName", 64, 3, struct_string_64, NULL),
YAML_END
};
static const struct YamlNode struct_anonymous_9[] = {
YAML_ARRAY("rx_id", 8, 4, struct_unsigned_8, NULL),
YAML_UNSIGNED( "mode", 3 ),
YAML_UNSIGNED( "rfPower", 1 ),
YAML_UNSIGNED( "reserved", 4 ),
YAML_ARRAY("rx_freq", 8, 2, struct_unsigned_8, NULL),
YAML_END
};
static const struct YamlNode struct_anonymous_10[] = {
YAML_UNSIGNED( "emi", 2 ),
YAML_UNSIGNED( "telemetry", 1 ),
YAML_UNSIGNED( "phyMode", 3 ),
YAML_UNSIGNED( "reserved", 2 ),
YAML_UNSIGNED( "rfPower", 8 ),
YAML_END
};
static const struct YamlNode struct_anonymous_11[] = {
YAML_UNSIGNED( "raw12bits", 1 ),
YAML_UNSIGNED( "telemetryBaudrate", 3 ),
YAML_PADDING( 4 ),
YAML_END
};
static const struct YamlNode struct_anonymous_12[] = {
YAML_UNSIGNED( "telemetryBaudrate", 3 ),
YAML_UNSIGNED( "crsfArmingMode", 1 ),
YAML_PADDING( 4 ),
YAML_SIGNED_CUST( "crsfArmingTrigger", 10, r_swtchSrc, w_swtchSrc ),
YAML_SIGNED( "spare3", 6 ),
YAML_END
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_ARRAY("raw", 8, 25, struct_unsigned_8, NULL),
YAML_STRUCT("ppm", 16, struct_PpmModule, NULL),
YAML_STRUCT("multi", 24, struct_anonymous_5, NULL),
YAML_STRUCT("pxx", 16, struct_anonymous_6, NULL),
YAML_STRUCT("sbus", 16, struct_anonymous_7, NULL),
YAML_STRUCT("pxx2", 200, struct_anonymous_8, NULL),
YAML_STRUCT("flysky", 56, struct_anonymous_9, NULL),
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
YAML_IDX,
YAML_UNSIGNED_CUST( "type", 8, r_moduleType, w_moduleType ),
YAML_CUSTOM("subType",r_modSubtype,w_modSubtype),
YAML_UNSIGNED( "channelsStart", 8 ),
YAML_SIGNED_CUST( "channelsCount", 8, r_channelsCount, w_channelsCount ),
YAML_ENUM("failsafeMode", 4, enum_FailsafeModes, NULL),
YAML_PADDING( 4 ),
YAML_UNION("mod", 200, union_anonymous_4_elmts, select_mod_type),
YAML_END
};
static const struct YamlNode struct_TrainerModuleData[] = {
YAML_UNSIGNED_CUST( "mode", 8, r_trainerMode, w_trainerMode ),
YAML_UNSIGNED( "channelsStart", 8 ),
YAML_SIGNED( "channelsCount", 8 ),
YAML_SIGNED( "frameLength", 8 ),
YAML_SIGNED( "delay", 6 ),
YAML_UNSIGNED( "pulsePol", 1 ),
YAML_PADDING( 1 ),
YAML_END
};
static const struct YamlNode union_ScriptDataInput_elmts[] = {
YAML_SIGNED( "value", 16 ),
YAML_UNSIGNED_CUST( "source", 16, r_mixSrcRaw, w_mixSrcRaw ),
YAML_END
};
static const struct YamlNode union_ScriptDataInput[] = {
YAML_IDX,
YAML_UNION("u", 16, union_ScriptDataInput_elmts, select_script_input),
YAML_END
};
static const struct YamlNode struct_ScriptData[] = {
YAML_IDX,
YAML_STRING("file", 6),
YAML_STRING("name", 6),
YAML_ARRAY("inputs", 16, 6, union_ScriptDataInput, NULL),
YAML_END
};
static const struct YamlNode struct_string_32[] = {
YAML_IDX,
YAML_STRING("val", 4),
YAML_END
};
static const struct YamlNode union_anonymous_14_elmts[] = {
YAML_UNSIGNED( "id", 16 ),
YAML_UNSIGNED( "persistentValue", 16 ),
YAML_END
};
static const struct YamlNode struct_anonymous_16[] = {
YAML_UNSIGNED( "physID", 5 ),
YAML_UNSIGNED( "rxIndex", 3 ),
YAML_END
};
static const struct YamlNode union_anonymous_15_elmts[] = {
YAML_STRUCT("frskyInstance", 8, struct_anonymous_16, NULL),
YAML_UNSIGNED( "instance", 8 ),
YAML_ENUM("formula", 8, enum_TelemetrySensorFormula, NULL),
YAML_END
};
static const struct YamlNode struct_anonymous_18[] = {
YAML_UNSIGNED( "ratio", 16 ),
YAML_SIGNED( "offset", 16 ),
YAML_END
};
static const struct YamlNode struct_anonymous_19[] = {
YAML_UNSIGNED( "source", 8 ),
YAML_UNSIGNED( "index", 8 ),
YAML_PADDING( 16 ),
YAML_END
};
static const struct YamlNode struct_anonymous_20[] = {
YAML_ARRAY("sources", 8, 4, struct_signed_8, NULL),
YAML_END
};
static const struct YamlNode struct_anonymous_21[] = {
YAML_UNSIGNED( "source", 8 ),
YAML_PADDING( 24 ),
YAML_END
};
static const struct YamlNode struct_anonymous_22[] = {
YAML_UNSIGNED( "gps", 8 ),
YAML_UNSIGNED( "alt", 8 ),
YAML_PADDING( 16 ),
YAML_END
};
static const struct YamlNode union_anonymous_17_elmts[] = {
YAML_STRUCT("custom", 32, struct_anonymous_18, NULL),
YAML_STRUCT("cell", 32, struct_anonymous_19, NULL),
YAML_STRUCT("calc", 32, struct_anonymous_20, NULL),
YAML_STRUCT("consumption", 32, struct_anonymous_21, NULL),
YAML_STRUCT("dist", 32, struct_anonymous_22, NULL),
YAML_UNSIGNED( "param", 32 ),
YAML_END
};
static const struct YamlNode struct_TelemetrySensor[] = {
YAML_IDX,
YAML_UNION("id1", 16, union_anonymous_14_elmts, select_id1),
YAML_UNION("id2", 8, union_anonymous_15_elmts, select_id2),
YAML_STRING("label", 4),
YAML_UNSIGNED( "subId", 8 ),
YAML_ENUM("type", 1, enum_TelemetrySensorType, NULL),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "unit", 6 ),
YAML_UNSIGNED( "prec", 2 ),
YAML_UNSIGNED( "autoOffset", 1 ),
YAML_UNSIGNED( "filter", 1 ),
YAML_UNSIGNED( "logs", 1 ),
YAML_UNSIGNED( "persistent", 1 ),
YAML_UNSIGNED( "onlyPositive", 1 ),
YAML_PADDING( 1 ),
YAML_UNION("cfg", 32, union_anonymous_17_elmts, select_sensor_cfg),
YAML_END
};
static const struct YamlNode union_ZoneOptionValue_elmts[] = {
YAML_UNSIGNED( "unsignedValue", 32 ),
YAML_SIGNED( "signedValue", 32 ),
YAML_UNSIGNED( "boolValue", 32 ),
YAML_STRING("stringValue", 12),
YAML_CUSTOM("source",r_zov_source,w_zov_source),
YAML_CUSTOM("color",r_zov_color,w_zov_color),
YAML_END
};
static const struct YamlNode struct_ZoneOptionValueTyped[] = {
YAML_IDX,
YAML_ENUM("type", 32, enum_ZoneOptionValueEnum, NULL),
YAML_UNION("value", 96, union_ZoneOptionValue_elmts, select_zov),
YAML_END
};
static const struct YamlNode struct_WidgetPersistentData[] = {
YAML_ARRAY("options", 128, 10, struct_ZoneOptionValueTyped, NULL),
YAML_END
};
static const struct YamlNode struct_ZonePersistentData[] = {
YAML_IDX,
YAML_STRING("widgetName", 20),
YAML_STRUCT("widgetData", 1280, struct_WidgetPersistentData, NULL),
YAML_END
};
static const struct YamlNode struct_LayoutPersistentData[] = {
YAML_ARRAY("zones", 1440, 10, struct_ZonePersistentData, NULL),
YAML_ARRAY("options", 128, 10, struct_ZoneOptionValueTyped, NULL),
YAML_END
};
static const struct YamlNode struct_CustomScreenData[] = {
YAML_IDX,
YAML_STRING("LayoutId", 12),
YAML_STRUCT("layoutData", 15680, struct_LayoutPersistentData, NULL),
YAML_END
};
static const struct YamlNode struct_TopBarPersistentData[] = {
YAML_ARRAY("zones", 1440, 6, struct_ZonePersistentData, NULL),
YAML_ARRAY("options", 128, 1, struct_ZoneOptionValueTyped, NULL),
YAML_END
};
static const struct YamlNode struct_customSwitch[] = {
YAML_IDX_CUST("sw",cfs_idx_read,cfs_idx_write),
YAML_STRING("name", 3),
YAML_ENUM("type", 3, enum_SwitchConfig, NULL),
YAML_UNSIGNED( "group", 2 ),
YAML_ENUM("start", 2, enum_fsStartPositionType, NULL),
YAML_UNSIGNED( "state", 1 ),
YAML_ENUM("onColorLuaOverride", 1, enum_booleanEnum, NULL),
YAML_ENUM("offColorLuaOverride", 1, enum_booleanEnum, NULL),
YAML_PADDING( 6 ),
YAML_STRUCT("onColor", 24, struct_RGBLedColor, isAlwaysActive),
YAML_STRUCT("offColor", 24, struct_RGBLedColor, isAlwaysActive),
YAML_END
};
static const struct YamlNode struct_USBJoystickChData[] = {
YAML_IDX,
YAML_ENUM("mode", 3, enum_USBJoystickCh, NULL),
YAML_UNSIGNED( "inversion", 1 ),
YAML_UNSIGNED( "param", 4 ),
YAML_UNSIGNED( "btn_num", 5 ),
YAML_UNSIGNED( "switch_npos", 3 ),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 1048, struct_ModelHeader, NULL),
YAML_ARRAY("timers", 136, 3, struct_TimerData, NULL),
YAML_UNSIGNED( "telemetryProtocol", 3 ),
YAML_UNSIGNED( "thrTrim", 1 ),
YAML_UNSIGNED( "noGlobalFunctions", 1 ),
YAML_UNSIGNED( "displayTrims", 2 ),
YAML_UNSIGNED( "ignoreSensorIds", 1 ),
YAML_SIGNED( "trimInc", 3 ),
YAML_UNSIGNED( "disableThrottleWarning", 1 ),
YAML_UNSIGNED( "displayChecklist", 1 ),
YAML_UNSIGNED( "extendedLimits", 1 ),
YAML_UNSIGNED( "extendedTrims", 1 ),
YAML_UNSIGNED( "throttleReversed", 1 ),
YAML_UNSIGNED( "enableCustomThrottleWarning", 1 ),
YAML_UNSIGNED( "disableTelemetryWarning", 1 ),
YAML_UNSIGNED( "showInstanceIds", 1 ),
YAML_UNSIGNED( "checklistInteractive", 1 ),
YAML_PADDING( 4 ),
YAML_SIGNED( "customThrottleWarningPosition", 8 ),
YAML_UNSIGNED( "beepANACenter", 16 ),
YAML_ARRAY("mixData", 160, 64, struct_MixData, NULL),
YAML_ARRAY("limitData", 104, 32, struct_LimitData, NULL),
YAML_ARRAY("expoData", 144, 64, struct_ExpoData, NULL),
YAML_ARRAY("curves", 32, 32, struct_CurveHeader, NULL),
YAML_ARRAY("points", 8, 512, struct_signed_8, NULL),
YAML_ARRAY("logicalSw", 72, 64, struct_LogicalSwitchData, NULL),
YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active),
YAML_STRUCT("swashR", 64, struct_SwashRingData, swash_is_active),
YAML_ARRAY("flightModeData", 384, 9, struct_FlightModeData, fmd_is_active),
YAML_UNSIGNED_CUST( "thrTraceSrc", 8, r_thrSrc, w_thrSrc ),
YAML_CUSTOM("switchWarningState",r_swtchWarn,nullptr),
YAML_ARRAY("switchWarning", 2, 32, struct_swtchWarn, nullptr),
YAML_ARRAY("gvars", 56, 9, struct_GVarData, NULL),
YAML_STRUCT("varioData", 40, struct_VarioData, NULL),
YAML_UNSIGNED_CUST( "rssiSource", 8, r_tele_sensor, w_tele_sensor ),
YAML_STRUCT("rssiAlarms", 0, struct_RssiAlarmData, NULL),
YAML_STRUCT("rfAlarms", 16, struct_RFAlarmData, NULL),
YAML_UNSIGNED( "thrTrimSw", 3 ),
YAML_ENUM("potsWarnMode", 2, enum_PotsWarnMode, NULL),
YAML_ENUM("jitterFilter", 2, enum_ModelOverridableEnable, NULL),
YAML_PADDING( 1 ),
YAML_ARRAY("moduleData", 232, 2, struct_ModuleData, NULL),
YAML_ARRAY("failsafeChannels", 16, 32, struct_signed_16, NULL),
YAML_STRUCT("trainerData", 40, struct_TrainerModuleData, NULL),
YAML_ARRAY("scriptsData", 192, 9, struct_ScriptData, NULL),
YAML_ARRAY("inputNames", 32, 32, struct_string_32, NULL),
YAML_UNSIGNED( "potsWarnEnabled", 16 ),
YAML_ARRAY("potsWarnPosition", 8, 16, struct_signed_8, NULL),
YAML_ARRAY("telemetrySensors", 112, 60, struct_TelemetrySensor, NULL),
YAML_ARRAY("screenData", 15776, 10, struct_CustomScreenData, NULL),
YAML_STRUCT("topbarData", 8768, struct_TopBarPersistentData, NULL),
YAML_ARRAY("topbarWidgetWidth", 8, 6, struct_unsigned_8, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_CUSTOM("functionSwitchConfig",r_functionSwitchConfig,nullptr),
YAML_CUSTOM("functionSwitchGroup",r_functionSwitchGroup,nullptr),
YAML_CUSTOM("functionSwitchStartConfig",r_functionSwitchStartConfig,nullptr),
YAML_CUSTOM("functionSwitchLogicalState",r_functionSwitchLogicalState,nullptr),
YAML_ARRAY("switchNames", 0, NUM_FUNCTIONS_SWITCHES, struct_cfsNameConfig, nullptr),
YAML_ARRAY("functionSwitchLedONColor", 0, NUM_FUNCTIONS_SWITCHES, struct_cfsOnColorConfig, nullptr),
YAML_ARRAY("functionSwitchLedOFFColor", 0, NUM_FUNCTIONS_SWITCHES, struct_cfsOffColorConfig, nullptr),
YAML_ARRAY("customSwitches", 88, 6, struct_customSwitch, isAlwaysActive),
YAML_ARRAY("cfsGroupOn", 1, 8, struct_cfsGroupOn, cfsGroupIsActive),
YAML_PADDING( 8 ),
YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode, NULL),
YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
YAML_ENUM("radioThemesDisabled", 2, enum_ModelOverridableEnable, NULL),
YAML_ENUM("radioGFDisabled", 2, enum_ModelOverridableEnable, NULL),
YAML_ENUM("radioTrainerDisabled", 2, enum_ModelOverridableEnable, NULL),
YAML_ENUM("modelHeliDisabled", 2, enum_ModelOverridableEnable, NULL),
YAML_ENUM("modelFMDisabled", 2, enum_ModelOverridableEnable, NULL),
YAML_ENUM("modelCurvesDisabled", 2, enum_ModelOverridableEnable, NULL),
YAML_ENUM("modelGVDisabled", 2, enum_ModelOverridableEnable, NULL),
YAML_ENUM("modelLSDisabled", 2, enum_ModelOverridableEnable, NULL),
YAML_ENUM("modelSFDisabled", 2, enum_ModelOverridableEnable, NULL),
YAML_ENUM("modelCustomScriptsDisabled", 2, enum_ModelOverridableEnable, NULL),
YAML_ENUM("modelTelemetryDisabled", 2, enum_ModelOverridableEnable, NULL),
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
YAML_STRUCT("header", 1048, struct_ModelHeader, NULL),
YAML_ARRAY("timers", 136, 3, struct_TimerData, NULL),
YAML_END
};
#define MAX_RADIODATA_MODELDATA_PARTIALMODEL_STR_LEN 29
static const struct YamlNode __RadioData_root_node = YAML_ROOT( struct_RadioData );
const YamlNode* get_radiodata_nodes()
{
return &__RadioData_root_node;
}
static const struct YamlNode __ModelData_root_node = YAML_ROOT( struct_ModelData );
const YamlNode* get_modeldata_nodes()
{
return &__ModelData_root_node;
}
static const struct YamlNode __PartialModel_root_node = YAML_ROOT( struct_PartialModel );
const YamlNode* get_partialmodel_nodes()
{
return &__PartialModel_root_node;
}
+5
View File
@@ -90,6 +90,11 @@ uint8_t potsPos[MAX_POTS];
uint16_t fsPreviousState = 0;
uint8_t isSwitch3Pos(uint8_t idx)
{
return IS_CONFIG_3POS(idx);
}
void setFSStartupPosition()
{
for (uint8_t i = 0; i < switchGetMaxSwitches(); i++) {
@@ -90,18 +90,15 @@
#endif
#if defined(SDMMC1) && defined(SD_SDIO)
# if !defined(SD_SDIO_IRQHandler)
# define SD_SDIO_IRQHandler SDMMC1_IRQHandler
# define SD_SDIO_IRQn SDMMC1_IRQn
# endif
#if defined(SDMMC1)
# define SD_SDIO_TypeDef SDMMC_TypeDef
# define SD_SDIO_CLOCK_EDGE_RISING SDMMC_CLOCK_EDGE_RISING
# define SD_SDIO_CLOCK_POWER_SAVE_DISABLE SDMMC_CLOCK_POWER_SAVE_DISABLE
# define SD_SDIO_BUS_WIDE_1B SDMMC_BUS_WIDE_1B
# define SD_SDIO_BUS_WIDE_4B SDMMC_BUS_WIDE_4B
# define SD_SDIO_HARDWARE_FLOW_CONTROL_DISABLE SDMMC_HARDWARE_FLOW_CONTROL_DISABLE
#elif !defined(SDMMC1)
# define SD_SDIO_IRQn SDMMC1_IRQn
#else
# if !defined(SD_SDIO)
# define SD_SDIO SDIO
# endif
@@ -118,6 +115,24 @@
# define SD_SDIO_HARDWARE_FLOW_CONTROL_DISABLE SDIO_HARDWARE_FLOW_CONTROL_DISABLE
#endif
struct {
SD_SDIO_TypeDef* periph = SD_SDIO;
gpio_t D0 = SD_SDIO_PIN_D0;
gpio_t D1 = SD_SDIO_PIN_D1;
gpio_t D2 = SD_SDIO_PIN_D2;
gpio_t D3 = SD_SDIO_PIN_D3;
gpio_t CMD = SD_SDIO_PIN_CMD;
gpio_t CLK = SD_SDIO_PIN_CLK;
gpio_af_t AF_D0 = SD_SDIO_AF_D0;
gpio_af_t AF_D1 = SD_SDIO_AF_D1;
gpio_af_t AF_D2 = SD_SDIO_AF_D2;
gpio_af_t AF_D3 = SD_SDIO_AF_D3;
gpio_af_t AF_CMD = SD_SDIO_AF_CMD;
gpio_af_t AF_CLK = SD_SDIO_AF_CLK;
IRQn_Type IRQn = SD_SDIO_IRQn;
uint32_t SD_CLK_DIV = SD_SDIO_TRANSFER_CLK_DIV;
} currentSD;
#if FF_MAX_SS != FF_MIN_SS
#error "Variable sector size is not supported"
#endif
@@ -156,8 +171,12 @@ extern uint32_t _heap_start;
// HAL state
static SD_HandleTypeDef sdio;
#if defined(SD_SDIO_DMA)
#if defined(STM32H7) || defined(STM32H7RS) || defined(STM32H5)
static_assert(false,"H7/H5 use dedicated DMA controler");
#else
static DMA_HandleTypeDef sdioTxDma;
#endif
#endif
// Disk status
static volatile uint32_t WriteStatus;
@@ -179,26 +198,26 @@ static void _sd_sdio_clk_enable(SD_SDIO_TypeDef* periph)
static void sdio_low_level_init(void)
{
_sd_sdio_clk_enable(SD_SDIO);
_sd_sdio_clk_enable(currentSD.periph);
// data pins
gpio_init(SD_SDIO_PIN_D0, GPIO_IN_PU, GPIO_PIN_SPEED_VERY_HIGH);
gpio_set_af(SD_SDIO_PIN_D0, SD_SDIO_AF_D0);
gpio_init(currentSD.D0, GPIO_IN_PU, GPIO_PIN_SPEED_VERY_HIGH);
gpio_set_af(currentSD.D0, currentSD.AF_D0);
gpio_init(SD_SDIO_PIN_D1, GPIO_IN_PU, GPIO_PIN_SPEED_VERY_HIGH);
gpio_set_af(SD_SDIO_PIN_D1, SD_SDIO_AF_D1);
gpio_init(SD_SDIO_PIN_D2, GPIO_IN_PU, GPIO_PIN_SPEED_VERY_HIGH);
gpio_set_af(SD_SDIO_PIN_D2, SD_SDIO_AF_D2);
gpio_init(currentSD.D1, GPIO_IN_PU, GPIO_PIN_SPEED_VERY_HIGH);
gpio_set_af(currentSD.D1, currentSD.AF_D1);
gpio_init(SD_SDIO_PIN_D3, GPIO_IN_PU, GPIO_PIN_SPEED_VERY_HIGH);
gpio_set_af(SD_SDIO_PIN_D3, SD_SDIO_AF_D3);
gpio_init(currentSD.D2, GPIO_IN_PU, GPIO_PIN_SPEED_VERY_HIGH);
gpio_set_af(currentSD.D2, currentSD.AF_D2);
gpio_init(SD_SDIO_PIN_CMD, GPIO_IN_PU, GPIO_PIN_SPEED_VERY_HIGH);
gpio_set_af(SD_SDIO_PIN_CMD, SD_SDIO_AF_CMD);
gpio_init(SD_SDIO_PIN_CLK, GPIO_IN_PU, GPIO_PIN_SPEED_VERY_HIGH);
gpio_set_af(SD_SDIO_PIN_CLK, SD_SDIO_AF_CLK);
gpio_init(currentSD.D3, GPIO_IN_PU, GPIO_PIN_SPEED_VERY_HIGH);
gpio_set_af(currentSD.D3, currentSD.AF_D3);
gpio_init(currentSD.CMD, GPIO_IN_PU, GPIO_PIN_SPEED_VERY_HIGH);
gpio_set_af(currentSD.CMD, currentSD.AF_CMD);
gpio_init(currentSD.CLK, GPIO_IN_PU, GPIO_PIN_SPEED_VERY_HIGH);
gpio_set_af(currentSD.CLK, currentSD.AF_CLK);
#if defined(SD_SDIO_HAS_TRANSCEIVER)
gpio_init_af(SD_SDIO_PIN_CKIN, SD_SDIO_AF_CKIN, GPIO_PIN_SPEED_HIGH);
@@ -208,8 +227,8 @@ static void sdio_low_level_init(void)
#endif
// SDIO Interrupt ENABLE
NVIC_SetPriority(SD_SDIO_IRQn, 0);
NVIC_EnableIRQ(SD_SDIO_IRQn);
NVIC_SetPriority(currentSD.IRQn, 0);
NVIC_EnableIRQ(currentSD.IRQn);
#if defined(SD_SDIO_DMA)
// Init SDIO DMA instance
@@ -231,7 +250,7 @@ static void sdio_low_level_init(void)
__HAL_LINKDMA(&sdio, hdmatx, sdioTxDma);
__HAL_LINKDMA(&sdio, hdmarx, sdioTxDma);
// DMA2 STREAMx Interrupt ENABLE
NVIC_SetPriority(SD_SDIO_DMA_IRQn, 0);
NVIC_EnableIRQ(SD_SDIO_DMA_IRQn);
@@ -241,6 +260,27 @@ static void sdio_low_level_init(void)
HAL_SD_CardInfoTypeDef cardInfo;
static DSTATUS sdio_initialize(BYTE lun)
{
#if defined(SD2_PRESENT_GPIO)
/* Define active SD */
if (gpio_read(SD2_PRESENT_GPIO) == 0) {
currentSD.periph = SDMMC2;
currentSD.D0 = SD2_SDIO_PIN_D0;
currentSD.AF_D0 = SD2_SDIO_AF_D0;
currentSD.D1 = SD2_SDIO_PIN_D1;
currentSD.AF_D1 = SD2_SDIO_AF_D1;
currentSD.D2 = SD2_SDIO_PIN_D2;
currentSD.AF_D2 = SD2_SDIO_AF_D2;
currentSD.D3 = SD2_SDIO_PIN_D3;
currentSD.AF_D3 = SD2_SDIO_AF_D3;
currentSD.CMD = SD2_SDIO_PIN_CMD;
currentSD.AF_CMD = SD2_SDIO_AF_CMD;
currentSD.CLK = SD2_SDIO_PIN_CLK;
currentSD.AF_CLK = SD2_SDIO_AF_CLK;
currentSD.IRQn = SDMMC2_IRQn;
currentSD.SD_CLK_DIV = SD2_SDIO_TRANSFER_CLK_DIV;
}
#endif
/* SDIO Peripheral Low Level Init */
sdio_low_level_init();
@@ -248,7 +288,7 @@ static DSTATUS sdio_initialize(BYTE lun)
/*!< SDIO_CK = SDIOCLK / (SDIO_TRANSFER_CLK_DIV + 2) */
/*!< on STM32F4xx devices, SDIOCLK is fixed to 48MHz */
sdio.Instance = SD_SDIO;
sdio.Instance = currentSD.periph;
sdio.Init.ClockEdge = SD_SDIO_CLOCK_EDGE_RISING;
sdio.Init.ClockPowerSave = SD_SDIO_CLOCK_POWER_SAVE_DISABLE;
sdio.Init.BusWide = SD_SDIO_BUS_WIDE_1B;
@@ -259,7 +299,7 @@ static DSTATUS sdio_initialize(BYTE lun)
#if defined(SD_SDIO_CLOCK_BYPASS_DISABLE)
sdio.Init.ClockBypass = SD_SDIO_CLOCK_BYPASS_DISABLE;
#endif
sdio.Init.ClockDiv = SD_SDIO_TRANSFER_CLK_DIV;
sdio.Init.ClockDiv = currentSD.SD_CLK_DIV;
HAL_StatusTypeDef halStatus = HAL_SD_Init(&sdio);
if (halStatus != HAL_OK) {
@@ -311,7 +351,7 @@ static SDTransferState sdio_check_card_state()
else if (cardstate == HAL_SD_CARD_ERROR) {
return SD_TRANSFER_ERROR;
}
return SD_TRANSFER_BUSY;
}
@@ -333,7 +373,11 @@ static DSTATUS sdio_status(BYTE lun)
{
DSTATUS stat = RES_OK;
#if defined(SD_PRESENT_GPIO)
#if defined(SD2_PRESENT_GPIO)
if (currentSD.periph == SDMMC2 && gpio_read(SD2_PRESENT_GPIO)) {
stat |= STA_NODISK;
}
#elif defined(SD_PRESENT_GPIO)
if (gpio_read(SD_PRESENT_GPIO)) {
stat |= STA_NODISK;
}
@@ -551,12 +595,28 @@ extern "C" void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
ReadStatus = 1;
}
#if defined(SDMMC1)
#if defined(SDMMC1)
extern "C" void SDMMC1_IRQHandler(void)
{
DEBUG_INTERRUPT(INT_SDIO);
HAL_SD_IRQHandler(&sdio);
}
#endif
#if defined(SDMMC2) && defined(SD2_PRESENT_GPIO)
extern "C" void SDMMC2_IRQHandler(void)
{
DEBUG_INTERRUPT(INT_SDIO);
HAL_SD_IRQHandler(&sdio);
}
#endif
#else
extern "C" void SD_SDIO_IRQHandler(void)
{
DEBUG_INTERRUPT(INT_SDIO);
HAL_SD_IRQHandler(&sdio);
}
#endif
#if defined(SD_SDIO_DMA)
extern "C" void SD_SDIO_DMA_IRQHANDLER(void)
{
@@ -48,8 +48,10 @@ static const stm32_usart_t fsUSART = {
.IRQn = FLYSKY_HALL_SERIAL_USART_IRQn,
.IRQ_Prio = 4,
.txDMA = FLYSKY_HALL_SERIAL_DMA,
#if defined(FLYSKY_HALL_DMA_Stream_TX)
.txDMA_Stream = FLYSKY_HALL_DMA_Stream_TX,
.txDMA_Channel = FLYSKY_HALL_DMA_Channel,
#endif
.rxDMA = FLYSKY_HALL_SERIAL_DMA,
.rxDMA_Stream = FLYSKY_HALL_DMA_Stream_RX,
.rxDMA_Channel = FLYSKY_HALL_DMA_Channel,
@@ -263,12 +265,17 @@ bool flysky_gimbal_init()
{
if (flysky_gimbal_init_uart() != 0) return false;
// Wait 70ms for FlySky gimbals to respond. According to LA trace, minimally
// 23ms is required
_fs_gimbal_detected = false;
for (uint8_t i = 0; i < 70; i++) {
// Wait 70ms for serial gimbals to respond
for (uint16_t i = 0; i < 70; i++) {
#if defined(HALL_SYNC) && !defined(SIMU)
gpio_set(HALL_SYNC);
#endif
delay_ms(1);
#if defined(HALL_SYNC) && !defined(SIMU)
gpio_clear(HALL_SYNC);
#endif
if (_fs_gimbal_detected) {
// Try to obtain the version of gimbal for operation mode selection
_fs_cmd_get_version();
@@ -24,7 +24,7 @@
#define __INIT_HOOK __attribute__((section(".init_hook")))
#define __CCMRAM __attribute__((section(".ccm"), aligned(4)))
#define __DMA __attribute__((section(".ram"), aligned(4)))
#define __DMA __attribute__((section(".ram"), aligned(32)))
#define __DMA_NO_CACHE __attribute__((section(".dram"), aligned(4)))
#define __IRAM __attribute__((section(".iram")))
#define __SDRAM __attribute__((section(".sdram"), aligned(4)))
@@ -32,6 +32,10 @@ void pwrInit()
gpio_init(SD_PRESENT_GPIO, GPIO_IN_PU, GPIO_PIN_SPEED_LOW);
#endif
#if defined(SD2_PRESENT_GPIO)
gpio_init(SD2_PRESENT_GPIO, GPIO_IN_PU, GPIO_PIN_SPEED_LOW);
#endif
#if defined(INTMODULE_BOOTCMD_GPIO)
gpio_init(INTMODULE_BOOTCMD_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW);
gpio_write(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_DEFAULT);
@@ -154,6 +154,7 @@ void rotaryEncoderStartDelay()
void rotaryEncoderInit()
{
#if defined(ROTARY_ENCODER_GPIO)
LL_GPIO_InitTypeDef pinInit;
LL_GPIO_StructInit(&pinInit);
pinInit.Mode = LL_GPIO_MODE_INPUT;
@@ -186,6 +187,44 @@ void rotaryEncoderInit()
uint32_t trigger = LL_EXTI_TRIGGER_RISING_FALLING;
stm32_exti_enable(ROTARY_ENCODER_EXTI_LINE1, trigger, rotaryEncoderStartDelay);
stm32_exti_enable(ROTARY_ENCODER_EXTI_LINE2, trigger, rotaryEncoderStartDelay);
#else
LL_GPIO_InitTypeDef pinInit;
LL_GPIO_StructInit(&pinInit);
pinInit.Mode = LL_GPIO_MODE_INPUT;
pinInit.Pull = LL_GPIO_PULL_UP;
pinInit.Pin = ROTARY_ENCODER_GPIO_PIN_A;
stm32_gpio_enable_clock(ROTARY_ENCODER_GPIO_A);
stm32_gpio_enable_clock(ROTARY_ENCODER_GPIO_B);
LL_GPIO_Init(ROTARY_ENCODER_GPIO_A, &pinInit);
pinInit.Pin = ROTARY_ENCODER_GPIO_PIN_B;
LL_GPIO_Init(ROTARY_ENCODER_GPIO_B, &pinInit);
stm32_timer_enable_clock(ROTARY_ENCODER_TIMER);
ROTARY_ENCODER_TIMER->ARR = 99; // 100uS
ROTARY_ENCODER_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1; // 1uS
ROTARY_ENCODER_TIMER->CCER = 0;
ROTARY_ENCODER_TIMER->CCMR1 = 0;
ROTARY_ENCODER_TIMER->EGR = 0;
ROTARY_ENCODER_TIMER->CR1 = 0;
ROTARY_ENCODER_TIMER->DIER |= TIM_DIER_UIE;
#if defined(LL_APB4_GRP1_PERIPH_SYSCFG)
LL_APB4_GRP1_EnableClock(LL_APB4_GRP1_PERIPH_SYSCFG);
#elif defined(LL_APB2_GRP1_PERIPH_SYSCFG)
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
#else
#error "Unsupported SYSCFG clock"
#endif
LL_SYSCFG_SetEXTISource(ROTARY_ENCODER_EXTI_PORT_A, ROTARY_ENCODER_EXTI_SYS_LINE1);
LL_SYSCFG_SetEXTISource(ROTARY_ENCODER_EXTI_PORT_B, ROTARY_ENCODER_EXTI_SYS_LINE2);
uint32_t trigger = LL_EXTI_TRIGGER_RISING_FALLING;
stm32_exti_enable(ROTARY_ENCODER_EXTI_LINE1, trigger, rotaryEncoderStartDelay);
stm32_exti_enable(ROTARY_ENCODER_EXTI_LINE2, trigger, rotaryEncoderStartDelay);
#endif
NVIC_EnableIRQ(ROTARY_ENCODER_TIMER_IRQn);
NVIC_SetPriority(ROTARY_ENCODER_TIMER_IRQn, 7);
@@ -67,8 +67,14 @@ void rtcInit()
__HAL_RCC_PWR_CLK_ENABLE();
#endif
HAL_PWR_EnableBkUpAccess();
#if defined(LSE_DRIVE_STRENGTH)
__HAL_RCC_LSE_CONFIG(RCC_LSE_OFF);
__HAL_RCC_LSEDRIVE_CONFIG(LSE_DRIVE_STRENGTH);
#endif
// Enable LSE Oscillator
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct = {};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
#if !defined(STM32H7RS) && !defined(STM32H5)
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
@@ -33,8 +33,12 @@
#include <string.h>
#include "FreeRTOSConfig.h"
#define OVERSAMPLING 4
#if defined(STM32H7) || defined(STM32H7RS) || defined(STM32H5)
// Disable software oversampling as HW one is used
#define OVERSAMPLING 1
#else
#define OVERSAMPLING 4
#endif
#define SAMPLING_TIMEOUT_US 500
@@ -78,6 +82,9 @@ static uint8_t _adc_run;
static uint8_t _adc_oversampling_disabled;
static uint16_t _adc_oversampling[MAX_ADC_INPUTS];
// Indicates ADC timeout has occured
static bool _adc_timeout_error;
void stm32_hal_set_inputs_mask(uint32_t inputs)
{
_adc_input_inhibt_mask |= inputs;
@@ -232,6 +239,12 @@ static void adc_setup_scan_mode(ADC_TypeDef* ADCx, uint8_t nconv)
wait_loop_index--;
}
}
/* Start ADC calibration in mode single-ended or differential */
LL_ADC_StartCalibration(ADCx, LL_ADC_CALIB_OFFSET_LINEARITY, LL_ADC_SINGLE_ENDED);
/* Wait for calibration completion */
while (LL_ADC_IsCalibrationOnGoing(ADCx) != 0UL);
#endif
#if defined(LL_ADC_RESOLUTION_12B_OPT)
@@ -253,6 +266,17 @@ static void adc_setup_scan_mode(ADC_TypeDef* ADCx, uint8_t nconv)
#endif
}
#if defined(STM32H7RS) || defined(STM32H7) || defined(STM32H5)
// set hardware oversampling
if (!_adc_oversampling_disabled && ADCx != ADC3) {
// LL_ADC_OVS_RATIO_x in stm32h7xx_ll_adc.h is broken
// so actual oversampling count need to be used
// ADC3 oversampling is disabled because of issues in LL libs
LL_ADC_ConfigOverSamplingRatioShift(ADCx, 16, LL_ADC_OVS_SHIFT_RIGHT_4);
LL_ADC_SetOverSamplingScope(ADCx, LL_ADC_OVS_GRP_REGULAR_CONTINUED);
}
#endif
LL_ADC_REG_Init(ADCx, &adcRegInit);
// Enable ADC
@@ -756,10 +780,12 @@ void stm32_hal_adc_wait_completion(const stm32_adc_t* ADCs, uint8_t n_ADC,
// busy wait
if ((uint32_t)(timersGetUsTick() - timeout) >= SAMPLING_TIMEOUT_US) {
TRACE("ADC timeout");
_adc_timeout_error = true;
_adc_started_mask = 0;
return;
}
}
_adc_timeout_error = false;
}
void stm32_hal_adc_disable_oversampling()
@@ -787,7 +813,7 @@ static void _adc_chain_conversions(const stm32_adc_t* adc)
for (uint8_t i = 0; i < _adc_n_inputs; i++) {
if (~_adc_input_mask & (1 << i)) continue;
if (_adc_inhibit_mask & (1 << i)) continue;
adcValues[i] = _adc_oversampling[i] / OVERSAMPLING;
if (!_adc_timeout_error) adcValues[i] = _adc_oversampling[i] / OVERSAMPLING;
}
// we're done!
@@ -360,7 +360,14 @@ static int i2c_init_clock_source(I2C_TypeDef* instance)
#endif
#if defined(LL_RCC_I2C123_CLKSOURCE)
LL_RCC_SetClockSource(LL_RCC_I2C123_CLKSOURCE_PCLK1);
# if defined(LL_RCC_I2C4_CLKSOURCE)
if (instance == I2C4) {
LL_RCC_SetClockSource(LL_RCC_I2C4_CLKSOURCE_PCLK4);
} else
# endif
{
LL_RCC_SetClockSource(LL_RCC_I2C123_CLKSOURCE_PCLK1);
}
#endif
return 0;
@@ -371,15 +378,17 @@ static int i2c_init_clock_source(I2C_TypeDef* instance)
static int i2c_enable_clock(I2C_TypeDef* instance)
{
/* Peripheral clock enable */
if (instance == I2C1) {
if (instance == I2C1)
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
} else if (instance == I2C2) {
else if (instance == I2C2)
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C2);
} else if (instance == I2C3) {
else if (instance == I2C3)
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3);
} else {
return -1;
}
#if defined(I2C4)
else if (instance == I2C4)
LL_APB4_GRP1_EnableClock(LL_APB4_GRP1_PERIPH_I2C4);
#endif
else return -1;
return 0;
}
@@ -393,6 +402,10 @@ static int i2c_disable_clock(I2C_TypeDef* instance)
LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_I2C2);
else if (instance == I2C3)
LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_I2C3);
#if defined(I2C4)
else if (instance == I2C4)
LL_APB4_GRP1_DisableClock(LL_APB4_GRP1_PERIPH_I2C4);
#endif
else
return -1;
@@ -472,17 +485,17 @@ int stm32_i2c_init(uint8_t bus, uint32_t clock_rate, const stm32_i2c_hw_def_t* h
if (i2c_gpio_init(hw_def) < 0) {
TRACE("I2C ERROR: HAL_I2C_MspInit() I2C_GPIO misconfiguration");
return -1;
return -2;
}
if (i2c_enable_clock(hw_def->I2Cx) < 0) {
TRACE("I2C ERROR: HAL_I2C_MspInit() I2C misconfiguration");
return -1;
return -3;
}
if (HAL_I2C_Init(h) != HAL_OK) {
TRACE("I2C ERROR: HAL_I2C_Init() failed");
return -1;
return -4;
}
#if defined(I2C_FLTR_ANOFF) && defined(I2C_FLTR_DNF) || defined(STM32H7) || \
@@ -480,6 +480,7 @@ bool stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params)
if (params->direction & ETX_Dir_TX)
usartInit.TransferDirection |= LL_USART_DIRECTION_TX;
LL_USART_Init(usart->USARTx, &usartInit);
LL_USART_Enable(usart->USARTx);
@@ -380,6 +380,11 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)
hpcd_USB_OTG.Init.speed = PCD_SPEED_FULL;
hpcd_USB_OTG.Init.dma_enable = DISABLE;
hpcd_USB_OTG.Init.phy_itface = PCD_PHY_EMBEDDED;
#if defined(STM32H7)
hpcd_USB_OTG.Init.battery_charging_enable = DISABLE;
hpcd_USB_OTG.Init.use_external_vbus = ENABLE;
#endif
hpcd_USB_OTG.Init.Sof_enable = ENABLE;
hpcd_USB_OTG.Init.low_power_enable = DISABLE;
hpcd_USB_OTG.Init.lpm_enable = DISABLE;
-1
View File
@@ -864,7 +864,6 @@
#define SD_SDIO_DMA_IRQn DMA2_Stream3_IRQn
#define SD_SDIO_DMA_IRQHANDLER DMA2_Stream3_IRQHandler
#define SD_SDIO_CLK_DIV(fq) ((48000000 / (fq)) - 2)
#define SD_SDIO_INIT_CLK_DIV SD_SDIO_CLK_DIV(400000)
#define SD_SDIO_TRANSFER_CLK_DIV SD_SDIO_CLK_DIV(24000000)
// Uncomment only one line below to select which storage to use
-1
View File
@@ -269,7 +269,6 @@
#define SD_SDIO_DMA_IRQn DMA2_Stream3_IRQn
#define SD_SDIO_DMA_IRQHANDLER DMA2_Stream3_IRQHandler
#define SD_SDIO_CLK_DIV(fq) ((48000000 / (fq)) - 2)
#define SD_SDIO_INIT_CLK_DIV SD_SDIO_CLK_DIV(400000)
#define SD_SDIO_TRANSFER_CLK_DIV SD_SDIO_CLK_DIV(24000000)
#define STORAGE_USE_SDIO
+1
View File
@@ -29,6 +29,7 @@ void ledGreen() {}
void ledBlue() {}
void ledOff() {}
void rgbLedColorApply() {}
void rgbLedClearAll() {}
bool fsLedState(uint8_t i)
{
+1 -1
View File
@@ -205,7 +205,7 @@
#define ADC_DMA_STREAM LL_DMA_STREAM_4
#define ADC_DMA_STREAM_IRQ DMA2_Stream4_IRQn
#define ADC_DMA_STREAM_IRQHandler DMA2_Stream4_IRQHandler
#define ADC_SAMPTIME LL_ADC_SAMPLINGTIME_64CYCLES_5
#define ADC_SAMPTIME LL_ADC_SAMPLINGTIME_8CYCLES_5
#define ADC_EXT ADC3
#define ADC_EXT_CHANNELS \
+1 -1
View File
@@ -366,7 +366,7 @@ void setTopBatteryValue(uint32_t volts);
#define BATTERY_DIVIDER 39500
#else
#define BATTERY_DIVIDER 26214
#endif
#endif
#define VOLTAGE_DROP 20
#endif
+196
View File
@@ -0,0 +1,196 @@
option(UNEXPECTED_SHUTDOWN "Enable the Unexpected Shutdown screen" ON)
option(PXX1 "PXX1 protocol support" ON)
option(PXX2 "PXX2 protocol support" OFF)
option(AFHDS3 "AFHDS3 TX Module" ON)
option(MULTIMODULE "DIY Multiprotocol TX Module (https://github.com/pascallanger/DIY-Multiprotocol-TX-Module)" ON)
option(GHOST "Ghost TX Module" ON)
option(MODULE_SIZE_STD "Standard size TX Module" ON)
option(LUA_MIXER "Enable LUA mixer/model scripts support" ON)
option(DISK_CACHE "Enable SD card disk cache" ON)
set(FIRMWARE_QSPI YES)
set(FIRMWARE_FORMAT_UF2 YES)
set(PWR_BUTTON "PRESS" CACHE STRING "Pwr button type (PRESS/SWITCH)")
set(CPU_TYPE STM32H7)
set(HSE_VALUE 48000000)
set(SDCARD YES)
set(STORAGE_MODELSLIST YES)
set(HAPTIC YES)
set(GUI_DIR colorlcd)
set(BITMAPS_DIR 480x272)
set(TARGET_DIR tx15)
set(RTC_BACKUP_RAM YES)
set(PPM_LIMITS_SYMETRICAL YES)
set(USB_SERIAL ON CACHE BOOL "Enable USB serial (CDC)")
set(HARDWARE_EXTERNAL_MODULE YES)
set(INTERNAL_MODULE_AFHDS3 NO)
set(ROTARY_ENCODER YES)
set(FUNCTION_SWITCHES_WITH_RGB YES)
#option(STICKS_DEAD_ZONE "Enable sticks dead zone" YES)
# IMU support
set(IMU ON)
add_definitions(-DIMU_ICM4207C)
# for size report script
set(CPU_TYPE_FULL STM32H750xB)
set(TARGET_LINKER_DIR stm32h750_sdram)
set(TARGET_EXTRAM_START 0xD0000000)
set(SIZE_TARGET_MEM_DEFINE "MEM_SIZE_SDRAM1=8192")
set(FIRMWARE_STRIP_BOOTLOADER YES)
add_definitions(-DPCBTX15 -DPCBHORUS)
add_definitions(-DBATTERY_CHARGE)
add_definitions(-DSTM32_SUPPORT_32BIT_TIMERS)
add_definitions(-DFIRMWARE_QSPI)
add_definitions(-DFIRMWARE_FORMAT_UF2)
add_definitions(-DUSE_CUSTOM_EXTI_IRQ)
add_definitions(-DUSB_CHARGER)
set(FLAVOUR tx15)
add_definitions(-DRADIO_TX15)
add_definitions(-DMANUFACTURER_RADIOMASTER)
# defines existing internal modules
set(INTERNAL_MODULES CRSF CACHE STRING "Internal modules")
set(DEFAULT_INTERNAL_MODULE CROSSFIRE CACHE STRING "Default internal module")
set(BITMAPS_TARGET bm480_bitmaps)
set(FONTS_TARGET x12_fonts)
set(LCD_DRIVER lcd_driver.cpp)
set(HARDWARE_TOUCH YES)
set(RADIO_DEPENDENCIES ${RADIO_DEPENDENCIES} ${BITMAPS_TARGET})
set(FIRMWARE_DEPENDENCIES datacopy)
set(SOFTWARE_KEYBOARD ON)
set(FLYSKY_GIMBAL ON)
set(FUNCTION_SWITCHES ON)
set(USB_CHARGER YES)
set(AUX_SERIAL YES)
set(AUX2_SERIAL YES)
add_definitions(
-DSTM32H750XBTx -DSTM32H750xx
-DSDRAM -DCCMRAM
-DCOLORLCD -DLIBOPENUI
-DHARDWARE_TOUCH -DHARDWARE_KEYS -DSOFTWARE_KEYBOARD
-DWS2812_MAX_LEDS=26
)
set(SDRAM ON)
add_definitions(-DAUDIO -DVOICE -DRTCLOCK)
add_definitions(-DGPS_USART_BAUDRATE=${INTERNAL_GPS_BAUDRATE})
add_definitions(-DPWR_BUTTON_${PWR_BUTTON})
if(STICKS_DEAD_ZONE)
add_definitions(-DSTICK_DEAD_ZONE)
endif()
if(NOT UNEXPECTED_SHUTDOWN)
add_definitions(-DNO_UNEXPECTED_SHUTDOWN)
endif()
if(DISK_CACHE)
set(SRC ${SRC} disk_cache.cpp)
add_definitions(-DDISK_CACHE)
endif()
if(FUNCTION_SWITCHES_WITH_RGB)
set(FUNCTION_SWITCHES YES)
add_definitions(-DFUNCTION_SWITCHES)
add_definitions(-DFUNCTION_SWITCHES_RGB_LEDS)
endif()
if(FUNCTION_SWITCHES)
add_definitions(-DFUNCTION_SWITCHES)
endif()
set(AFHDS3 ON)
# VCP CLI
set(ENABLE_SERIAL_PASSTHROUGH ON CACHE BOOL "Enable serial passthrough")
set(CLI ON CACHE BOOL "Enable CLI")
set(TARGET_SRC_DIR targets/${TARGET_DIR})
set(BOARD_COMMON_SRC
${TARGET_SRC_DIR}/board.cpp
${TARGET_SRC_DIR}/bsp_io.cpp
${TARGET_SRC_DIR}/key_driver.cpp
${TARGET_SRC_DIR}/lcd_driver.cpp
${TARGET_SRC_DIR}/backlight_driver.cpp
${TARGET_SRC_DIR}/haptic_driver.cpp
${TARGET_SRC_DIR}/extflash_driver.cpp
${TARGET_SRC_DIR}/usb_charger_driver.cpp
targets/common/arm/stm32/abnormal_reboot.cpp
targets/common/arm/stm32/delays_driver.cpp
targets/common/arm/stm32/dma2d.cpp
targets/common/arm/stm32/flash_driver.cpp
targets/common/arm/stm32/pwr_driver.cpp
targets/common/arm/stm32/rotary_encoder_driver.cpp
targets/common/arm/stm32/rtc_driver.cpp
targets/common/arm/stm32/watchdog_driver.cpp
drivers/pca95xx.cpp
)
# Bootloader board library
add_library(board_bl OBJECT EXCLUDE_FROM_ALL
${BOARD_COMMON_SRC}
${TARGET_SRC_DIR}/system_clock.c
${TARGET_SRC_DIR}/sdram_driver.cpp
${TARGET_SRC_DIR}/usb_charger_driver.cpp
${RADIO_SRC_DIR}/gui/colorlcd/boot_menu.cpp
targets/common/arm/stm32/stm32_qspi.cpp
targets/common/arm/stm32/stm32_pulse_driver.cpp
)
add_dependencies(board_bl minimal_board_lib)
set(BOOTLOADER_SRC ${BOOTLOADER_SRC} $<TARGET_OBJECTS:board_bl>)
# Firmware board library
add_library(board OBJECT EXCLUDE_FROM_ALL
${BOARD_COMMON_SRC}
${TARGET_SRC_DIR}/led_driver.cpp
${TARGET_SRC_DIR}/tp_gt911.cpp
${TARGET_SRC_DIR}/audio_driver.cpp
drivers/icm42607C.cpp
drivers/imu_filter.cpp
drivers/tas2505.cpp
targets/common/arm/stm32/heartbeat_driver.cpp
targets/common/arm/stm32/mixer_scheduler_driver.cpp
targets/common/arm/stm32/module_timer_driver.cpp
targets/common/arm/stm32/stm32_pulse_driver.cpp
targets/common/arm/stm32/stm32_softserial_driver.cpp
targets/common/arm/stm32/stm32_qspi.cpp
targets/common/arm/stm32/stm32_i2s.cpp
targets/common/arm/stm32/stm32_switch_driver.cpp
targets/common/arm/stm32/stm32_ws2812.cpp
targets/common/arm/stm32/trainer_driver.cpp
)
add_dependencies(board board_lib)
set(FIRMWARE_SRC ${FIRMWARE_SRC} $<TARGET_OBJECTS:board>)
include_directories(${RADIO_SRC_DIR}/fonts/colorlcd gui/${GUI_DIR} gui/${GUI_DIR}/layouts)
if(BOOTLOADER)
set(FIRMWARE_TARGET_SRC
${FIRMWARE_TARGET_SRC}
../../bootloader/loadboot.cpp
)
endif()
set(SRC
${SRC}
io/frsky_firmware_update.cpp
io/multi_firmware_update.cpp
)
if (MULTIMODULE)
add_definitions(-DMULTI_PROTOLIST)
set(SRC ${SRC}
io/multi_protolist.cpp
)
endif()
# Make malloc() thread-safe
add_definitions(-DTHREADSAFE_MALLOC)
+156
View File
@@ -0,0 +1,156 @@
#include "drivers/tas2505.h"
#include "stm32_dma.h"
#include "stm32_i2s.h"
#include "stm32_i2c_driver.h"
#include "stm32_hal_ll.h"
#include "timers_driver.h"
#include "audio.h"
#include "debug.h"
#define DEFAULT_DAC_VOL -15 // -7dB
#define DEFAULT_HP_VOL 20
#define DEFAULT_SPK_VOL 40
static tas2505_t _tas2505 = {
.ndac = 2,
.mdac = 1,
.dosr = 256,
.dac_vol = DEFAULT_DAC_VOL,
.hp_drv = 0,
.hp_vol = DEFAULT_HP_VOL,
.spk_drv = TAS2505_SPK_DRV_32_DB,
.spk_vol = DEFAULT_SPK_VOL,
};
//
// TX15 pinout
//
// Pin MCU TAS2505
// ---------------------------------
// PC6 (I2S2_MCK): MCLK <-> MCLK
// PI0 (I2S2_WS): WCLK <-> WCLK
// PI1 (I2S2_CK): BCLK <-> BCLK
// PI3 (I2S2_SDO): DOUT <-> DIN
// PC2 (I2S2_SDI): DIN <-> DOUT
const stm32_i2s_t _i2s_dev = {
.SPIx = AUDIO_SPI,
.MCK = {GPIO_PIN(GPIOC, 6), GPIO_AF5},
.WS = {GPIO_PIN(GPIOI, 0), GPIO_AF5},
.CK = {GPIO_PIN(GPIOI, 1), GPIO_AF5},
.SDO = {GPIO_PIN(GPIOI, 3), GPIO_AF5},
.SDI = {GPIO_PIN(GPIOI, 2), GPIO_AF5},
.DMA = I2S_DMA,
.DMA_Stream = I2S_DMA_Stream,
.DMA_PeriphRequest = I2S_DMA_Stream_Request,
};
// 16 bit, 2 channels
#define DMA_BUFFER_HALF_LEN AUDIO_BUFFER_SIZE
// 2 buffers
#define DMA_BUFFER_LEN (DMA_BUFFER_HALF_LEN * 2)
static int32_t _dma_buffer[DMA_BUFFER_LEN] __DMA_NO_CACHE;
static void enable_dma_irqs()
{
LL_DMA_EnableIT_HT(I2S_DMA, I2S_DMA_Stream);
LL_DMA_EnableIT_TC(I2S_DMA, I2S_DMA_Stream);
NVIC_SetPriority(I2S_DMA_Stream_IRQn, 7);
NVIC_EnableIRQ(I2S_DMA_Stream_IRQn);
}
int audioInit()
{
gpio_init(AUDIO_HP_DETECT_PIN, GPIO_IN_PU, GPIO_PIN_SPEED_LOW);
memset(_dma_buffer, 0, sizeof(_dma_buffer));
if (tas2505_probe(&_tas2505, 0, 0x30 >> 1) < 0) {
return -1;
}
if (stm32_i2s_init(&_i2s_dev)) {
return -1;
}
enable_dma_irqs();
return tas2505_init(&_tas2505);
}
static volatile uint32_t _dma_buffer_offset = 0;
void audioConsumeCurrentBuffer()
{
if (!stm32_i2s_is_xfer_started(&_i2s_dev)) {
auto buffer = audioQueue.buffersFifo.getNextFilledBuffer();
if (!buffer) return;
unsigned idx = 0;
for (; idx < buffer->size; idx++) {
uint32_t offset = _dma_buffer_offset + idx;
_dma_buffer[offset] = (uint32_t)buffer->data[idx];
}
for (; idx < DMA_BUFFER_HALF_LEN; idx++) {
uint32_t offset = _dma_buffer_offset + idx;
_dma_buffer[offset] = 0;
}
audioQueue.buffersFifo.freeNextFilledBuffer();
stm32_i2s_config_dma_stream(&_i2s_dev, _dma_buffer, DMA_BUFFER_LEN * 2);
stm32_i2s_start_dma_stream(&_i2s_dev);
}
}
static inline uint32_t _calc_offset(uint8_t tc)
{
return tc * DMA_BUFFER_HALF_LEN;
}
static void audio_update_dma_buffer(uint8_t tc)
{
_dma_buffer_offset = _calc_offset(tc);
auto buffer = audioQueue.buffersFifo.getNextFilledBuffer();
if (!buffer) {
unsigned idx = 0;
for (; idx < DMA_BUFFER_HALF_LEN; idx++) {
uint32_t offset = _dma_buffer_offset + idx;
_dma_buffer[offset] = 0;
}
} else {
unsigned idx = 0;
for (; idx < buffer->size; idx++) {
uint32_t offset = _dma_buffer_offset + idx;
_dma_buffer[offset] = (uint16_t)buffer->data[idx];
}
for (; idx < DMA_BUFFER_HALF_LEN; idx++) {
uint32_t offset = _dma_buffer_offset + idx;
_dma_buffer[offset] = 0;
}
audioQueue.buffersFifo.freeNextFilledBuffer();
}
}
void audioSetVolume(uint8_t volume)
{
tas2505_set_volume(&_tas2505, volume * 9 / 10); // TX15 HP cannot handle the full power of TAS2505
}
extern "C" void DMA1_Stream4_IRQHandler(void)
{
if (stm32_dma_check_ht_flag(I2S_DMA, I2S_DMA_Stream)) {
audio_update_dma_buffer(0);
}
if (stm32_dma_check_tc_flag(I2S_DMA, I2S_DMA_Stream)) {
audio_update_dma_buffer(1);
}
}
@@ -0,0 +1,94 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "hal/gpio.h"
#include "stm32_gpio.h"
#include "stm32_timer.h"
#include "stm32_pulse_driver.h"
#include "edgetx_types.h"
#include "board.h"
#include "globals.h"
#include "lcd_driver.h"
static const stm32_pulse_timer_t _bl_timer = {
.GPIO = (gpio_t)BACKLIGHT_GPIO,
.GPIO_Alternate = BACKLIGHT_GPIO_AF,
.TIMx = BACKLIGHT_TIMER,
.TIM_Freq = BACKLIGHT_TIMER_FREQ,
.TIM_Channel = BACKLIGHT_TIMER_CHANNEL,
.TIM_IRQn = (IRQn_Type)-1,
.DMAx = nullptr,
.DMA_Stream = 0,
.DMA_Channel = 0,
.DMA_IRQn = (IRQn_Type)-1,
.DMA_TC_CallbackPtr = nullptr,
};
void backlightLowInit()
{
gpio_init(BACKLIGHT_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW);
gpio_clear(BACKLIGHT_GPIO);
}
void backlightInit()
{
stm32_pulse_init(&_bl_timer, 1000000);
stm32_pulse_config_output(&_bl_timer, true, LL_TIM_OCMODE_PWM1, 100);
LL_TIM_SetAutoReload(_bl_timer.TIMx, 100);
LL_TIM_EnableCounter(_bl_timer.TIMx);
}
uint8_t lastDutyCycle = 0;
void backlightEnable(uint8_t dutyCycle)
{
stm32_pulse_set_cmp_val(&_bl_timer, dutyCycle);
if(!dutyCycle) {
//experimental to turn off LCD when no backlight
if(lcdOffFunction) lcdOffFunction();
}
else if(!lastDutyCycle) {
if(lcdOnFunction) lcdOnFunction();
else lcdInit();
}
lastDutyCycle = dutyCycle;
}
void lcdOff() {
backlightEnable(0);
}
void lcdOn(){
// if(lcdOnFunction) lcdOnFunction();
// else lcdInit();
backlightEnable(BACKLIGHT_LEVEL_MAX);
}
bool boardBacklightOn;
bool isBacklightEnabled()
{
return boardBacklightOn;
}
+217
View File
@@ -0,0 +1,217 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "stm32_adc.h"
#include "stm32_gpio.h"
#include "stm32_i2c_driver.h"
#include "stm32_hal.h"
#include "stm32_ws2812.h"
#include "stm32_spi.h"
#include "flash_driver.h"
#include "extflash_driver.h"
#include "board.h"
#include "boards/generic_stm32/module_ports.h"
#include "boards/generic_stm32/rgb_leds.h"
#include "bsp_io.h"
#include "hal/adc_driver.h"
#include "hal/flash_driver.h"
#include "hal/trainer_driver.h"
#include "hal/rotary_encoder.h"
#include "hal/switch_driver.h"
#include "hal/abnormal_reboot.h"
#include "hal/watchdog_driver.h"
#include "hal/usb_driver.h"
#include "hal/gpio.h"
#include "hal/rgbleds.h"
#include "globals.h"
#include "sdcard.h"
#include "debug.h"
#include "flysky_gimbal_driver.h"
#include "timers_driver.h"
#include "bitmapbuffer.h"
#include "colors.h"
#include "touch_driver.h"
#include <string.h>
// common ADC driver
extern const etx_hal_adc_driver_t _adc_driver;
// RGB LED timer
extern const stm32_pulse_timer_t _led_timer;
static void led_strip_off()
{
for (uint8_t i = 0; i < LED_STRIP_LENGTH; i++) {
ws2812_set_color(i, 0, 0, 0);
}
ws2812_update(&_led_timer);
}
void INTERNAL_MODULE_ON()
{
gpio_set(INTMODULE_PWR_GPIO);
}
void INTERNAL_MODULE_OFF()
{
gpio_clear(INTMODULE_PWR_GPIO);
}
void EXTERNAL_MODULE_ON()
{
gpio_set(EXTMODULE_PWR_GPIO);
}
void EXTERNAL_MODULE_OFF()
{
gpio_clear(EXTMODULE_PWR_GPIO);
}
void boardBLEarlyInit()
{
// TAS2505 requires reset pin to be low on power on
gpio_init(AUDIO_RESET_PIN, GPIO_OUT, GPIO_PIN_SPEED_LOW);
gpio_clear(AUDIO_RESET_PIN);
timersInit();
bsp_io_init();
usbChargerInit();
}
void boardBLPreJump()
{
// TAS2505 requires reset pin to be high only after power on
// https://www.ti.com/lit/ug/slau472c/slau472c.pd fig 4.2
gpio_set(AUDIO_RESET_PIN);
ExtFLASH_Init();
SDRAM_Init();
// Stop 1ms timer
MS_TIMER->CR1 &= ~TIM_CR1_CEN;
}
void boardBLInit()
{
ExtFLASH_Init();
SDRAM_Init();
// register external FLASH for DFU
usbRegisterDFUMedia((void*)extflash_dfu_media);
// register internal & external FLASH for UF2
flashRegisterDriver(FLASH_BANK1_BASE, BOOTLOADER_SIZE, &stm32_flash_driver);
flashRegisterDriver(QSPI_BASE, 8 * 1024 * 1024, &extflash_driver);
}
void boardInit()
{
// enable interrupts
__enable_irq();
ledInit();
boardInitModulePorts();
pwrInit();
delaysInit();
timersInit();
bsp_io_init();
usbChargerInit();
gpio_set(LED_BLUE_GPIO);
gpio_init(HALL_SYNC, GPIO_OUT, GPIO_PIN_SPEED_LOW);
ExtFLASH_InitRuntime();
// register internal & external FLASH for UF2
flashRegisterDriver(FLASH_BANK1_BASE, BOOTLOADER_SIZE, &stm32_flash_driver);
flashRegisterDriver(QSPI_BASE, QSPI_FLASH_SIZE, &extflash_driver);
// init_trainer();
auto inittime = flysky_gimbal_init();
if (inittime)
TRACE("Serial gimbal detected in %d ms", inittime);
else
TRACE("No serial gimbal detected");
usbInit();
rgbLedInit();
led_strip_off();
keysInit();
switchInit();
rotaryEncoderInit();
touchPanelInit();
audioInit();
adcInit(&_adc_driver);
hapticInit();
// RTC must be initialized before rambackupRestore() is called
rtcInit();
}
extern void rtcDisableBackupReg();
void boardOff()
{
lcdOff();
while (pwrPressed()) {
WDG_RESET();
}
SysTick->CTRL = 0; // turn off systick
// Shutdown the Haptic
hapticDone();
rtcDisableBackupReg();
pwrOff();
// We reach here only in forced power situations, such as hw-debugging with external power
// Enter STM32 stop mode / deep-sleep
// Code snippet from ST Nucleo PWR_EnterStopMode example
#define PDMode 0x00000000U
#if defined(PWR_CR1_MRUDS) && defined(PWR_CR1_LPUDS) && defined(PWR_CR1_FPDS)
MODIFY_REG(PWR->CR1, (PWR_CR1_PDDS | PWR_CR1_LPDS | PWR_CR1_FPDS | PWR_CR1_LPUDS | PWR_CR1_MRUDS), PDMode);
#elif defined(PWR_CR_MRLVDS) && defined(PWR_CR_LPLVDS) && defined(PWR_CR_FPDS)
MODIFY_REG(PWR->CR1, (PWR_CR1_PDDS | PWR_CR1_LPDS | PWR_CR1_FPDS | PWR_CR1_LPLVDS | PWR_CR1_MRLVDS), PDMode);
#else
// MODIFY_REG(PWR->CR1, (PWR_CR1_P_PDDS| PWR_CR1_LPDS), PDMode);
#endif /* PWR_CR_MRUDS && PWR_CR_LPUDS && PWR_CR_FPDS */
/* Set SLEEPDEEP bit of Cortex System Control Register */
SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
// To avoid HardFault at return address, end in an endless loop
while (1) {
}
}
+243
View File
@@ -0,0 +1,243 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _BOARD_H_
#define _BOARD_H_
#include "definitions.h"
#include "edgetx_constants.h"
#include "board_common.h"
#include "hal.h"
#include "hal/serial_port.h"
#include "hal/watchdog_driver.h"
#define BOOTLOADER_SIZE 0x10000
#define BOOTLOADER_ADDRESS 0x08000000
#define FIRMWARE_ADDRESS 0x90000000
#define FIRMWARE_LEN(fsize) (fsize)
#define FIRMWARE_MAX_LEN FLASHSIZE
#define APP_START_ADDRESS (uint32_t)(FIRMWARE_ADDRESS)
#define BOOTLOADER_KEYS 0x42
#define MB *1024*1024
#define LUA_MEM_EXTRA_MAX (2 MB) // max allowed memory usage for Lua bitmaps (in bytes)
#define LUA_MEM_MAX (6 MB) // max allowed memory usage for complete Lua (in bytes), 0 means unlimited
extern uint16_t sessionTimer;
#define SLAVE_MODE() (g_model.trainerData.mode == TRAINER_MODE_SLAVE)
// Board driver
void boardInit();
void boardOff();
// CPU Unique ID
#define LEN_CPU_UID (3*8+2)
void getCPUUniqueID(char * s);
// Flash Write driver
#define FLASH_PAGESIZE 256
void unlockFlash();
void lockFlash();
void flashWrite(uint32_t * address, const uint32_t * buffer);
uint32_t isFirmwareStart(const uint8_t * buffer);
uint32_t isBootloaderStart(const uint8_t * buffer);
// SDRAM driver
extern "C" void SDRAM_Init();
// Pulses driver
#if !defined(SIMU)
void INTERNAL_MODULE_ON();
void INTERNAL_MODULE_OFF();
void EXTERNAL_MODULE_ON();
void EXTERNAL_MODULE_OFF();
#define EXTERNAL_MODULE_PWR_OFF EXTERNAL_MODULE_OFF
#define BLUETOOTH_MODULE_ON() gpio_clear(BLUETOOTH_ON_GPIO)
#define BLUETOOTH_MODULE_OFF() gpio_set(BLUETOOTH_ON_GPIO)
#define IS_INTERNAL_MODULE_ON() (false)
#define IS_EXTERNAL_MODULE_ON() (gpio_read(EXTMODULE_PWR_GPIO) ? 1 : 0)
#else
#define INTERNAL_MODULE_OFF()
#define INTERNAL_MODULE_ON()
#define EXTERNAL_MODULE_ON()
#define EXTERNAL_MODULE_OFF()
#define BLUETOOTH_MODULE_ON()
#define BLUETOOTH_MODULE_OFF()
#define IS_INTERNAL_MODULE_ON() (false)
#define IS_EXTERNAL_MODULE_ON() (false)
#endif // defined(SIMU)
#if defined(FUNCTION_SWITCHES)
#define NUM_FUNCTIONS_SWITCHES 6
#define NUM_FUNCTIONS_GROUPS 3
#define DEFAULT_FS_CONFIG \
(SWITCH_2POS << 10) + (SWITCH_2POS << 8) + (SWITCH_2POS << 6) + \
(SWITCH_2POS << 4) + (SWITCH_2POS << 2) + (SWITCH_2POS << 0)
#define DEFAULT_FS_GROUPS \
(1 << 10) + (1 << 8) + (1 << 6) + (1 << 4) + (1 << 2) + \
(1 << 0) // Set all FS to group 1 to act like a 6pos
#define DEFAULT_FS_STARTUP_CONFIG \
((FS_START_PREVIOUS << 10) + (FS_START_PREVIOUS << 8) + \
(FS_START_PREVIOUS << 6) + (FS_START_PREVIOUS << 4) + \
(FS_START_PREVIOUS << 2) + \
(FS_START_PREVIOUS << 0)) // keep last state by default
#else
#define NUM_FUNCTIONS_SWITCHES 0
#endif
#define NUM_TRIMS 8
#define DEFAULT_STICK_DEADZONE 2
#define BATTERY_WARN 74 // 7.4V
#define BATTERY_MIN 70 // 6.8V
#define BATTERY_MAX 86 // 8.6V
// --- MOSFET ---- R1 --- MCU
// |__ R2 --- GND
//
#define VBAT_DIV_R1 100 // kOhms
#define VBAT_DIV_R2 32 // kOhms
#define VBAT_MOSFET_DROP 0 // * 10mV
#if defined(__cplusplus) && !defined(SIMU)
extern "C" {
#endif
// Power driver
#define SOFT_PWR_CTRL
#define POWER_ON_DELAY 10 // 1s
void pwrInit();
void extModuleInit();
uint32_t pwrCheck();
uint32_t lowPowerCheck();
void pwrOn();
void pwrSoftReboot();
void pwrOff();
void pwrResetHandler();
bool pwrPressed();
bool pwrOffPressed();
#if defined(PWR_EXTRA_SWITCH_GPIO)
bool pwrForcePressed();
#else
#define pwrForcePressed() false
#endif
uint32_t pwrPressedDuration();;
const etx_serial_port_t* auxSerialGetPort(int port_nr);
#define AUX_SERIAL_POWER_ON()
#define AUX_SERIAL_POWER_OFF()
// LED driver
void ledInit();
void ledOff();
void ledRed();
void ledBlue();
void ledGreen();
// LCD driver
void lcdSetInitalFrameBuffer(void* fbAddress);
void lcdInit();
void lcdCopy(void * dest, void * src);
void lcdOff();
void lcdOn();
#define lcdRefreshWait(...)
// Backlight driver
#define BACKLIGHT_LEVEL_MAX 100
#define BACKLIGHT_FORCED_ON BACKLIGHT_LEVEL_MAX + 1
#define BACKLIGHT_LEVEL_MIN 1
extern bool boardBacklightOn;
void backlightLowInit( void );
void backlightInit();
void backlightEnable(uint8_t dutyCycle);
void backlightFullOn();
bool isBacklightEnabled();
#define BACKLIGHT_ENABLE() \
{ \
boardBacklightOn = true; \
backlightEnable(BACKLIGHT_LEVEL_MAX - currentBacklightBright); \
}
#define BACKLIGHT_DISABLE() \
{ \
boardBacklightOn = false; \
backlightEnable(((g_eeGeneral.blOffBright == BACKLIGHT_LEVEL_MIN) && \
(g_eeGeneral.backlightMode != e_backlight_mode_off)) \
? 0 \
: g_eeGeneral.blOffBright); \
}
#define USB_NAME "TX15"
#define USB_MANUFACTURER 'R', 'M', ' ', ' ', ' ', ' ', ' ', ' ' /* 8 bytes */
#define USB_PRODUCT 'T', 'X', '1', '5', ' ', ' ', ' ', ' ' /* 8 Bytes */
#if defined(__cplusplus) && !defined(SIMU)
}
#endif
int audioInit();
void audioConsumeCurrentBuffer();
// Telemetry driver
#define INTMODULE_FIFO_SIZE 512
#define TELEMETRY_FIFO_SIZE 512
// Haptic driver
void hapticInit();
void hapticDone();
void hapticOff();
void hapticOn(uint32_t pwmPercent);
// Second serial port driver
//#define AUX_SERIAL
#define DEBUG_BAUDRATE 115200
#define LUA_DEFAULT_BAUDRATE 115200
extern uint8_t currentTrainerMode;
void checkTrainerSettings();
// Touch panel driver
bool touchPanelEventOccured();
struct TouchState touchPanelRead();
struct TouchState getInternalTouchState();
// USB Charger
#if defined(USB_CHARGER)
void usbChargerInit();
bool usbChargerLed();
#endif
#endif // _BOARD_H_
+219
View File
@@ -0,0 +1,219 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "bsp_io.h"
#include "stm32_ws2812.h"
#include "stm32_switch_driver.h"
#include "stm32_i2c_driver.h"
#include "hal/switch_driver.h"
#include "drivers/pca95xx.h"
#include "timers_driver.h"
#include "delays_driver.h"
#include "hal.h"
#if !defined(BOOT)
#include "os/async.h"
#include "os/timer.h"
#endif
#include "debug.h"
extern const stm32_switch_t* boardGetSwitchDef(uint8_t idx);
struct bsp_io_expander {
pca95xx_t exp;
uint32_t mask;
uint32_t state;
};
static volatile bool _poll_switches_in_queue = false;
static bsp_io_expander _io_switches;
static bsp_io_expander _io_fs_switches;
#if !defined(BOOT)
static timer_handle_t _poll_timer = TIMER_INITIALIZER;
#endif
static void _init_io_expander(bsp_io_expander* io, uint32_t mask)
{
io->mask = mask;
io->state = 0;
}
static volatile uint8_t pca95xx_errors = 0;
static uint32_t _read_io_expander(bsp_io_expander* io)
{
uint16_t value = 0;
if (pca95xx_read(&io->exp, io->mask, &value) == 0) {
io->state = value;
} else {
if (pca95xx_errors++ > 5) {
gpio_clear(IO_RESET_GPIO);
pca95xx_errors = 0;
delay_us(1); // Only 6ns are needed according to PCA datasheet, but lets be safe
gpio_set(IO_RESET_GPIO);
}
}
return io->state;
}
#if !defined(BOOT)
typedef enum {
TRIGGERED_BY_TIMER = 0,
TRIGGERED_BY_IRQ,
} trigger_source_t;
static void _poll_switches(void *param1, uint32_t trigger_source)
{
if (trigger_source == TRIGGERED_BY_IRQ) {
_poll_switches_in_queue = false;
timer_reset(&_poll_timer);
}
_read_io_expander(&_io_switches);
_read_io_expander(&_io_fs_switches);
}
static void _io_int_handler()
{
async_call_isr(_poll_switches, &_poll_switches_in_queue, nullptr,
TRIGGERED_BY_IRQ);
}
static void _poll_cb(timer_handle_t* timer)
{
(void)timer;
_poll_switches(nullptr, TRIGGERED_BY_TIMER);
}
static void start_poll_timer()
{
timer_create(&_poll_timer, _poll_cb, "portex", 100, true);
timer_start(&_poll_timer);
}
#endif
int bsp_io_init()
{
int i2cError = i2c_init(I2C_Bus_1);
if (i2cError < 0) {
TRACE("I2C INIT ERROR: %d", i2cError);
return -1;
}
// setup expanders reset pin
gpio_init(IO_RESET_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW);
gpio_clear(IO_RESET_GPIO);
gpio_set(IO_RESET_GPIO);
// configure expander 1
_init_io_expander(&_io_fs_switches, 0xFF3F);
if (pca95xx_init(&_io_fs_switches.exp, I2C_Bus_1, 0x74) < 0) {
TRACE("EXP1 INIT ERROR");
return -1;
}
// configure expander 2
_init_io_expander(&_io_switches, 0xFFF8);
if (pca95xx_init(&_io_switches.exp, I2C_Bus_1, 0x75) < 0) {
TRACE("EXP2 INIT ERROR");
return -1;
}
#if !defined(BOOT)
// setup expanders pin change interrupt
gpio_init_int(IO_INT_GPIO, GPIO_IN, GPIO_FALLING, _io_int_handler);
#endif
_read_io_expander(&_io_switches);
_read_io_expander(&_io_fs_switches);
#if !defined(BOOT)
start_poll_timer();
#endif
return 0;
}
uint32_t bsp_get_fs_switches()
{
return _io_fs_switches.state;
}
void boardInitSwitches()
{
bsp_io_init();
}
static SwitchHwPos _get_switch_pos(uint8_t idx)
{
SwitchHwPos pos = SWITCH_HW_UP;
const stm32_switch_t* def = boardGetSwitchDef(idx);
uint32_t state = _io_switches.state;
if (def->isCustomSwitch) {
if ((state & def->Pin_high) == 0) {
return SWITCH_HW_DOWN;
} else {
return SWITCH_HW_UP;
}
}
else if (!def->Pin_low) {
// 2POS switch
if ((state & def->Pin_high) == 0) {
pos = SWITCH_HW_DOWN;
}
} else {
bool hi = state & def->Pin_high;
bool lo = state & def->Pin_low;
if (hi && lo) {
pos = SWITCH_HW_MID;
} else if (!hi && lo) {
pos = SWITCH_HW_DOWN;
}
}
return pos;
}
static SwitchHwPos _get_fs_switch_pos(uint8_t idx)
{
const stm32_switch_t* def = boardGetSwitchDef(idx);
uint32_t state = _io_fs_switches.state;
if ((state & def->Pin_high) == 0) {
return SWITCH_HW_DOWN;
} else {
return SWITCH_HW_UP;
}
}
SwitchHwPos boardSwitchGetPosition(uint8_t idx)
{
if (idx < 6)
return _get_switch_pos(idx);
return _get_fs_switch_pos(idx);
}
+69
View File
@@ -0,0 +1,69 @@
/*
* Copyright (C) EdgeTx
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#pragma once
#include "drivers/pca95xx.h"
#include "hal/switch_driver.h"
// Port expander 1 (0x74)
#define SWITCH_A_L PCA95XX_P14
#define SWITCH_A_H PCA95XX_P15
#define SWITCH_B_L PCA95XX_P12
#define SWITCH_B_H PCA95XX_P13
#define SWITCH_C_L PCA95XX_P10
#define SWITCH_C_H PCA95XX_P11
#define SWITCH_D_L PCA95XX_P6
#define SWITCH_D_H PCA95XX_P7
#define SWITCH_E_L PCA95XX_P16
#define SWITCH_E_H PCA95XX_P17
#define SWITCH_F_H PCA95XX_P4
#define SWITCH_F_L PCA95XX_P5
// Port expander 2 (0x75)
#define BSP_TR1U PCA95XX_PIN_13
#define BSP_TR1D PCA95XX_PIN_12
#define BSP_TR2U PCA95XX_PIN_11
#define BSP_TR2D PCA95XX_PIN_10
#define BSP_TR3L PCA95XX_PIN_15
#define BSP_TR3R PCA95XX_PIN_14
#define BSP_TR4L PCA95XX_PIN_9
#define BSP_TR4R PCA95XX_PIN_8
#define FSSWITCH_1 PCA95XX_P0
#define FSSWITCH_2 PCA95XX_P1
#define FSSWITCH_3 PCA95XX_P2
#define FSSWITCH_4 PCA95XX_P3
#define FSSWITCH_5 PCA95XX_P4
#define FSSWITCH_6 PCA95XX_P5
extern uint8_t isSwitch3Pos(uint8_t idx);
int bsp_io_init();
uint32_t bsp_io_read_switches();
uint32_t bsp_io_read_fs_switches();
uint32_t bsp_get_fs_switches();
uint16_t bsp_input_get();
struct stm32_switch_t;
+154
View File
@@ -0,0 +1,154 @@
#include "extflash_driver.h"
#include "stm32_hal.h"
#include "stm32_qspi.h"
#include "board.h"
#define QSPI_NOR_PAGE_SIZE 256
int32_t ExtFLASH_Init()
{
if (stm32_qspi_nor_init() != 0) {
return -1;
}
return stm32_qspi_nor_memory_mapped();
}
void ExtFLASH_InitRuntime() { stm32_qspi_no_init_runtime(); }
//
// ETX HAL flash interface
//
static uint32_t extflash_get_size_kb()
{
return QSPI_FLASH_SIZE / 1024;
}
static uint32_t extflash_get_sector(uint32_t address)
{
address -= QSPI_BASE;
return address / (64 * 1024);
}
static uint32_t extflash_get_sector_size(uint32_t sector)
{
(void)sector;
return (64 * 1024);
}
static int extflash_erase_sector(uint32_t address)
{
address -= QSPI_BASE;
return stm32_qspi_nor_erase_sector(address);
}
static int extflash_program(uint32_t address, void* data, uint32_t len)
{
address -= QSPI_BASE;
int ret = 0;
while (len > 0) {
uint32_t size = (len > QSPI_NOR_PAGE_SIZE) ? QSPI_NOR_PAGE_SIZE : len;
ret = stm32_qspi_nor_program(address, data, size);
if (ret != 0) break;
len -= size;
address += size;
data = (uint8_t*)data + size;
}
return ret;
}
static int extflash_read(uint32_t address, void* data, uint32_t len)
{
address -= QSPI_BASE;
return stm32_qspi_nor_read(address, data, len);
}
const etx_flash_driver_t extflash_driver = {
.get_size_kb = extflash_get_size_kb,
.get_sector = extflash_get_sector,
.get_sector_size = extflash_get_sector_size,
.erase_sector = extflash_erase_sector,
.program = extflash_program,
.read = extflash_read,
};
#if defined(BOOT)
//
// USB DFU interface
//
#include "usbd_dfu.h"
#define MEDIA_DESC_STR "@External Flash /0x90000000/128*064Kg"
static uint16_t extflash_dfu_init()
{
return USBD_OK;
}
static uint16_t extflash_dfu_deinit()
{
return USBD_OK;
}
static uint16_t extflash_dfu_erase(uint32_t address)
{
if (extflash_erase_sector(address) < 0) {
return USBD_FAIL;
}
return USBD_OK;
}
static uint16_t extflash_dfu_write(uint8_t* src, uint8_t* dest, uint32_t len)
{
if (extflash_program((intptr_t)dest, (void*)src, len) < 0) {
return USBD_FAIL;
}
return USBD_OK;
}
static uint8_t* extflash_dfu_read(uint8_t* src, uint8_t* dest, uint32_t len)
{
if (extflash_read((intptr_t)src, (void*)dest, len) < 0) {
return nullptr;
}
return dest;
}
static uint16_t extflash_dfu_get_status(uint32_t address, uint8_t cmd, uint8_t *buffer)
{
switch (cmd) {
case DFU_MEDIA_PROGRAM:
buffer[1] = 1;
buffer[2] = 0;
buffer[3] = 0;
break;
case DFU_MEDIA_ERASE:
default:
buffer[1] = 20;
buffer[2] = 0;
buffer[3] = 0;
break;
}
return USBD_OK;
}
const USBD_DFU_MediaTypeDef _extflash_dfu_media = {
.pStrDesc = (uint8_t*)MEDIA_DESC_STR,
.Init = extflash_dfu_init,
.DeInit = extflash_dfu_deinit,
.Erase = extflash_dfu_erase,
.Write = extflash_dfu_write,
.Read = extflash_dfu_read,
.GetStatus = extflash_dfu_get_status,
};
const void* extflash_dfu_media = &_extflash_dfu_media;
#endif // BOOT
+33
View File
@@ -0,0 +1,33 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#pragma once
#include "hal/flash_driver.h"
extern const etx_flash_driver_t extflash_driver;
extern const void* extflash_dfu_media;
// init external FLASH hardware
int32_t ExtFLASH_Init();
// init only runtime structures
void ExtFLASH_InitRuntime();
+593
View File
@@ -0,0 +1,593 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/*
STM32H750
SDMMC uses own DMA controler
DMA1
Stream0: LED_STRIP_TIMER_DMA_STREAM
Stream1: INTMODULE_DMA_STREAM
Stream2: FLYSKY_HALL_DMA_Stream_RX
Stream3: TELEMETRY_DMA_Stream_RX
Stream4: I2S_DMA_Stream
Stream5: INTMODULE_RX_DMA_STREAM
Stream6: AUX2_SERIAL_DMA_RX_STREAM
Stream7: TELEMETRY_DMA_Stream_TX
DMA2
Stream0: ADC_EXT_DMA_STREAM (do not move)
Stream1: AUX_SERIAL_DMA_TX_STREAM
Stream2: AUX_SERIAL_DMA_RX_STREAM
Stream3: EXTMODULE_TIMER_DMA_STREAM
Stream4: ADC_DMA_STREAM (do not move)
Stream5: EXTMODULE_USART_RX_DMA_STREAM
Stream6: EXTMODULE_USART_TX_DMA_STREAM
Stream7: AUX2_SERIAL_DMA_TX_STREAM
TIM1: BACKLIGHT_TIMER
TIM2: LED_STRIP_TIMER
TIM3: HAPTIC_GPIO_TIMER
TIM4:
TIM5: EXTMODULE_TIMER
TIM7:
TIM8: TRAINER_TIMER
TIM12: MIXER_SCHEDULER_TIMER
TIM14: MS_TIMER
TIM15: PDM
TIM16:
TIM17: ROTARY_ENCODER_TIMER
*/
#ifndef _HAL_H_
#define _HAL_H_
#define CPU_FREQ 480000000
#define PERI1_FREQUENCY 120000000
#define PERI2_FREQUENCY 120000000
#define TIMER_MULT_APB1 2
#define TIMER_MULT_APB2 2
// Keys
#define KEYS_GPIO_REG_PAGEDN GPIOA
#define KEYS_GPIO_PIN_PAGEDN LL_GPIO_PIN_8 // PA.08
#define KEYS_GPIO_REG_PAGEUP GPIOG
#define KEYS_GPIO_PIN_PAGEUP LL_GPIO_PIN_7 // PG.07
#define KEYS_GPIO_REG_SYS GPIOB
#define KEYS_GPIO_PIN_SYS LL_GPIO_PIN_2 // PB.02
#define KEYS_GPIO_REG_ENTER GPIOG
#define KEYS_GPIO_PIN_ENTER LL_GPIO_PIN_12 // PG.12
#define KEYS_GPIO_REG_MDL GPIOE
#define KEYS_GPIO_PIN_MDL LL_GPIO_PIN_3 // PE.03
#define KEYS_GPIO_REG_EXIT GPIOG
#define KEYS_GPIO_PIN_EXIT LL_GPIO_PIN_3 // PG.03
#define KEYS_GPIO_REG_TELE GPIOG
#define KEYS_GPIO_PIN_TELE LL_GPIO_PIN_2 // PG.02
// Trims
#define TRIMS_GPIO_REG_LHL
#define TRIMS_GPIO_PIN_LHL
#define TRIMS_GPIO_REG_LHR
#define TRIMS_GPIO_PIN_LHR
#define TRIMS_GPIO_REG_LVD
#define TRIMS_GPIO_PIN_LVD
#define TRIMS_GPIO_REG_LVU
#define TRIMS_GPIO_PIN_LVU
#define TRIMS_GPIO_REG_RHL
#define TRIMS_GPIO_PIN_RHL
#define TRIMS_GPIO_REG_RHR
#define TRIMS_GPIO_PIN_RHR
#define TRIMS_GPIO_REG_RVD
#define TRIMS_GPIO_PIN_RVD
#define TRIMS_GPIO_REG_RVU
#define TRIMS_GPIO_PIN_RVU
// function switches
//SW1
#define SWITCHES_GPIO_REG_G
#define SWITCHES_GPIO_PIN_G PCA95XX_P0
#define SWITCHES_G_CFS_IDX 0
#define FUNCTION_SWITCH_1 SG
//SW2
#define SWITCHES_GPIO_REG_H
#define SWITCHES_GPIO_PIN_H PCA95XX_P1
#define SWITCHES_H_CFS_IDX 1
#define FUNCTION_SWITCH_2 SH
//SW3
#define SWITCHES_GPIO_REG_I
#define SWITCHES_GPIO_PIN_I PCA95XX_P2
#define SWITCHES_I_CFS_IDX 2
#define FUNCTION_SWITCH_3 SI
//SW4
#define SWITCHES_GPIO_REG_J
#define SWITCHES_GPIO_PIN_J PCA95XX_P3
#define SWITCHES_J_CFS_IDX 3
#define FUNCTION_SWITCH_4 SJ
//SW5
#define SWITCHES_GPIO_REG_K
#define SWITCHES_GPIO_PIN_K PCA95XX_P4
#define SWITCHES_K_CFS_IDX 4
#define FUNCTION_SWITCH_5 SK
//SW6
#define SWITCHES_GPIO_REG_L
#define SWITCHES_GPIO_PIN_L PCA95XX_P5
#define SWITCHES_L_CFS_IDX 5
#define FUNCTION_SWITCH_6 SL
// Extender Switches
#define SWITCHES_A_3POS
#define SWITCHES_GPIO_REG_A_H
#define SWITCHES_GPIO_PIN_A_H PCA95XX_P15
#define SWITCHES_GPIO_REG_A_L
#define SWITCHES_GPIO_PIN_A_L PCA95XX_P14
#define SWITCHES_B_3POS
#define SWITCHES_GPIO_REG_B_H
#define SWITCHES_GPIO_PIN_B_H PCA95XX_P13
#define SWITCHES_GPIO_REG_B_L
#define SWITCHES_GPIO_PIN_B_L PCA95XX_P12
#define SWITCHES_C_3POS
#define SWITCHES_GPIO_REG_C_H
#define SWITCHES_GPIO_PIN_C_H PCA95XX_P11
#define SWITCHES_GPIO_REG_C_L
#define SWITCHES_GPIO_PIN_C_L PCA95XX_P10
#define SWITCHES_D_3POS
#define SWITCHES_GPIO_REG_D_H
#define SWITCHES_GPIO_PIN_D_H PCA95XX_P7
#define SWITCHES_GPIO_REG_D_L
#define SWITCHES_GPIO_PIN_D_L PCA95XX_P6
#define SWITCHES_E_2POS
#define SWITCHES_GPIO_REG_E
#define SWITCHES_GPIO_PIN_E PCA95XX_P16
#define SWITCHES_F_2POS
#define SWITCHES_GPIO_REG_F
#define SWITCHES_GPIO_PIN_F PCA95XX_P4
// Expanders
#define IO_INT_GPIO GPIO_PIN(GPIOD, 3)
#define IO_RESET_GPIO GPIO_PIN(GPIOG, 10)
#if !defined(USE_EXTI3_IRQ)
#define USE_EXTI3_IRQ
#define EXTI3_IRQ_Priority 9
#endif
// ADC
#define ADC_GPIO_PIN_STICK_LH LL_GPIO_PIN_6 // PA.06
#define ADC_GPIO_PIN_STICK_LV LL_GPIO_PIN_3 // PC.03
#define ADC_GPIO_PIN_STICK_RV LL_GPIO_PIN_4 // PC.04
#define ADC_GPIO_PIN_STICK_RH LL_GPIO_PIN_5 // PC.05
#define ADC_GPIO_PIN_POT1 LL_GPIO_PIN_1 // PC.01 POT1
#define ADC_GPIO_PIN_POT2 LL_GPIO_PIN_1 // PB.01 POT2
#define ADC_GPIO_PIN_BATT LL_GPIO_PIN_3 // PH.03
#define ADC_GPIOA_PINS (ADC_GPIO_PIN_STICK_LH)
#define ADC_GPIOB_PINS (ADC_GPIO_PIN_POT2)
#define ADC_GPIOC_PINS (ADC_GPIO_PIN_STICK_RV | ADC_GPIO_PIN_STICK_LV | ADC_GPIO_PIN_STICK_RH | ADC_GPIO_PIN_POT1)
#define ADC_GPIOH_PINS (ADC_GPIO_PIN_BATT)
#define ADC_CHANNEL_STICK_LH LL_ADC_CHANNEL_3 // ADC12_INP3
#define ADC_CHANNEL_STICK_LV LL_ADC_CHANNEL_13 // ADC12_INP13
#define ADC_CHANNEL_STICK_RV LL_ADC_CHANNEL_4 // ADC12_INP4
#define ADC_CHANNEL_STICK_RH LL_ADC_CHANNEL_8 // ADC12_INP8
// Each ADC cannot map more than 8 channels, otherwise it will cause problems
#define ADC_CHANNEL_POT1 LL_ADC_CHANNEL_11 // ADC12_INP11
#define ADC_CHANNEL_POT2 LL_ADC_CHANNEL_5 // ADC12_INP5
#define ADC_CHANNEL_BATT LL_ADC_CHANNEL_14 // ADC3_INP14
#define ADC_CHANNEL_RTC_BAT LL_ADC_CHANNEL_VBAT // ADC3_INP17
#define ADC_MAIN ADC1
#define ADC_DMA DMA2
#define ADC_DMA_CHANNEL LL_DMAMUX1_REQ_ADC1
#define ADC_DMA_STREAM LL_DMA_STREAM_4
#define ADC_DMA_STREAM_IRQ DMA2_Stream4_IRQn
#define ADC_DMA_STREAM_IRQHandler DMA2_Stream4_IRQHandler
#define ADC_SAMPTIME LL_ADC_SAMPLINGTIME_8CYCLES_5
#define ADC_EXT ADC3
#define ADC_EXT_CHANNELS { ADC_CHANNEL_BATT , ADC_CHANNEL_RTC_BAT }
#define ADC_EXT_DMA DMA2
#define ADC_EXT_DMA_CHANNEL LL_DMAMUX1_REQ_ADC3
#define ADC_EXT_DMA_STREAM LL_DMA_STREAM_0
#define ADC_EXT_DMA_STREAM_IRQ DMA2_Stream0_IRQn
#define ADC_EXT_DMA_STREAM_IRQHandler DMA2_Stream0_IRQHandler
#define ADC_EXT_SAMPTIME LL_ADC_SAMPLINGTIME_64CYCLES_5 // No hardware oversampling on ADC3
#define ADC_VREF_PREC2 330
#define ADC_DIRECTION { \
0,-1,0,-1, /* gimbals */ \
-1,-1, /* pots */ \
0,0, /* sliders */ \
0, /* vbat */ \
0, /* rtc_bat */ \
0, /* SWA */ \
0, /* SWB */ \
0, /* SWC */ \
0, /* SWD */ \
0, /* SWE */ \
0 /* SWF */ \
}
// Serial gimbal sync port
#define HALL_SYNC GPIO_PIN(GPIOH, 11)
#define USE_EXTI9_5_IRQ // used for I2C port extender interrupt
#define EXTI9_5_IRQ_Priority 5
// Power
#define PWR_SWITCH_GPIO GPIO_PIN(GPIOA, 4)
#define PWR_ON_GPIO GPIO_PIN(GPIOH, 12)
// Chargers (USB and wireless)
#define UCHARGER_GPIO GPIO_PIN(GPIOD, 11)
#define UCHARGER_EN_GPIO GPIO_PIN(GPIOB, 12)
// TODO! Check IOLL1 to PI.01 connectivity!
// S.Port update connector
#define HAS_SPORT_UPDATE_CONNECTOR() (false)
// Telemetry
#define TELEMETRY_SET_INPUT 0
#define TELEMETRY_TX_GPIO GPIO_PIN(GPIOA, 9)
#define TELEMETRY_RX_GPIO GPIO_UNDEF
#define TELEMETRY_USART USART1
#define TELEMETRY_USART_IRQn USART1_IRQn
#define TELEMETRY_DMA DMA1
#define TELEMETRY_DMA_Stream_TX LL_DMA_STREAM_7
#define TELEMETRY_DMA_Channel_TX LL_DMAMUX1_REQ_USART1_TX
#define TELEMETRY_DMA_TX_Stream_IRQ DMA1_Stream7_IRQn
#define TELEMETRY_DMA_TX_IRQHandler DMA1_Stream7_IRQHandler
#define TELEMETRY_DMA_Stream_RX LL_DMA_STREAM_3
#define TELEMETRY_DMA_Channel_RX LL_DMAMUX1_REQ_USART1_RX
#define TELEMETRY_USART_IRQHandler USART1_IRQHandler
// Software IRQ (Prio 5 -> FreeRTOS compatible)
#define TELEMETRY_USE_CUSTOM_EXTI
#define CUSTOM_EXTI_IRQ_NAME ETH_WKUP_IRQ
#define ETH_WKUP_IRQ_Priority 5
#define CUSTOM_EXTI_IRQ_LINE 86
#define TELEMETRY_RX_FRAME_EXTI_LINE CUSTOM_EXTI_IRQ_LINE
// USB
#define USB_GPIO GPIOA
#define USB_GPIO_VBUS GPIO_PIN(GPIOH, 5)
#define USB_GPIO_DM GPIO_PIN(GPIOA, 11)
#define USB_GPIO_DP GPIO_PIN(GPIOA, 12)
#define USB_GPIO_AF GPIO_AF10
// LCD
#define LCD_SPI_CS_GPIO GPIOA
#define LCD_SPI_CS_GPIO_PIN LL_GPIO_PIN_7
#define LCD_SPI_SCK_GPIO GPIOB
#define LCD_SPI_SCK_GPIO_PIN LL_GPIO_PIN_0
#define LCD_SPI_MOSI_GPIO GPIOI
#define LCD_SPI_MOSI_GPIO_PIN LL_GPIO_PIN_9
#define LTDC_IRQ_PRIO 4
#define DMA_SCREEN_IRQ_PRIO 6
#define LCD_RESET_GPIO GPIOJ
#define LCD_RESET_GPIO_PIN LL_GPIO_PIN_12
#define LCD_TE_GPIO GPIOI
#define LCD_TE_GPIO_PIN LL_GPIO_PIN_4
// Backlight
#define BACKLIGHT_GPIO GPIO_PIN(GPIOA, 10) // TIM1_CH3
#define BACKLIGHT_TIMER TIM1
#define BACKLIGHT_TIMER_CHANNEL LL_TIM_CHANNEL_CH3
#define BACKLIGHT_GPIO_AF GPIO_AF1
#define BACKLIGHT_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1)
// QSPI Flash
#define QSPI_CLK_GPIO GPIO_PIN(GPIOF, 10)
#define QSPI_CLK_GPIO_AF GPIO_AF9
#define QSPI_CS_GPIO GPIO_PIN(GPIOG, 6)
#define QSPI_CS_GPIO_AF GPIO_AF10
#define QSPI_MISO_GPIO GPIO_PIN(GPIOF, 9)
#define QSPI_MISO_GPIO_AF GPIO_AF10
#define QSPI_MOSI_GPIO GPIO_PIN(GPIOF, 8)
#define QSPI_MOSI_GPIO_AF GPIO_AF10
#define QSPI_WP_GPIO GPIO_PIN(GPIOF, 7)
#define QSPI_WP_GPIO_AF GPIO_AF9
#define QSPI_HOLD_GPIO GPIO_PIN(GPIOF, 6)
#define QSPI_HOLD_GPIO_AF GPIO_AF9
#define QSPI_FLASH_SIZE 0x1000000
// SD
#define SD_SDIO SDMMC1
#define SD_SDIO_CLK_DIV(fq) (HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SDMMC) / (2 * fq))
#define SD_SDIO_TRANSFER_CLK_DIV SD_SDIO_CLK_DIV(24000000) // Hz
#define SD2_PRESENT_GPIO GPIO_PIN(GPIOH, 8) // PH.08
#define SD2_SDIO SDMMC2
#define SD2_SDIO_PIN_D0 GPIO_PIN(GPIOB, 14)
#define SD2_SDIO_AF_D0 GPIO_AF9
#define SD2_SDIO_PIN_D1 GPIO_PIN(GPIOB, 15)
#define SD2_SDIO_AF_D1 GPIO_AF9
#define SD2_SDIO_PIN_D2 GPIO_PIN(GPIOG, 11)
#define SD2_SDIO_AF_D2 GPIO_AF10
#define SD2_SDIO_PIN_D3 GPIO_PIN(GPIOB, 4)
#define SD2_SDIO_AF_D3 GPIO_AF9
#define SD2_SDIO_PIN_CLK GPIO_PIN(GPIOD, 6)
#define SD2_SDIO_AF_CLK GPIO_AF11
#define SD2_SDIO_PIN_CMD GPIO_PIN(GPIOD, 7)
#define SD2_SDIO_AF_CMD GPIO_AF11
#define SD2_SDIO_TRANSFER_CLK_DIV SD_SDIO_CLK_DIV(24000000) // Hz
#define STORAGE_USE_SDIO
// AUDIO
#define AUDIO_SPI SPI2
#define AUDIO_RESET_PIN GPIO_PIN(GPIOH, 10)
#define AUDIO_HP_DETECT_PIN GPIO_PIN(GPIOA, 5)
#define I2S_DMA DMA1
#define I2S_DMA_Stream LL_DMA_STREAM_4
#define I2S_DMA_Stream_Request LL_DMAMUX1_REQ_SPI2_TX
#define I2S_DMA_Stream_IRQn DMA1_Stream4_IRQn
#define I2S_DMA_Stream_IRQHandler DMA1_Stream4_IRQHandler
// I2C Bus
#define I2C_B1 I2C4
#define I2C_B1_SDA_GPIO GPIO_PIN(GPIOD, 13) // PD.13
#define I2C_B1_SCL_GPIO GPIO_PIN(GPIOD, 12) // PD.12
#define I2C_B1_GPIO_AF LL_GPIO_AF_4
#define I2C_B1_CLK_RATE 400000
// Haptic: TIM3_CH2
#define HAPTIC_PWM
#define HAPTIC_GPIO GPIO_PIN(GPIOC, 7)
#define HAPTIC_GPIO_TIMER TIM3
#define HAPTIC_GPIO_AF GPIO_AF2
#define HAPTIC_TIMER_OUTPUT_ENABLE TIM_CCER_CC2E | TIM_CCER_CC2NE;
#define HAPTIC_TIMER_MODE TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2PE
#define HAPTIC_TIMER_COMPARE_VALUE HAPTIC_GPIO_TIMER->CCR2
// Flysky Hall Stick
#define FLYSKY_HALL_SERIAL_USART UART4
#define FLYSKY_HALL_SERIAL_TX_GPIO GPIO_PIN(GPIOB, 9)
#define FLYSKY_HALL_SERIAL_RX_GPIO GPIO_PIN(GPIOB, 8)
#define FLYSKY_HALL_SERIAL_USART_IRQn UART4_IRQn
#define FLYSKY_HALL_SERIAL_DMA DMA1
#define FLYSKY_HALL_DMA_Stream_RX LL_DMA_STREAM_2
#define FLYSKY_HALL_DMA_Channel LL_DMAMUX1_REQ_UART4_RX
// LED Strip
#define LED_STRIP_LENGTH 26 // 6POS + 2 rings of 10
#define BLING_LED_STRIP_START 6
#define BLING_LED_STRIP_LENGTH 20
#define CFS_LED_STRIP_START 0
#define CFS_LED_STRIP_LENGTH 6
#define CFS_LEDS_PER_SWITCH 1
#define LED_STRIP_GPIO GPIO_PIN(GPIOA, 0) // PA.00 / TIM2_CH1
#define LED_STRIP_GPIO_AF LL_GPIO_AF_1 // TIM1/2/16/17
#define LED_STRIP_TIMER TIM2
#define LED_STRIP_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1)
#define LED_STRIP_TIMER_CHANNEL LL_TIM_CHANNEL_CH1
#define LED_STRIP_TIMER_DMA DMA1
#define LED_STRIP_TIMER_DMA_CHANNEL LL_DMAMUX1_REQ_TIM2_UP
#define LED_STRIP_TIMER_DMA_STREAM LL_DMA_STREAM_0
#define LED_STRIP_TIMER_DMA_IRQn DMA1_Stream0_IRQn
#define LED_STRIP_TIMER_DMA_IRQHandler DMA1_Stream0_IRQHandler
#define LED_STRIP_REFRESH_PERIOD 50 //ms
#define STATUS_LEDS
#define GPIO_LED_GPIO_ON gpio_clear
#define GPIO_LED_GPIO_OFF gpio_set
#define LED_RED_GPIO GPIO_PIN(GPIOI, 8) // PI.08
#define LED_GREEN_GPIO GPIO_PIN(GPIOI, 11) // PI.11
#define LED_BLUE_GPIO GPIO_PIN(GPIOI, 10) // PI.10
// Internal Module
#define INTMODULE_PWR_GPIO GPIO_PIN(GPIOB, 13) // PB.13
#define INTMODULE_BOOTCMD_GPIO GPIO_PIN(GPIOH, 9) // PH.09
#define INTMODULE_BOOTCMD_DEFAULT 0
#define INTMODULE_TX_GPIO GPIO_PIN(GPIOG, 14)
#define INTMODULE_RX_GPIO GPIO_PIN(GPIOG, 9)
#define INTMODULE_USART USART6
#define INTMODULE_GPIO_AF LL_GPIO_AF_7
#define INTMODULE_USART_IRQn USART6_IRQn
#define INTMODULE_USART_IRQHandler USART6_IRQHandler
#define INTMODULE_DMA DMA1
#define INTMODULE_DMA_STREAM LL_DMA_STREAM_1
#define INTMODULE_DMA_STREAM_IRQ DMA1_Stream1_IRQn
#define INTMODULE_DMA_FLAG_TC DMA_FLAG_TCIF1
#define INTMODULE_DMA_CHANNEL LL_DMAMUX1_REQ_USART6_TX
#define INTMODULE_RX_DMA DMA1
#define INTMODULE_RX_DMA_STREAM LL_DMA_STREAM_5
#define INTMODULE_RX_DMA_CHANNEL LL_DMAMUX1_REQ_USART6_RX
#define INTMODULE_RX_DMA_Stream_IRQn DMA1_Stream5_IRQn
#define INTMODULE_RX_DMA_Stream_IRQHandler DMA1_Stream5_IRQHandler
// External Module
#define EXTMODULE
#define EXTMODULE_PULSES
#define EXTMODULE_PWR_GPIO GPIO_PIN(GPIOD, 4) // PD.04
#define EXTMODULE_TX_GPIO GPIO_PIN(GPIOA, 2) // TIM2_CH3, TIM5_CH3,TIM15_CH1,
#define EXTMODULE_RX_GPIO GPIO_PIN(GPIOA, 3)
#define EXTMODULE_TX_GPIO_AF LL_GPIO_AF_3 // TIM5_CH3
#define EXTMODULE_TIMER TIM5
#define EXTMODULE_TIMER_32BITS
#define EXTMODULE_TIMER_Channel LL_TIM_CHANNEL_CH3
#define EXTMODULE_TIMER_IRQn TIM5_IRQn
#define EXTMODULE_TIMER_IRQHandler TIM5_IRQHandler
#define EXTMODULE_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2)
#define EXTMODULE_TIMER_TX_GPIO_AF LL_GPIO_AF_2
//USART
#define EXTMODULE_USART USART2
#define EXTMODULE_USART_TX_DMA DMA2
#define EXTMODULE_USART_TX_DMA_CHANNEL LL_DMAMUX1_REQ_USART2_TX
#define EXTMODULE_USART_TX_DMA_STREAM LL_DMA_STREAM_6
#define EXTMODULE_USART_RX_DMA_CHANNEL LL_DMAMUX1_REQ_USART2_RX
#define EXTMODULE_USART_RX_DMA_STREAM LL_DMA_STREAM_5
#define EXTMODULE_USART_IRQHandler USART2_IRQHandler
#define EXTMODULE_USART_IRQn USART2_IRQn
//TIMER
#define EXTMODULE_TIMER_DMA_CHANNEL LL_DMAMUX1_REQ_TIM5_UP
#define EXTMODULE_TIMER_DMA DMA2
#define EXTMODULE_TIMER_DMA_STREAM LL_DMA_STREAM_6
#define EXTMODULE_TIMER_DMA_STREAM_IRQn DMA2_Stream6_IRQn
#define EXTMODULE_TIMER_DMA_IRQHandler DMA2_Stream6_IRQHandler
// Trainer Port
#define TRAINER_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA)
#define TRAINER_IN_GPIO GPIO_PIN(GPIOI, 6)
#define TRAINER_IN_TIMER_Channel LL_TIM_CHANNEL_CH2
#define TRAINER_OUT_GPIO GPIO_PIN(GPIOI, 5)
#define TRAINER_OUT_TIMER_Channel LL_TIM_CHANNEL_CH1
#define TRAINER_TIMER TIM8
#define TRAINER_TIMER_IRQn TIM8_CC_IRQn
#define TRAINER_TIMER_IRQHandler TIM8_CC_IRQHandler
#define TRAINER_GPIO_AF LL_GPIO_AF_3
#define TRAINER_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2)
#define TRAINER_DETECT_GPIO GPIO_PIN(GPIOH, 4)
// AUX ports
#define AUX_SERIAL_TX_GPIO GPIO_PIN(GPIOB, 6) // PB.06
#define AUX_SERIAL_RX_GPIO GPIO_PIN(GPIOB, 5) // PB.05
#define AUX_SERIAL_USART UART5
#define AUX_SERIAL_USART_IRQHandler UART5_IRQHandler
#define AUX_SERIAL_USART_IRQn UART5_IRQn
#define AUX_SERIAL_DMA_TX DMA2
#define AUX_SERIAL_DMA_TX_STREAM LL_DMA_STREAM_1
#define AUX_SERIAL_DMA_TX_CHANNEL LL_DMAMUX1_REQ_UART5_TX
#define AUX_SERIAL_DMA_RX DMA2
#define AUX_SERIAL_DMA_RX_STREAM LL_DMA_STREAM_2
#define AUX_SERIAL_DMA_RX_CHANNEL LL_DMAMUX1_REQ_UART5_RX
#define AUX_SERIAL_PWR_GPIO GPIO_PIN(GPIOB, 7) // PB.07
#define AUX2_SERIAL_TX_GPIO GPIO_PIN(GPIOB, 10) // PB.10
#define AUX2_SERIAL_RX_GPIO GPIO_PIN(GPIOB, 11) // PB.11
#define AUX2_SERIAL_USART USART3
#define AUX2_SERIAL_USART_IRQHandler USART3_IRQHandler
#define AUX2_SERIAL_USART_IRQn USART3_IRQn
#define AUX2_SERIAL_DMA_TX DMA2
#define AUX2_SERIAL_DMA_TX_STREAM LL_DMA_STREAM_7
#define AUX2_SERIAL_DMA_TX_CHANNEL LL_DMAMUX1_REQ_USART3_TX
#define AUX2_SERIAL_DMA_RX DMA1
#define AUX2_SERIAL_DMA_RX_STREAM LL_DMA_STREAM_6
#define AUX2_SERIAL_DMA_RX_CHANNEL LL_DMAMUX1_REQ_USART3_RX
#define AUX2_SERIAL_PWR_GPIO GPIO_PIN(GPIOC, 13) // PC.13
// Touch
#define TOUCH_I2C_BUS I2C_Bus_1
#define TOUCH_INT_GPIO GPIO_PIN(GPIOE, 2) // PE.02
#define TOUCH_RST_GPIO GPIO_PIN(GPIOJ, 13) // PJ.13
// TOUCH_INT_EXTI IRQ
#if !defined(USE_EXTI2_IRQ)
#define USE_EXTI2_IRQ
#define EXTI2_IRQ_Priority 9
#endif
// IMU
#define IMU_I2C_BUS I2C_Bus_1
#define IMU_I2C_ADDRESS 0x6A
#define IMU_INT_GPIO GPIO_PIN(GPIOG, 13) // PG.13
// IMU_INT_EXTI IRQ
#if !defined(USE_EXTI15_10_IRQ)
#define USE_EXTI15_10_IRQ
#define EXTI15_10_IRQ_Priority 6
#endif
//ROTARY emulation for trims as buttons
#define ROTARY_ENCODER_NAVIGATION
// Rotary Encoder
#define ROTARY_ENCODER_INVERTED
#define ROTARY_ENCODER_GPIO_A GPIOI
#define ROTARY_ENCODER_GPIO_PIN_A LL_GPIO_PIN_7
#define ROTARY_ENCODER_GPIO_B GPIOJ
#define ROTARY_ENCODER_GPIO_PIN_B LL_GPIO_PIN_8
#define ROTARY_ENCODER_POSITION() (((ROTARY_ENCODER_GPIO_A->IDR >> 7) & 0x01)|((ROTARY_ENCODER_GPIO_B->IDR >> 7) & 0x02))
#define ROTARY_ENCODER_EXTI_LINE1 LL_EXTI_LINE_7
#define ROTARY_ENCODER_EXTI_LINE2 LL_EXTI_LINE_8
#if !defined(USE_EXTI7_IRQ)
#define USE_EXTI7_IRQ
#define EXTI7_IRQ_Priority 5
#endif
#if !defined(USE_EXTI8_IRQ)
#define USE_EXTI8_IRQ
#define EXTI8_IRQ_Priority 5
#endif
#define ROTARY_ENCODER_EXTI_PORT_A LL_SYSCFG_EXTI_PORTI
#define ROTARY_ENCODER_EXTI_PORT_B LL_SYSCFG_EXTI_PORTJ
#define ROTARY_ENCODER_EXTI_SYS_LINE1 LL_SYSCFG_EXTI_LINE7
#define ROTARY_ENCODER_EXTI_SYS_LINE2 LL_SYSCFG_EXTI_LINE8
#define ROTARY_ENCODER_TIMER TIM17
#define ROTARY_ENCODER_TIMER_IRQn TIM17_IRQn
#define ROTARY_ENCODER_TIMER_IRQHandler TIM17_IRQHandler
// Millisecond timer
#define MS_TIMER TIM14
#define MS_TIMER_IRQn TIM8_TRG_COM_TIM14_IRQn
#define MS_TIMER_IRQHandler TIM8_TRG_COM_TIM14_IRQHandler
// Mixer scheduler timer
#define MIXER_SCHEDULER_TIMER TIM12
#define MIXER_SCHEDULER_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1)
#define MIXER_SCHEDULER_TIMER_IRQn TIM8_BRK_TIM12_IRQn
#define MIXER_SCHEDULER_TIMER_IRQHandler TIM8_BRK_TIM12_IRQHandler
#define LANDSCAPE_LCD true
#define PORTRAIT_LCD false
#define LANDSCAPE_LCD_SML false
#define LANDSCAPE_LCD_STD true
#define LANDSCAPE_LCD_LRG false
#define LCD_W 480
#define LCD_H 320
#define LCD_PHYS_W LCD_H
#define LCD_PHYS_H LCD_W
#define LCD_DEPTH 16
#define LSE_DRIVE_STRENGTH RCC_LSEDRIVE_HIGH
#endif // _HAL_H_
+60
View File
@@ -0,0 +1,60 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "hal/gpio.h"
#include "stm32_gpio.h"
#include "stm32_timer.h"
#include "stm32_pulse_driver.h"
#include "board.h"
#define HAPTIC_TIMER_FREQ 200000000
static const stm32_pulse_timer_t _haptic_timer = {
.GPIO = (gpio_t)HAPTIC_GPIO,
.GPIO_Alternate = HAPTIC_GPIO_AF,
.TIMx = HAPTIC_GPIO_TIMER,
.TIM_Freq = HAPTIC_TIMER_FREQ,
.TIM_Channel = LL_TIM_CHANNEL_CH2,
.TIM_IRQn = (IRQn_Type)-1,
.DMAx = nullptr,
.DMA_Stream = 0,
.DMA_Channel = 0,
.DMA_IRQn = (IRQn_Type)-1,
.DMA_TC_CallbackPtr = nullptr,
};
void hapticInit(void)
{
stm32_pulse_init(&_haptic_timer, 10000);
stm32_pulse_config_output(&_haptic_timer, true, LL_TIM_OCMODE_PWM1, 0);
LL_TIM_SetAutoReload(_haptic_timer.TIMx, 100);
LL_TIM_EnableCounter(_haptic_timer.TIMx);
}
void hapticOn(uint32_t pwmPercent)
{
if (pwmPercent > 100) pwmPercent = 100;
stm32_pulse_set_cmp_val(&_haptic_timer, pwmPercent);
}
void hapticOff(void) { hapticOn(0); }
void hapticDone(void) { hapticOff(); }
+82
View File
@@ -0,0 +1,82 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "hal/key_driver.h"
#include "bsp_io.h"
#include "stm32_hal_ll.h"
#include "stm32_gpio_driver.h"
#include "stm32_i2c_driver.h"
#include "hal.h"
#include "delays_driver.h"
#include "keys.h"
#include "stm32_keys.inc"
#include "debug.h"
void keysInit() { _init_keys(); }
uint32_t readKeys() { return _read_keys(); }
/* The output bit-order has to be:
0 LHL TR3L (Left equals down)
1 LHR TR3R
2 LVD TR1D
3 LVU TR1U
4 RVD TR2D
5 RVU TR2U
6 RHL TR4L
7 RHR TR4R
*/
enum PhysicalTrims {
TR3L = 0,
TR3R,
TR1D = 2,
TR1U,
TR2D = 4,
TR2U,
TR4L = 6,
TR4R
};
uint32_t readTrims()
{
uint32_t result = 0;
uint32_t keys = bsp_get_fs_switches();
#define _TRIM(t) \
if ((keys & BSP_##t) == 0) result |= 1 << t;
_TRIM(TR1U);
_TRIM(TR1D);
_TRIM(TR3L);
_TRIM(TR3R);
_TRIM(TR2U);
_TRIM(TR2D);
_TRIM(TR4L);
_TRIM(TR4R);
#undef _TRIM
return result;
}
+538
View File
@@ -0,0 +1,538 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "stm32_hal_ll.h"
#include "stm32_hal.h"
#include "edgetx_types.h"
#include "dma2d.h"
#include "hal.h"
#include "delays_driver.h"
#include "debug.h"
#include "lcd.h"
#include "lcd_driver.h"
#include "board.h"
#include "hal/gpio.h"
#include "stm32_gpio.h"
#include "stm32_qspi.h"
uint8_t TouchControllerType = 0; // 0: other; 1: CST836U
static volatile uint16_t lcd_phys_w = LCD_PHYS_W;
static volatile uint16_t lcd_phys_h = LCD_PHYS_H;
static LTDC_HandleTypeDef hltdc;
static void* initialFrameBuffer = nullptr;
static volatile uint8_t _frame_addr_reloaded = 0;
static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer,
const rect_t &copy_area)
{
(void)disp_drv;
(void)copy_area;
// given the data cache size, this is probably
// faster than cleaning by address
SCB_CleanDCache();
LTDC_Layer1->CFBAR = (uint32_t)buffer;
// reload shadow registers on vertical blank
_frame_addr_reloaded = 0;
LTDC->SRCR = LTDC_SRCR_VBR;
__HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI);
// wait for reload
// TODO: replace through some smarter mechanism without busy wait
while(_frame_addr_reloaded == 0);
}
lcdSpiInitFucPtr lcdInitFunction;
lcdSpiInitFucPtr lcdOffFunction;
lcdSpiInitFucPtr lcdOnFunction;
uint32_t lcdPixelClock;
volatile uint8_t LCD_ReadBuffer[24] = { 0, 0 };
static void LCD_Delay(void) {
volatile unsigned int i;
for (i = 0; i < 20; i++) {
;
}
}
gpio_t _lcd_af_gpios[] = {
GPIO_PIN(GPIOI, 12), GPIO_PIN(GPIOI, 13), GPIO_PIN(GPIOI, 14),
GPIO_PIN(GPIOJ, 1), GPIO_PIN(GPIOJ, 2), GPIO_PIN(GPIOJ, 3),
GPIO_PIN(GPIOJ, 4), GPIO_PIN(GPIOJ, 5), GPIO_PIN(GPIOJ, 6),
GPIO_PIN(GPIOJ, 9), GPIO_PIN(GPIOJ, 10), GPIO_PIN(GPIOJ, 11),
GPIO_PIN(GPIOJ, 14), GPIO_PIN(GPIOJ, 15),
GPIO_PIN(GPIOK, 0), GPIO_PIN(GPIOK, 1), GPIO_PIN(GPIOK, 2),
GPIO_PIN(GPIOK, 3), GPIO_PIN(GPIOK, 4), GPIO_PIN(GPIOK, 5),
GPIO_PIN(GPIOK, 6), GPIO_PIN(GPIOK, 7),
};
static void LCD_AF_GPIOConfig(void)
{
for (unsigned i = 0; i < sizeof(_lcd_af_gpios) / sizeof(_lcd_af_gpios[0]); i++) {
gpio_init_af(_lcd_af_gpios[i], GPIO_AF14, GPIO_SPEED_FREQ_LOW);
}
}
static void lcdSpiConfig(void)
{
LL_GPIO_InitTypeDef GPIO_InitStructure;
LL_GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.Pin = LCD_SPI_MOSI_GPIO_PIN;
GPIO_InitStructure.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Mode = LL_GPIO_MODE_OUTPUT;
GPIO_InitStructure.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStructure.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(LCD_SPI_MOSI_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.Pin = LCD_SPI_SCK_GPIO_PIN;
LL_GPIO_Init(LCD_SPI_SCK_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.Pin = LCD_SPI_CS_GPIO_PIN;
LL_GPIO_Init(LCD_SPI_CS_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.Pin = LCD_RESET_GPIO_PIN;
LL_GPIO_Init(LCD_RESET_GPIO, &GPIO_InitStructure);
LCD_CS_HIGH();
}
void lcdDelay() {
delay_01us(1);
}
static void lcdReset() {
LCD_CS_HIGH();
LCD_NRST_HIGH();
delay_ms(1);
LCD_NRST_LOW(); // RESET();
delay_ms(10);
LCD_NRST_HIGH();
delay_ms(100);
}
unsigned char LCD_ReadByteOnFallingEdge(void) {
unsigned int i;
unsigned char ReceiveData = 0;
LCD_MOSI_HIGH();
LCD_MOSI_AS_INPUT();
for (i = 0; i < 8; i++) {
LCD_DELAY();
LCD_SCK_HIGH();
LCD_DELAY();
LCD_DELAY();
ReceiveData <<= 1;
LCD_SCK_LOW();
LCD_DELAY();
LCD_DELAY();
if (LCD_READ_DATA_PIN()) {
ReceiveData |= 0x01;
}
}
LCD_MOSI_AS_OUTPUT();
return (ReceiveData);
}
static void lcdWriteByte(uint8_t data_enable, uint8_t byte) {
LCD_SCK_LOW();
lcdDelay();
if (data_enable) {
LCD_MOSI_HIGH();
} else {
LCD_MOSI_LOW();
}
LCD_SCK_HIGH();
lcdDelay();
for (int i = 0; i < 8; i++) {
LCD_SCK_LOW();
lcdDelay();
if (byte & 0x80) {
LCD_MOSI_HIGH();
} else {
LCD_MOSI_LOW();
}
LCD_SCK_HIGH();
byte <<= 1;
lcdDelay();
}
LCD_SCK_LOW();
}
unsigned char LCD_ReadByte(void) {
unsigned int i;
unsigned char ReceiveData = 0;
LCD_MOSI_HIGH();
LCD_MOSI_AS_INPUT();
for (i = 0; i < 8; i++) {
LCD_SCK_LOW();
lcdDelay();
ReceiveData <<= 1;
LCD_SCK_HIGH();
lcdDelay();
if (LCD_READ_DATA_PIN()) {
ReceiveData |= 0x01;
}
}
LCD_SCK_LOW();
LCD_MOSI_AS_OUTPUT();
return (ReceiveData);
}
unsigned char LCD_ReadRegister(unsigned char Register) {
unsigned char ReadData = 0;
LCD_CS_LOW();
lcdDelay();
lcdWriteByte(0, Register);
lcdDelay();
lcdDelay();
ReadData = LCD_ReadByte();
LCD_CS_HIGH();
return (ReadData);
}
void lcdWriteCommand(uint8_t command) {
lcdWriteByte(0, command);
}
void lcdWriteData(uint8_t data) {
lcdWriteByte(1, data);
}
void LCD_ST7365_On(void) {
LCD_CS_LOW();
delay_ms(1);
lcdWriteCommand(0x29);
LCD_CS_HIGH();
}
void LCD_ST7365_Init(void) {
LCD_CS_LOW();
delay_ms(1);
lcdWriteCommand( 0x11 );
delay_ms(120);
lcdWriteCommand( 0xF0 );
lcdWriteData( 0xC3 );
lcdWriteCommand( 0xF0 );
lcdWriteData( 0x96 );
lcdWriteCommand(0x11);
delay_ms(120);
lcdWriteCommand(0xF0); // Command Set Control
lcdWriteData(0xC3);
lcdWriteCommand(0xF0);
lcdWriteData(0x96);
lcdWriteCommand(0x36); // Memory Data Access Control MY,MX~~
lcdWriteData(0xE8);
lcdWriteCommand(0x2A);//480-1
lcdWriteData(0x00);
lcdWriteData(0x00);
lcdWriteData(0x01);
lcdWriteData(0xDF);
lcdWriteCommand(0x2B);
lcdWriteData(0x00);
lcdWriteData(0x00);
lcdWriteData(0x01);
lcdWriteData(0x3F); //320-1
lcdWriteCommand(0x3A);
lcdWriteData(0x66); //55:RGB565 66:RGB666 77:RGB888
lcdWriteCommand(0xB4);
lcdWriteData(0x01);
lcdWriteCommand(0xB6); //RGB
lcdWriteData(0x20);
lcdWriteData(0x02); //02
lcdWriteData(0x3B);
lcdWriteCommand(0xB7);
lcdWriteData(0xC6);
lcdWriteCommand(0xC0);
lcdWriteData(0x80);
lcdWriteData(0x45);
lcdWriteCommand(0xC1);
lcdWriteData(0x0F ); //18 //00
lcdWriteCommand(0xC2);
lcdWriteData(0xA7); //A7
lcdWriteCommand(0xC5);
lcdWriteData(0x0A);
lcdWriteCommand(0xE8);
lcdWriteData(0x40);
lcdWriteData(0x8A);
lcdWriteData(0x00);
lcdWriteData(0x00);
lcdWriteData(0x29);
lcdWriteData(0x19);
lcdWriteData(0xA5);
lcdWriteData(0x33);
lcdWriteCommand(0xE0);
lcdWriteData(0xD0);
lcdWriteData(0x08);
lcdWriteData(0x0F);
lcdWriteData(0x06);
lcdWriteData(0x06);
lcdWriteData(0x33);
lcdWriteData(0x30);
lcdWriteData(0x33);
lcdWriteData(0x47);
lcdWriteData(0x17);
lcdWriteData(0x13);
lcdWriteData(0x13);
lcdWriteData(0x2B);
lcdWriteData(0x31);
lcdWriteCommand(0xE1);
lcdWriteData(0xD0);
lcdWriteData(0x0A);
lcdWriteData(0x11);
lcdWriteData(0x0B);
lcdWriteData(0x09);
lcdWriteData(0x07);
lcdWriteData(0x2F);
lcdWriteData(0x33);
lcdWriteData(0x47);
lcdWriteData(0x38);
lcdWriteData(0x15);
lcdWriteData(0x16);
lcdWriteData(0x2C);
lcdWriteData(0x32);
lcdWriteCommand(0xF0);
lcdWriteData(0x3C);
lcdWriteCommand(0xF0);
lcdWriteData(0x69);
delay_ms(120);
lcdWriteCommand(0x21);
LCD_CS_HIGH();
delay_ms(1);
LCD_ST7365_On();
}
void LCD_ST7365_Off(void) {
LCD_CS_LOW();
delay_ms(1);
lcdWriteCommand(0x28);
LCD_CS_HIGH();
}
void LCD_Init_LTDC() {
hltdc.Instance = LTDC;
/* Configure PLLSAI prescalers for LCD */
/* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */
/* PLLSAI_VCO Output = PLLSAI_VCO Input * lcdPixelclock * 16 = XX Mhz */
/* PLLLCDCLK = PLLSAI_VCO Output/PLL_LTDC = PLLSAI_VCO/4 = YY Mhz */
/* LTDC clock frequency = PLLLCDCLK / RCC_PLLSAIDivR = YY/4 = lcdPixelClock Mhz */
// uint32_t clock = (lcdPixelClock*16) / 1000000; // clock*16 in MHz
// RCC_PeriphCLKInitTypeDef clkConfig;
// clkConfig.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
// clkConfig.PLLI2S
// clkConfig.PLLSAI.PLLSAIN = clock;
// clkConfig.PLLSAI.PLLSAIR = 4;
// clkConfig.PLLSAIDivQ = 6;
// clkConfig.PLLSAIDivR = RCC_PLLSAIDIVR_4;
// HAL_RCCEx_PeriphCLKConfig(&clkConfig);
/* LTDC Configuration *********************************************************/
/* Polarity configuration */
/* Initialize the horizontal synchronization polarity as active low */
hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
/* Initialize the vertical synchronization polarity as active low */
hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL;
/* Initialize the data enable polarity as active low */
hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
/* Initialize the pixel clock polarity as input pixel clock */
hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IIPC;
/* Configure R,G,B component values for LCD background color */
hltdc.Init.Backcolor.Red = 0;
hltdc.Init.Backcolor.Green = 0;
hltdc.Init.Backcolor.Blue = 0;
/* Configure horizontal synchronization width */
hltdc.Init.HorizontalSync = HSW-1;
/* Configure vertical synchronization height */
hltdc.Init.VerticalSync = VSH-1;
/* Configure accumulated horizontal back porch */
hltdc.Init.AccumulatedHBP = HSW+HBP-1;
/* Configure accumulated vertical back porch */
hltdc.Init.AccumulatedVBP = VSH+VBP-1;
/* Configure accumulated active width */
hltdc.Init.AccumulatedActiveW = lcd_phys_w + HBP+HSW-1;
/* Configure accumulated active height */
hltdc.Init.AccumulatedActiveH = lcd_phys_h + VBP+VSH-1;
/* Configure total width */
hltdc.Init.TotalWidth = lcd_phys_w + HBP + HFP + HSW -1;
/* Configure total height */
hltdc.Init.TotalHeigh = lcd_phys_h + VBP + VFP+VSH-1;
HAL_LTDC_Init(&hltdc);
// Configure IRQ (line)
NVIC_SetPriority(LTDC_IRQn, LTDC_IRQ_PRIO);
NVIC_EnableIRQ(LTDC_IRQn);
// Trigger on last line
HAL_LTDC_ProgramLineEvent(&hltdc, lcd_phys_h);
__HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI);
}
void LCD_LayerInit() {
auto& layer = hltdc.LayerCfg[0];
/* Windowing configuration */
layer.WindowX0 = 0;
layer.WindowX1 = lcd_phys_w;
layer.WindowY0 = 0;
layer.WindowY1 = lcd_phys_h;
/* Pixel Format configuration*/
layer.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
/* Alpha constant (255 totally opaque) */
layer.Alpha = 255;
/* Default Color configuration (configure A,R,G,B component values) */
layer.Backcolor.Blue = 0;
layer.Backcolor.Green = 0;
layer.Backcolor.Red = 0;
layer.Alpha0 = 0;
/* Configure blending factors */
layer.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;
layer.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA;
layer.ImageWidth = lcd_phys_w;
layer.ImageHeight = lcd_phys_h;
/* Start Address configuration : the LCD Frame buffer is defined on SDRAM w/ Offset */
layer.FBStartAdress = (intptr_t)initialFrameBuffer;
/* Initialize LTDC layer 1 */
HAL_LTDC_ConfigLayer(&hltdc, &hltdc.LayerCfg[0], 0);
/* dithering activation */
HAL_LTDC_EnableDither(&hltdc);
}
extern "C"
void lcdSetInitalFrameBuffer(void* fbAddress)
{
initialFrameBuffer = fbAddress;
}
const char* boardLcdType = "";
extern "C"
void lcdInit(void)
{
#if defined(LCD_SPI_CONFLICTS_WITH_QSPI)
stm32_qspi_nor_deinit();
#endif
/* Configure the LCD SPI+RESET pins */
lcdSpiConfig();
/* Reset the LCD --------------------------------------------------------*/
lcdReset();
/* Configure the LCD Control pins */
LCD_AF_GPIOConfig();
/* Send LCD initialization commands */
TRACE("LCD INIT (default): ST7365");
boardLcdType = "ST7365 (Default)";
lcdInitFunction = LCD_ST7365_Init;
lcdOffFunction = LCD_ST7365_Off;
lcdOnFunction = LCD_ST7365_On;
__HAL_RCC_LTDC_CLK_ENABLE();
lcdInitFunction();
LCD_Init_LTDC();
LCD_LayerInit();
// Enable LCD display
__HAL_LTDC_ENABLE(&hltdc);
lcdSetFlushCb(startLcdRefresh);
#if defined(LCD_SPI_CONFLICTS_WITH_QSPI)
stm32_qspi_nor_init();
stm32_qspi_nor_memory_mapped();
#endif
}
extern "C" void LTDC_IRQHandler(void)
{
__HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI);
__HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI);
_frame_addr_reloaded = 1;
}
+69
View File
@@ -0,0 +1,69 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __LCD_DRIVER_H__
#define __LCD_DRIVER_H__
#include "bsp_io.h"
#define HBP ( 20 )
#define VBP ( 10 )
#define HSW ( 6 )
#define VSH ( 2 )
#define HFP ( 40 )
#define VFP ( 10 )
#define LCD_DELAY() LCD_Delay()
typedef void (*lcdSpiInitFucPtr)(void);
typedef unsigned int LcdReadIDFucPtr( void );
extern lcdSpiInitFucPtr lcdInitFunction;
extern lcdSpiInitFucPtr lcdOffFunction;
extern lcdSpiInitFucPtr lcdOnFunction;
#define SET_IO_INPUT( PORT, PIN ) LL_GPIO_SetPinMode( PORT, PIN, LL_GPIO_MODE_INPUT )
#define SET_IO_OUTPUT( PORT, PIN ) LL_GPIO_SetPinMode( PORT, PIN, LL_GPIO_MODE_OUTPUT )
#define LCD_NRST_HIGH() LL_GPIO_SetOutputPin(LCD_RESET_GPIO, LCD_RESET_GPIO_PIN)
#define LCD_NRST_LOW() LL_GPIO_ResetOutputPin(LCD_RESET_GPIO, LCD_RESET_GPIO_PIN)
#define LCD_CS_HIGH() LL_GPIO_SetOutputPin(LCD_SPI_CS_GPIO, LCD_SPI_CS_GPIO_PIN)
#define LCD_CS_LOW() LL_GPIO_ResetOutputPin(LCD_SPI_CS_GPIO, LCD_SPI_CS_GPIO_PIN)
#define LCD_SCK_HIGH() LL_GPIO_SetOutputPin(LCD_SPI_SCK_GPIO, LCD_SPI_SCK_GPIO_PIN)
#define LCD_SCK_LOW() LL_GPIO_ResetOutputPin(LCD_SPI_SCK_GPIO, LCD_SPI_SCK_GPIO_PIN)
#define LCD_MOSI_HIGH() LL_GPIO_SetOutputPin(LCD_SPI_MOSI_GPIO, LCD_SPI_MOSI_GPIO_PIN)
#define LCD_MOSI_LOW() LL_GPIO_ResetOutputPin(LCD_SPI_MOSI_GPIO, LCD_SPI_MOSI_GPIO_PIN)
#define LCD_MOSI_AS_INPUT() SET_IO_INPUT( LCD_SPI_MOSI_GPIO, LCD_SPI_MOSI_GPIO_PIN )
#define LCD_MOSI_AS_OUTPUT() SET_IO_OUTPUT( LCD_SPI_MOSI_GPIO, LCD_SPI_MOSI_GPIO_PIN )
#define LCD_READ_DATA_PIN() LL_GPIO_IsInputPinSet(LCD_SPI_MOSI_GPIO, LCD_SPI_MOSI_GPIO_PIN)
#endif
+129
View File
@@ -0,0 +1,129 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "hal/gpio.h"
#include "hal/rgbleds.h"
#include "stm32_gpio.h"
#include "stm32_ws2812.h"
#include "boards/generic_stm32/rgb_leds.h"
#include "board.h"
#define GET_RED(color) (((color) & 0xFF0000) >>16)
#define GET_GREEN(color) (((color) & 0x00FF00) >> 8)
#define GET_BLUE(color) ((color) & 0x0000FF)
#if defined(FUNCTION_SWITCHES) && !defined(FUNCTION_SWITCHES_RGB_LEDS)
static const uint32_t fsLeds[] = {FSLED_GPIO_PIN_1, FSLED_GPIO_PIN_2,
FSLED_GPIO_PIN_3, FSLED_GPIO_PIN_4,
FSLED_GPIO_PIN_5, FSLED_GPIO_PIN_6};
#endif
void ledInit()
{
#if defined(LED_GREEN_GPIO)
gpio_init(LED_GREEN_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW);
#endif
#if defined(LED_RED_GPIO)
gpio_init(LED_RED_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW);
#endif
#if defined(LED_BLUE_GPIO)
gpio_init(LED_BLUE_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW);
#endif
#if defined(FUNCTION_SWITCHES) && !defined(FUNCTION_SWITCHES_RGB_LEDS)
for (size_t i = 0; i < DIM(fsLeds); i++) {
gpio_init(fsLeds[i], GPIO_OUT, GPIO_PIN_SPEED_LOW);
}
#endif
}
#if defined(FUNCTION_SWITCHES_RGB_LEDS)
void fsLedRGB(uint8_t index, uint32_t color)
{
ws2812_set_color(index + CFS_LED_STRIP_START, GET_RED(color), GET_GREEN(color),
GET_BLUE(color));
}
uint32_t fsGetLedRGB(uint8_t index)
{
return rgbGetLedColor(index + CFS_LED_STRIP_START);
}
uint8_t getRGBColorIndex(uint32_t color)
{
for (uint8_t i = 0; i < DIM(colorTable); i++) {
if (color == colorTable[i])
return(i + 1);
}
return 0; // Custom value set with Companion
}
#elif defined(FUNCTION_SWITCHES)
void fsLedOff(uint8_t index)
{
gpio_clear(fsLeds[index]);
}
void fsLedOn(uint8_t index)
{
gpio_set(fsLeds[index]);
}
bool fsLedState(uint8_t index)
{
return gpio_read(fsLeds[index]) ? true : false;
}
#endif
void ledOff()
{
#if defined(LED_RED_GPIO)
GPIO_LED_GPIO_OFF(LED_RED_GPIO);
#endif
#if defined(LED_BLUE_GPIO)
GPIO_LED_GPIO_OFF(LED_BLUE_GPIO);
#endif
#if defined(LED_GREEN_GPIO)
GPIO_LED_GPIO_OFF(LED_GREEN_GPIO);
#endif
}
void ledRed()
{
#if defined(LED_RED_GPIO)
GPIO_LED_GPIO_ON(LED_RED_GPIO);
#endif
}
void ledGreen()
{
#if defined(LED_GREEN_GPIO)
GPIO_LED_GPIO_ON(LED_GREEN_GPIO);
#endif
}
void ledBlue()
{
#if defined(LED_BLUE_GPIO)
GPIO_LED_GPIO_ON(LED_BLUE_GPIO);
#endif
}
+215
View File
@@ -0,0 +1,215 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "hal/gpio.h"
#include "stm32_gpio.h"
#include "stm32_hal_ll.h"
#include "board.h"
#define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_16
#define SDRAM_CAS_LATENCY FMC_SDRAM_CAS_LATENCY_3
#define SDCLOCK_PERIOD FMC_SDRAM_CLOCK_PERIOD_2
#define SDRAM_TIMEOUT ((uint32_t)0xFFFF)
#define SDRAM_READBURST FMC_SDRAM_RBURST_DISABLE
#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004)
#define SDRAM_MODEREG_BURST_FULL_PAGE ((uint16_t)0x0007)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_1 ((uint16_t)0x0010)
#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200)
#define GPIO_AF_FMC GPIO_AF12
extern "C" void SDRAM_GPIOConfig(void)
{
/*-- GPIOs Configuration -----------------------------------------------------*/
/*
*/
/* GPIOC configuration */
gpio_init_af(GPIO_PIN(GPIOC, 0), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
/* GPIOD configuration */
gpio_init_af(GPIO_PIN(GPIOD, 0), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOD, 1), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOD, 8), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOD, 9), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOD, 10), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOD, 14), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOD, 15), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
/* GPIOE configuration */
gpio_init_af(GPIO_PIN(GPIOE, 0), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOE, 1), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOE, 7), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOE, 8), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOE, 9), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOE, 10), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOE, 11), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOE, 12), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOE, 13), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOE, 14), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOE, 15), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
/* GPIOF configuration */
gpio_init_af(GPIO_PIN(GPIOF, 0), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOF, 1), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOF, 2), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOF, 3), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOF, 4), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOF, 5), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOF, 11), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOF, 12), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOF, 13), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOF, 14), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOF, 15), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
/* GPIOG configuration */
gpio_init_af(GPIO_PIN(GPIOG, 0), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOG, 1), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOG, 4), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOG, 5), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOG, 8), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOG, 15), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOH, 6), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
gpio_init_af(GPIO_PIN(GPIOH, 7), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH);
}
extern "C" void SDRAM_InitSequence(void)
{
FMC_SDRAM_CommandTypeDef FMC_SDRAMCommandStructure;
uint32_t tmpr = 0;
/* Step 3 --------------------------------------------------------------------*/
/* Configure a clock configuration enable command */
FMC_SDRAMCommandStructure.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
FMC_SDRAMCommandStructure.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
FMC_SDRAMCommandStructure.AutoRefreshNumber = 1;
FMC_SDRAMCommandStructure.ModeRegisterDefinition = 0;
/* Send the command */
FMC_SDRAM_SendCommand(FMC_Bank5_6_R, &FMC_SDRAMCommandStructure, 10);
/* Step 4 --------------------------------------------------------------------*/
/* Insert 1 ms delay */
delay_ms(100);
/* Step 5 --------------------------------------------------------------------*/
/* Configure a PALL (precharge all) command */
FMC_SDRAMCommandStructure.CommandMode = FMC_SDRAM_CMD_PALL;
FMC_SDRAMCommandStructure.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
FMC_SDRAMCommandStructure.AutoRefreshNumber = 1;
FMC_SDRAMCommandStructure.ModeRegisterDefinition = 0;
/* Send the command */
FMC_SDRAM_SendCommand(FMC_Bank5_6_R, &FMC_SDRAMCommandStructure, 10);
/* Step 6 --------------------------------------------------------------------*/
/* Configure a Auto-Refresh command */
FMC_SDRAMCommandStructure.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
FMC_SDRAMCommandStructure.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
FMC_SDRAMCommandStructure.AutoRefreshNumber = 8;
FMC_SDRAMCommandStructure.ModeRegisterDefinition = 0;
/* Send the command */
FMC_SDRAM_SendCommand(FMC_Bank5_6_R, &FMC_SDRAMCommandStructure, 10);
/* Step 7 --------------------------------------------------------------------*/
/* Program the external memory mode register */
tmpr = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_2 |
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_3 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
/* Configure a load Mode register command*/
FMC_SDRAMCommandStructure.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
FMC_SDRAMCommandStructure.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
FMC_SDRAMCommandStructure.AutoRefreshNumber = 1;
FMC_SDRAMCommandStructure.ModeRegisterDefinition = tmpr;
/* Send the command */
FMC_SDRAM_SendCommand(FMC_Bank5_6_R, &FMC_SDRAMCommandStructure, 10);
/* Step 8 --------------------------------------------------------------------*/
/* Set the refresh rate counter */
/* (15.62 us x Freq) - 20 */
/* Set the device refresh counter */
FMC_SDRAM_SetAutoRefreshNumber(FMC_Bank5_6_R, 15);
FMC_SDRAM_ProgramRefreshRate(FMC_Bank5_6_R, 1855);
}
extern "C" void SDRAM_Init(void)
{
//delay funcion needed
delaysInit();
/* GPIO configuration for FMC SDRAM bank */
SDRAM_GPIOConfig();
/* Enable FMC clock */
LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_FMC);
/* FMC Configuration ---------------------------------------------------------*/
FMC_SDRAM_InitTypeDef FMC_SDRAMInitStructure;
FMC_SDRAM_TimingTypeDef FMC_SDRAMTimingInitStructure;
/* FMC SDRAM Bank configuration */
/* Timing configuration for 80 Mhz of SD clock */
FMC_SDRAMTimingInitStructure.LoadToActiveDelay = 2;
FMC_SDRAMTimingInitStructure.ExitSelfRefreshDelay = 7;
FMC_SDRAMTimingInitStructure.SelfRefreshTime = 4;
FMC_SDRAMTimingInitStructure.RowCycleDelay = 7;
FMC_SDRAMTimingInitStructure.WriteRecoveryTime = 3;
FMC_SDRAMTimingInitStructure.RPDelay = 2;
FMC_SDRAMTimingInitStructure.RCDDelay = 2;
/* FMC SDRAM control configuration */
FMC_SDRAMInitStructure.SDBank = FMC_SDRAM_BANK2;
FMC_SDRAMInitStructure.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8;
FMC_SDRAMInitStructure.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
FMC_SDRAMInitStructure.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
FMC_SDRAMInitStructure.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
FMC_SDRAMInitStructure.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
FMC_SDRAMInitStructure.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
FMC_SDRAMInitStructure.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_3;
FMC_SDRAMInitStructure.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
FMC_SDRAMInitStructure.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
/* FMC SDRAM bank initialization */
FMC_SDRAM_Init(FMC_Bank5_6_R, &FMC_SDRAMInitStructure);
FMC_SDRAM_Timing_Init(FMC_Bank5_6_R, &FMC_SDRAMTimingInitStructure, FMC_SDRAM_BANK2);
__FMC_ENABLE();
/* FMC SDRAM device initialization sequence */
SDRAM_InitSequence();
}
+111
View File
@@ -0,0 +1,111 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "stm32h7xx_ll_pwr.h"
#include "stm32h7xx_ll_rcc.h"
#include "stm32h7xx_ll_system.h"
#include "stm32h7xx_ll_bus.h"
#define BOOTSTRAP __attribute__((section(".bootstrap")))
BOOTSTRAP void SystemClock_Config(void)
{
/* Power Configuration */
LL_PWR_ConfigSupply(LL_PWR_LDO_SUPPLY);
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
while (LL_PWR_IsActiveFlag_VOS() == 0){
}
/* Enable HSE oscillator */
LL_RCC_HSE_Enable();
while (LL_RCC_HSE_IsReady() != 1) {
}
/* Set FLASH latency */
LL_FLASH_SetLatency(LL_FLASH_LATENCY_5);
/* Main PLL configuration and activation */
LL_RCC_PLL_SetSource(LL_RCC_PLLSOURCE_HSE);
LL_RCC_PLL1P_Enable();
LL_RCC_PLL1Q_Enable();
LL_RCC_PLL1R_Enable();
LL_RCC_PLL1FRACN_Disable();
LL_RCC_PLL1_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_2_4);
LL_RCC_PLL1_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE);
LL_RCC_PLL1_SetM(3);
LL_RCC_PLL1_SetN(60);
LL_RCC_PLL1_SetP(2);
LL_RCC_PLL1_SetQ(20);
LL_RCC_PLL1_SetR(2);
LL_RCC_PLL1_Enable();
while (LL_RCC_PLL1_IsReady() != 1) {
}
/* Set Sys & AHB & APB1 & APB2 & APB4 prescaler */
LL_RCC_SetSysPrescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetAHBPrescaler(LL_RCC_AHB_DIV_2);
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2);
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_2);
LL_RCC_SetAPB4Prescaler(LL_RCC_APB4_DIV_2);
/* Set PLL1 as System Clock Source */
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL1);
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL1) {
}
/* Config & activate PLL2 */
LL_RCC_PLL2P_Enable();
LL_RCC_PLL2FRACN_Disable();
LL_RCC_PLL2_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_2_4);
LL_RCC_PLL2_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE);
LL_RCC_PLL2_SetM(24);
LL_RCC_PLL2_SetN(96);
LL_RCC_PLL2_SetP(17); // 11.294 MHz
LL_RCC_PLL2_Enable();
while (LL_RCC_PLL2_IsReady() != 1) {
}
/* Config & activate PLL3 */
LL_RCC_PLL3P_Enable();
LL_RCC_PLL3Q_Enable();
LL_RCC_PLL3R_Enable();
LL_RCC_PLL3FRACN_Disable();
LL_RCC_PLL3_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_2_4);
LL_RCC_PLL3_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE);
LL_RCC_PLL3_SetM(1);
LL_RCC_PLL3_SetN(4);
LL_RCC_PLL3_SetP(2);
LL_RCC_PLL3_SetQ(2);
LL_RCC_PLL3_SetR(18);
LL_RCC_PLL3_Enable();
while (LL_RCC_PLL3_IsReady() != 1) {
}
/* Enable SRAM1, SRAM2 & SRAM3 */
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_D2SRAM1 |
LL_AHB2_GRP1_PERIPH_D2SRAM2 |
LL_AHB2_GRP1_PERIPH_D2SRAM3);
/* Set periph clock sources */
LL_RCC_SetSPIClockSource(LL_RCC_SPI123_CLKSOURCE_PLL1Q);
LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLL1Q);
LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_CLKP);
}
+23
View File
@@ -0,0 +1,23 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
void SystemClock_Config();
+31
View File
@@ -0,0 +1,31 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#pragma once
#include "touch.h"
extern void touchPanelDeInit();
extern bool touchPanelInit();
struct TouchState touchPanelRead();
bool touchPanelEventOccured();
struct TouchState getInternalTouchState();
+331
View File
@@ -0,0 +1,331 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "hal/gpio.h"
#include "hal/i2c_driver.h"
#include "stm32_gpio.h"
#include "stm32_hal_ll.h"
#include "stm32_hal.h"
#include "stm32_i2c_driver.h"
#include "stm32_gpio_driver.h"
#include "stm32_exti_driver.h"
#include "hal.h"
#include "timers_driver.h"
#include "tp_gt911.h"
#include "delays_driver.h"
#include "os/sleep.h"
#include "edgetx_types.h"
#include "debug.h"
#include <stdlib.h>
#include <string.h>
#define TP_GT911_ID "911"
bool touchGT911Flag = false;
volatile static bool touchEventOccured = false;
struct TouchData touchData;
uint16_t touchGT911fwver = 0;
uint32_t touchGT911hiccups = 0;
static tmr10ms_t downTime = 0;
static tmr10ms_t tapTime = 0;
static short tapCount = 0;
static TouchState internalTouchState = {};
static void _gt911_exti_isr(void)
{
touchEventOccured = true;
}
void I2C_Init_Radio(void)
{
TRACE("GT911 I2C Init");
if (i2c_init(TOUCH_I2C_BUS) < 0) {
TRACE("GT911 ERROR: i2c_init failed");
return;
}
}
bool I2C_GT911_WriteRegister(uint16_t reg, uint8_t *buf, uint8_t len)
{
uint8_t uAddrAndBuf[258];
uAddrAndBuf[0] = (uint8_t)((reg & 0xFF00) >> 8);
uAddrAndBuf[1] = (uint8_t)(reg & 0x00FF);
if (len > 0) {
for (int i = 0; i < len; i++) {
uAddrAndBuf[i + 2] = buf[i];
}
}
if (stm32_i2c_master_tx(TOUCH_I2C_BUS, GT911_I2C_ADDR, uAddrAndBuf, len + 2,
100) < 0) {
TRACE("I2C B1 ERROR: WriteRegister failed");
return false;
}
return true;
}
bool I2C_GT911_ReadRegister(uint16_t reg, uint8_t *buf, uint8_t len)
{
uint8_t uRegAddr[2];
uRegAddr[0] = (uint8_t)((reg & 0xFF00) >> 8);
uRegAddr[1] = (uint8_t)(reg & 0x00FF);
if (stm32_i2c_master_tx(TOUCH_I2C_BUS, GT911_I2C_ADDR, uRegAddr, 2, 10) < 0) {
TRACE("I2C B1 ERROR: ReadRegister write reg address failed");
return false;
}
if (stm32_i2c_master_rx(TOUCH_I2C_BUS, GT911_I2C_ADDR, buf, len, 100) < 0) {
TRACE("I2C B1 ERROR: ReadRegister read reg address failed");
return false;
}
return true;
}
void touchPanelDeInit(void)
{
gpio_int_disable(TOUCH_INT_GPIO);
touchGT911Flag = false;
}
uint8_t tp_gt911_cfgVer = GT911_CFG_NUMBER;
bool touchPanelInit(void)
{
uint8_t tmp[4] = {0};
if (touchGT911Flag) {
gpio_init_int(TOUCH_INT_GPIO, GPIO_IN_PU, GPIO_RISING, _gt911_exti_isr);
return true;
} else {
TRACE("Touchpanel init start ...");
gpio_init(TOUCH_RST_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW);
gpio_init(TOUCH_INT_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW);
I2C_Init_Radio();
gpio_clear(TOUCH_RST_GPIO);
gpio_set(TOUCH_INT_GPIO);
delay_us(200);
gpio_set(TOUCH_RST_GPIO);
delay_ms(6);
gpio_clear(TOUCH_INT_GPIO);
delay_ms(55);
gpio_init(TOUCH_INT_GPIO, GPIO_IN_PU, GPIO_PIN_SPEED_LOW);
delay_ms(50);
TRACE("Reading Touch registry");
if (!I2C_GT911_ReadRegister(GT911_PRODUCT_ID_REG, tmp, 4)) {
TRACE("GT911 ERROR: Product ID read failed");
}
if (strcmp((char *)tmp, TP_GT911_ID) == 0) {
TRACE("GT911 chip detected");
tmp[0] = 0X02;
if (!I2C_GT911_WriteRegister(GT911_COMMAND_REG, tmp, 1)) {
TRACE("GT911 ERROR: write to control register failed");
}
if (!I2C_GT911_ReadRegister(GT911_CONFIG_REG, tmp, 1)) {
TRACE("GT911 ERROR: configuration register read failed");
}
TRACE("Chip config Ver:%x", tmp[0]);
if ((tp_gt911_cfgVer == 0) || (tmp[0] < tp_gt911_cfgVer)) { // Config ver
TRACE("Sending new config %d", GT911_CFG_NUMBER);
if (!I2C_GT911_ReadRegister(GT911_CONFIG_REG, tmp, 1)) {
TRACE("GT911 ERROR: configuration register read failed");
}
tp_gt911_cfgVer = tmp[0];
}
if (!I2C_GT911_ReadRegister(GT911_FIRMWARE_VERSION_REG, tmp, 2)) {
TRACE("GT911 ERROR: reading firmware version failed");
} else {
touchGT911fwver = (tmp[1] << 8) + tmp[0];
TRACE("GT911 FW version: %u", touchGT911fwver);
}
delay_ms(10);
tmp[0] = 0X00;
if (!I2C_GT911_WriteRegister(GT911_COMMAND_REG, tmp, 1)) { // end reset
TRACE("GT911 ERROR: write to command register failed");
}
touchGT911Flag = true;
gpio_init_int(TOUCH_INT_GPIO, GPIO_IN_PU, GPIO_RISING, _gt911_exti_isr);
return true;
}
TRACE("GT911 chip NOT FOUND");
return false;
}
}
bool I2C_ReInit(void)
{
TRACE("I2C B1 ReInit");
touchPanelDeInit();
if (stm32_i2c_deinit(TOUCH_I2C_BUS) < 0)
TRACE("I2C B1 ReInit - I2C DeInit failed");
// If DeInit fails, try to re-init anyway
if (!touchPanelInit()) {
TRACE("I2C B1 ReInit - touchPanelInit failed");
return false;
}
return true;
}
#if defined(SIMU) || defined(SEMIHOSTING) || defined(DEBUG)
static const char *event2str(uint8_t ev)
{
switch (ev) {
case TE_NONE:
return "NONE";
case TE_UP:
return "UP";
case TE_DOWN:
return "DOWN";
case TE_SLIDE_END:
return "SLIDE_END";
case TE_SLIDE:
return "SLIDE";
default:
return "UNKNOWN";
}
}
#endif
struct TouchState touchPanelRead()
{
uint8_t state = 0;
if (!touchEventOccured) return internalTouchState;
touchEventOccured = false;
uint32_t startReadStatus = timersGetMsTick();
do {
if (!I2C_GT911_ReadRegister(GT911_READ_XY_REG, &state, 1)) {
// ledRed();
touchGT911hiccups++;
TRACE("GT911 I2C read XY error");
if (!I2C_ReInit()) TRACE("I2C B1 ReInit failed");
return internalTouchState;
}
if (state & 0x80u) {
// ready
break;
}
sleep_ms(1);
} while (timersGetMsTick() - startReadStatus < GT911_TIMEOUT);
internalTouchState.deltaX = 0;
internalTouchState.deltaY = 0;
TRACE("touch state = 0x%x", state);
if (state & 0x80u) {
uint8_t pointsCount = (state & 0x0Fu);
uint32_t now = timersGetMsTick();
internalTouchState.tapCount = 0;
if (pointsCount > 0 && pointsCount <= GT911_MAX_TP) {
if (!I2C_GT911_ReadRegister(GT911_READ_XY_REG + 1, touchData.data,
pointsCount * sizeof(TouchPoint))) {
// ledRed();
touchGT911hiccups++;
TRACE("GT911 I2C data read error");
if (!I2C_ReInit()) TRACE("I2C B1 ReInit failed");
return internalTouchState;
}
if (internalTouchState.event == TE_NONE ||
internalTouchState.event == TE_UP ||
internalTouchState.event == TE_SLIDE_END) {
internalTouchState.event = TE_DOWN;
internalTouchState.startX = internalTouchState.x =
touchData.points[0].x;
internalTouchState.startY = internalTouchState.y =
touchData.points[0].y;
downTime = now;
} else {
internalTouchState.deltaX =
touchData.points[0].x - internalTouchState.x;
internalTouchState.deltaY =
touchData.points[0].y - internalTouchState.y;
if (internalTouchState.event == TE_SLIDE ||
abs(internalTouchState.deltaX) >= SLIDE_RANGE ||
abs(internalTouchState.deltaY) >= SLIDE_RANGE) {
internalTouchState.event = TE_SLIDE;
internalTouchState.x = touchData.points[0].x;
internalTouchState.y = touchData.points[0].y;
}
}
} else {
if (internalTouchState.event == TE_SLIDE) {
internalTouchState.event = TE_SLIDE_END;
} else if (internalTouchState.event == TE_DOWN) {
internalTouchState.event = TE_UP;
if (now - downTime <= GT911_TAP_TIME) {
if (now - tapTime > GT911_TAP_TIME)
tapCount = 1;
else
tapCount++;
internalTouchState.tapCount = tapCount;
tapTime = now;
}
} else {
internalTouchState.event = TE_NONE;
}
}
}
uint8_t zero = 0;
if (!I2C_GT911_WriteRegister(GT911_READ_XY_REG, &zero, 1)) {
TRACE("GT911 ERROR: clearing XY register failed");
}
TRACE("touch event = %s", event2str(internalTouchState.event));
return internalTouchState;
}
bool touchPanelEventOccured()
{
return touchEventOccured;
}
TouchState getInternalTouchState()
{
return internalTouchState;
}
+83
View File
@@ -0,0 +1,83 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#pragma once
#include "touch.h"
#include "definitions.h"
#define HAS_TOUCH_PANEL() (touchGT911Flag == true)
extern bool touchGT911Flag;
extern uint16_t touchGT911fwver;
extern uint32_t touchGT911hiccups;
extern void touchPanelDeInit();
extern bool touchPanelInit();
struct TouchState touchPanelRead();
bool touchPanelEventOccured();
struct TouchState getInternalTouchState();
#define GT911_TIMEOUT 3 // 3ms
#define GT911_TAP_TIME 250 // 250 ms
#define GT911_MAX_TP 5
#define GT911_CFG_NUMBER 0x6D
//I2C
#define GT911_I2C_ADDR 0x14
//#define GT_CMD_WR 0x28
//#define GT_CMD_RD 0x29
//#define I2C_TIMEOUT_MAX 1000
#define GT911_COMMAND_REG 0x8040
#define GT911_CONFIG_REG 0x8047
#define GT911_COORDINATE_REG 0x804D
#define GT911_CONFIG_CHECKSUM_REG 0x80FF
#define GT911_PRODUCT_ID_REG 0x8140
#define GT911_FIRMWARE_VERSION_REG 0x8144
#define GT911_VENDOR_ID_REG 0x814A
#define GT911_READ_XY_REG 0x814E
#define GT911_TP1_REG 0x8150
#define GT911_TP2_REG 0x8158
#define GT911_TP3_REG 0x8160
#define GT911_TP4_REG 0x8168
#define GT911_TP5_REG 0x8170
PACK(typedef struct {
uint8_t track;
uint16_t x;
uint16_t y;
uint16_t size;
uint8_t reserved;
}) TouchPoint;
PACK(struct TouchData {
union
{
TouchPoint points[GT911_MAX_TP];
uint8_t data[GT911_MAX_TP * sizeof(TouchPoint)];
};
});
@@ -19,31 +19,22 @@
* GNU General Public License for more details.
*/
#include "hal/gpio.h"
#include "stm32_gpio.h"
#include "board.h"
#include "hal/usb_driver.h"
void EXTERNAL_MODULE_ON()
//TODO: charger enable control
void usbChargerInit()
{
GPIO_SetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN);
gpio_init(UCHARGER_GPIO, GPIO_IN_PU, GPIO_PIN_SPEED_LOW);
gpio_init(UCHARGER_EN_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW);
gpio_clear(UCHARGER_EN_GPIO);
}
void EXTERNAL_MODULE_OFF()
bool usbChargerLed()
{
GPIO_ResetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN);
}
void extModuleInit()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = EXTMODULE_TX_INVERT_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(EXTMODULE_TX_INVERT_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = EXTMODULE_RX_INVERT_GPIO_PIN;
GPIO_Init(EXTMODULE_RX_INVERT_GPIO, &GPIO_InitStructure);
EXTMODULE_TX_INVERTED();
EXTMODULE_RX_INVERTED();
return (gpio_read(UCHARGER_GPIO) && usbPlugged());
}
+29
View File
@@ -0,0 +1,29 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _USB_DESCRIPTOR_H_
#define _USB_DESCRIPTOR_H_
#define USB_NAME "TX15"
#define USB_MANUFACTURER 'R', 'M', ' ', ' ', ' ', ' ', ' ', ' ' /* 8 bytes */
#define USB_PRODUCT 'T', 'X', '1', '5', ' ', ' ', ' ', ' ' /* 8 Bytes */
#endif // _USB_DESCRIPTOR_H_
+88 -88
View File
@@ -125,33 +125,33 @@ TEST_F(TrimsTest, throttleTrim)
{
g_model.thrTrim = 1;
// stick max + trim max
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, TRIM_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 1024);
// stick max + trim min
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, TRIM_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 1024);
// stick min + trim max
anaSetFiltered(THR_STICK, THR_STICK_MIN_THR_POS);
anaSetFiltered(inputMappingConvertMode(THR_STICK), THR_STICK_MIN_THR_POS);
setTrimValue(0, THR_STICK, TRIM_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], THR_STICK_MIN_THR_POS + TRIM_SCALE(512));
// stick min + trim mid
anaSetFiltered(THR_STICK, THR_STICK_MIN_THR_POS);
anaSetFiltered(inputMappingConvertMode(THR_STICK), THR_STICK_MIN_THR_POS);
setTrimValue(0, THR_STICK, 0);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], THR_STICK_MIN_THR_POS + TRIM_SCALE(256));
// stick min + trim min
anaSetFiltered(THR_STICK, THR_STICK_MIN_THR_POS);
anaSetFiltered(inputMappingConvertMode(THR_STICK), THR_STICK_MIN_THR_POS);
setTrimValue(0, THR_STICK, TRIM_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], THR_STICK_MIN_THR_POS);
#if defined(SURFACE_RADIO)
// stick bellow 0 + trim max :no trim in reverse
anaSetFiltered(THR_STICK, -512);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -512);
setTrimValue(0, THR_STICK, TRIM_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], -512);
@@ -159,27 +159,27 @@ TEST_F(TrimsTest, throttleTrim)
// now the same tests with extended Trims
g_model.extendedTrims = 1;
// stick max + trim max
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 1024);
// stick max + trim min
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 1024);
// stick min + trim max
anaSetFiltered(THR_STICK, THR_STICK_MIN_THR_POS);
anaSetFiltered(inputMappingConvertMode(THR_STICK), THR_STICK_MIN_THR_POS);
setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], THR_STICK_MIN_THR_POS + TRIM_SCALE(2048));
// stick min + trim mid
anaSetFiltered(THR_STICK, THR_STICK_MIN_THR_POS);
anaSetFiltered(inputMappingConvertMode(THR_STICK), THR_STICK_MIN_THR_POS);
setTrimValue(0, THR_STICK, 0);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], THR_STICK_MIN_THR_POS + TRIM_SCALE(1024));
// stick min + trim min
anaSetFiltered(THR_STICK, THR_STICK_MIN_THR_POS);
anaSetFiltered(inputMappingConvertMode(THR_STICK), THR_STICK_MIN_THR_POS);
setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], THR_STICK_MIN_THR_POS);
@@ -190,12 +190,12 @@ TEST_F(TrimsTest, invertedThrottlePlusThrottleTrim)
g_model.throttleReversed = 1;
g_model.thrTrim = 1;
// stick max + trim max
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, TRIM_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], -1024);
// stick max + trim mid
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, 0);
evalMixes(1);
#if defined(SURFACE_RADIO)
@@ -204,7 +204,7 @@ TEST_F(TrimsTest, invertedThrottlePlusThrottleTrim)
EXPECT_EQ(channelOutputs[2], -1024+256);
#endif
// stick max + trim min
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, TRIM_MIN);
evalMixes(1);
#if defined(SURFACE_RADIO)
@@ -213,7 +213,7 @@ TEST_F(TrimsTest, invertedThrottlePlusThrottleTrim)
EXPECT_EQ(channelOutputs[THR_CHAN], -1024+512);
#endif
// stick max + trim min
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, TRIM_MIN);
evalMixes(1);
#if defined(SURFACE_RADIO)
@@ -222,12 +222,12 @@ TEST_F(TrimsTest, invertedThrottlePlusThrottleTrim)
EXPECT_EQ(channelOutputs[THR_CHAN], -1024+512);
#endif
// stick min + trim max
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
setTrimValue(0, THR_STICK, TRIM_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], +1024);
// stick min + trim min
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
setTrimValue(0, THR_STICK, TRIM_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], +1024);
@@ -235,40 +235,40 @@ TEST_F(TrimsTest, invertedThrottlePlusThrottleTrim)
// now the same tests with extended Trims
g_model.extendedTrims = 1;
// stick max + trim max : no effect since we are in reverse mode
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], -1024);
#if defined(SURFACE_RADIO)
// stick max + trim mid: no effect since we are in reverse mode
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, 0);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], -1024);
#else
// stick max + trim mid
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, 0);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], -1024+1024);
// stick max + trim min
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], -1024+2048);
#endif
// stick min + trim max
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], +1024);
// stick min + trim mid
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
setTrimValue(0, THR_STICK, 0);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], +1024);
// stick min + trim min
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], +1024);
@@ -281,32 +281,32 @@ TEST_F(TrimsTest, throttleTrimWithZeroWeightOnThrottle)
ExpoData *expo = expoAddress(THR_STICK);
expo->weight = makeSourceNumVal(0);
// stick max + trim max
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, TRIM_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 256);
// stick max + trim mid
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, 0);
evalMixes(1);
EXPECT_LE(abs(channelOutputs[THR_CHAN] - 128), 1); //can't use precise comparison here because of lower precision math on 9X
// stick max + trim min
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, TRIM_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 0);
// stick min + trim max
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
setTrimValue(0, THR_STICK, TRIM_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 256);
// stick min + trim mid
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
setTrimValue(0, THR_STICK, 0);
evalMixes(1);
EXPECT_LE(abs(channelOutputs[THR_CHAN] - 128), 1);
// stick min + trim min
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
setTrimValue(0, THR_STICK, TRIM_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 0);
@@ -315,31 +315,31 @@ TEST_F(TrimsTest, throttleTrimWithZeroWeightOnThrottle)
g_model.extendedTrims = 1;
// trim min + various stick positions = should always be same value
setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN);
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 0);
anaSetFiltered(THR_STICK, -300);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -300);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 0);
anaSetFiltered(THR_STICK, +300);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +300);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 0);
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 0);
// trim max + various stick positions = should always be same value
setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX);
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 1024);
anaSetFiltered(THR_STICK, -300);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -300);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 1024);
anaSetFiltered(THR_STICK, +300);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +300);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 1024);
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 1024);
}
@@ -352,32 +352,32 @@ TEST_F(TrimsTest, invertedThrottlePlusthrottleTrimWithZeroWeightOnThrottle)
ExpoData *expo = expoAddress(THR_STICK);
expo->weight = makeSourceNumVal(0);
// stick max + trim max
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, TRIM_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 0);
// stick max + trim mid
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, 0);
evalMixes(1);
EXPECT_LE(abs(channelOutputs[THR_CHAN] - 128), 1);
// stick max + trim min
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, THR_STICK, TRIM_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 256);
// stick min + trim max
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
setTrimValue(0, THR_STICK, TRIM_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 0);
// stick min + trim mid
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
setTrimValue(0, THR_STICK, 0);
evalMixes(1);
EXPECT_LE(abs(channelOutputs[THR_CHAN] - 128), 1);
// stick min + trim min
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
setTrimValue(0, THR_STICK, TRIM_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 256);
@@ -386,38 +386,38 @@ TEST_F(TrimsTest, invertedThrottlePlusthrottleTrimWithZeroWeightOnThrottle)
g_model.extendedTrims = 1;
// trim min + various stick positions = should always be same value
setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN);
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 1024);
anaSetFiltered(THR_STICK, -300);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -300);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 1024);
anaSetFiltered(THR_STICK, +300);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +300);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 1024);
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 1024);
// trim max + various stick positions = should always be same value
setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX);
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 0);
anaSetFiltered(THR_STICK, -300);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -300);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 0);
anaSetFiltered(THR_STICK, +300);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +300);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 0);
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 0);
}
TEST_F(TrimsTest, CopyTrimsToOffset)
{
setTrimValue(0, ELE_STICK, -100); // -100 on elevator/steering
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, -100); // -100 on elevator/steering
evalFunctions(g_model.customFn, modelFunctionsContext); // it disables all safety channels
copyTrimsToOffset(ELE_CHAN);
EXPECT_EQ(getTrimValue(0, ELE_STICK), -100); // unchanged
@@ -426,7 +426,7 @@ TEST_F(TrimsTest, CopyTrimsToOffset)
TEST_F(TrimsTest, CopySticksToOffset)
{
anaSetFiltered(ELE_STICK, -100);
anaSetFiltered(inputMappingConvertMode(ELE_STICK), -100);
evalMixes(1);
copySticksToOffset(ELE_CHAN);
#if defined(STICK_DEAD_ZONE)
@@ -440,7 +440,7 @@ TEST_F(TrimsTest, MoveTrimsToOffsets)
{
// No trim idle only
g_model.thrTrim = 0;
anaSetFiltered(THR_STICK, 0);
anaSetFiltered(inputMappingConvertMode(THR_STICK), 0);
setTrimValue(0, MIXSRC_TRIMTHR - MIXSRC_FIRST_TRIM, 100);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, -100);
evalMixes(1);
@@ -462,7 +462,7 @@ TEST_F(TrimsTest, MoveTrimsToOffsetsWithTrimIdle)
{
// Trim idle only
g_model.thrTrim = 1;
anaSetFiltered(THR_STICK, THR_STICK_MIN_THR_POS); // Min stick
anaSetFiltered(inputMappingConvertMode(THR_STICK), THR_STICK_MIN_THR_POS); // Min stick
g_model.limitData[THR_CHAN].offset = 0;
g_model.limitData[ELE_CHAN].offset = 0;
setTrimValue(0, MIXSRC_TRIMTHR - MIXSRC_FIRST_TRIM, 100);
@@ -505,8 +505,8 @@ TEST_F(TrimsTest, MoveTrimsToOffsetsWithCrossTrims)
expo = expoAddress(ELE_CHAN);
expo->trimSource = THR_TRIM_SOURCE;
anaSetFiltered(THR_STICK, 0);
anaSetFiltered(ELE_STICK, 0);
anaSetFiltered(inputMappingConvertMode(THR_STICK), 0);
anaSetFiltered(inputMappingConvertMode(ELE_STICK), 0);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, 100);
setTrimValue(0, MIXSRC_TRIMTHR - MIXSRC_FIRST_TRIM, -100);
evalMixes(1);
@@ -537,7 +537,7 @@ TEST_F(TrimsTest, MoveTrimsToOffsetsWithCrosstrimsAndTrimIdle)
expo->trimSource = ELE_TRIM_SOURCE;
expo = expoAddress(ELE_CHAN);
expo->trimSource = THR_TRIM_SOURCE;
anaSetFiltered(THR_STICK, THR_STICK_MIN_THR_POS); // Min throttle
anaSetFiltered(inputMappingConvertMode(THR_STICK), THR_STICK_MIN_THR_POS); // Min throttle
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, 100);
setTrimValue(0, MIXSRC_TRIMTHR - MIXSRC_FIRST_TRIM, -100);
evalMixes(1);
@@ -927,7 +927,7 @@ TEST_F(TrimsTest, throttleTrimEle) {
g_model.thrTrim = 1;
// checks ELE sticks are not affected by throttleTrim
// stick max + trim min
anaSetFiltered(ELE_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(ELE_STICK), +1024);
setTrimValue(0, ELE_STICK, TRIM_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 1024 - 256);
@@ -965,9 +965,9 @@ TEST(Heli, BasicTest)
g_model.mixData[2].mltpx = MLTPX_ADD;
g_model.mixData[2].srcRaw = MIXSRC_CYC3;
g_model.mixData[2].weight = makeSourceNumVal(100);
anaSetFiltered(THR_STICK, 0);
anaSetFiltered(ELE_STICK, 1024);
anaSetFiltered(AIL_STICK, 0);
anaSetFiltered(inputMappingConvertMode(THR_STICK), 0);
anaSetFiltered(inputMappingConvertMode(ELE_STICK), 1024);
anaSetFiltered(inputMappingConvertMode(AIL_STICK), 0);
evalFlightModeMixes(e_perout_mode_normal, 0);
EXPECT_EQ(chans[0], -CHANNEL_MAX);
EXPECT_EQ(chans[1], CHANNEL_MAX/2);
@@ -1001,9 +1001,9 @@ TEST(Heli, Mode2Test)
g_model.mixData[2].mltpx = MLTPX_ADD;
g_model.mixData[2].srcRaw = MIXSRC_CYC3;
g_model.mixData[2].weight = makeSourceNumVal(100);
anaSetFiltered(THR_STICK, 0);
anaSetFiltered(ELE_STICK, 1024);
anaSetFiltered(AIL_STICK, 0);
anaSetFiltered(inputMappingConvertMode(THR_STICK), 0);
anaSetFiltered(inputMappingConvertMode(ELE_STICK), 1024);
anaSetFiltered(inputMappingConvertMode(AIL_STICK), 0);
evalFlightModeMixes(e_perout_mode_normal, 0);
EXPECT_EQ(chans[0], -CHANNEL_MAX);
EXPECT_EQ(chans[1], CHANNEL_MAX/2);
@@ -1093,32 +1093,32 @@ TEST_F(TrimsTest, throttleTrimWithCrossTrims)
expo->trimSource = THR_TRIM_SOURCE;
// stick max + trim max
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(ELE_STICK, 0);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
anaSetFiltered(inputMappingConvertMode(ELE_STICK), 0);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, TRIM_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 1024);
EXPECT_EQ(channelOutputs[ELE_CHAN], 0);
// stick max + trim min
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, TRIM_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 1024);
EXPECT_EQ(channelOutputs[ELE_CHAN], 0);
// stick min + trim max
anaSetFiltered(THR_STICK, THR_STICK_MIN_THR_POS);
anaSetFiltered(inputMappingConvertMode(THR_STICK), THR_STICK_MIN_THR_POS);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, TRIM_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], THR_STICK_MIN_THR_POS + TRIM_SCALE(512));
EXPECT_EQ(channelOutputs[ELE_CHAN], 0);
// stick min + trim mid
anaSetFiltered(THR_STICK, THR_STICK_MIN_THR_POS);
anaSetFiltered(inputMappingConvertMode(THR_STICK), THR_STICK_MIN_THR_POS);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, 0);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], THR_STICK_MIN_THR_POS + TRIM_SCALE(256));
EXPECT_EQ(channelOutputs[ELE_CHAN], 0);
// stick min + trim min
anaSetFiltered(THR_STICK, THR_STICK_MIN_THR_POS);
anaSetFiltered(inputMappingConvertMode(THR_STICK), THR_STICK_MIN_THR_POS);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, TRIM_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], THR_STICK_MIN_THR_POS);
@@ -1127,31 +1127,31 @@ TEST_F(TrimsTest, throttleTrimWithCrossTrims)
// now the same tests with extended Trims
g_model.extendedTrims = 1;
// stick max + trim max
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, TRIM_EXTENDED_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 1024);
EXPECT_EQ(channelOutputs[ELE_CHAN], 0);
// stick max + trim min
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, TRIM_EXTENDED_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], 1024);
EXPECT_EQ(channelOutputs[ELE_CHAN], 0);
// stick min + trim max
anaSetFiltered(THR_STICK, THR_STICK_MIN_THR_POS);
anaSetFiltered(inputMappingConvertMode(THR_STICK), THR_STICK_MIN_THR_POS);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, TRIM_EXTENDED_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], -1024+2048);
EXPECT_EQ(channelOutputs[ELE_CHAN], 0);
// stick min + trim mid
anaSetFiltered(THR_STICK, THR_STICK_MIN_THR_POS);
anaSetFiltered(inputMappingConvertMode(THR_STICK), THR_STICK_MIN_THR_POS);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, 0);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], THR_STICK_MIN_THR_POS + TRIM_SCALE(1024));
EXPECT_EQ(channelOutputs[ELE_CHAN], 0);
// stick min + trim min
anaSetFiltered(THR_STICK, THR_STICK_MIN_THR_POS);
anaSetFiltered(inputMappingConvertMode(THR_STICK), THR_STICK_MIN_THR_POS);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, TRIM_EXTENDED_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], THR_STICK_MIN_THR_POS);
@@ -1169,14 +1169,14 @@ TEST_F(TrimsTest, invertedThrottlePlusThrottleTrimWithCrossTrims)
expo->trimSource = THR_TRIM_SOURCE;
// stick max + trim max
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(ELE_STICK, 0);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
anaSetFiltered(inputMappingConvertMode(ELE_STICK), 0);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, TRIM_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], -1024);
EXPECT_EQ(channelOutputs[ELE_CHAN], 0);
// stick max + trim mid
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, 0);
evalMixes(1);
#if defined(SURFACE_RADIO)
@@ -1186,7 +1186,7 @@ TEST_F(TrimsTest, invertedThrottlePlusThrottleTrimWithCrossTrims)
#endif
EXPECT_EQ(channelOutputs[ELE_CHAN], 0);
// stick max + trim min
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, TRIM_MIN);
evalMixes(1);
#if defined(SURFACE_RADIO)
@@ -1196,13 +1196,13 @@ TEST_F(TrimsTest, invertedThrottlePlusThrottleTrimWithCrossTrims)
#endif
EXPECT_EQ(channelOutputs[ELE_CHAN], 0);
// stick min + trim max
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, TRIM_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], +1024);
EXPECT_EQ(channelOutputs[ELE_CHAN], 0);
// stick min + trim min
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, TRIM_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], +1024);
@@ -1211,13 +1211,13 @@ TEST_F(TrimsTest, invertedThrottlePlusThrottleTrimWithCrossTrims)
// now the same tests with extended Trims
g_model.extendedTrims = 1;
// stick max + trim max
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, TRIM_EXTENDED_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], -1024);
EXPECT_EQ(channelOutputs[ELE_CHAN], 0);
// stick max + trim mid
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, 0);
evalMixes(1);
#if defined(SURFACE_RADIO)
@@ -1227,7 +1227,7 @@ TEST_F(TrimsTest, invertedThrottlePlusThrottleTrimWithCrossTrims)
#endif
EXPECT_EQ(channelOutputs[ELE_CHAN], 0);
// stick max + trim min
anaSetFiltered(THR_STICK, +1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), +1024);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, TRIM_EXTENDED_MIN);
evalMixes(1);
#if defined(SURFACE_RADIO)
@@ -1237,13 +1237,13 @@ TEST_F(TrimsTest, invertedThrottlePlusThrottleTrimWithCrossTrims)
#endif
EXPECT_EQ(channelOutputs[ELE_CHAN], 0);
// stick min + trim max
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, TRIM_EXTENDED_MAX);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], +1024);
EXPECT_EQ(channelOutputs[ELE_CHAN], 0);
// stick min + trim min
anaSetFiltered(THR_STICK, -1024);
anaSetFiltered(inputMappingConvertMode(THR_STICK), -1024);
setTrimValue(0, MIXSRC_TRIMELE - MIXSRC_FIRST_TRIM, TRIM_EXTENDED_MIN);
evalMixes(1);
EXPECT_EQ(channelOutputs[THR_CHAN], +1024);
+1 -1
View File
@@ -90,7 +90,7 @@ LEGACY_NAMES = [
}
},
{
"targets": {"t15"},
"targets": {"t15", "tx15"},
"inputs": {
"LH": {
"yaml": "Rud",
+4
View File
@@ -142,6 +142,10 @@ POT_CONFIG = {
"SL1": {"default": "SLIDER"},
"SL2": {"default": "SLIDER"}
},
"tx15": {
"P1": {"default": "POT"},
"P2": {"default": "POT"},
},
"tx16s": {
"P1": {"default": "POT_CENTER"},
"P2": {"default": "MULTIPOS"},
+15
View File
@@ -382,6 +382,21 @@ SWITCH_CONFIG = {
"SF": {"default": "3POS", "display": [1, 2]},
"SH": {"default": "NONE", "display": [1, 3]}
},
"tx15": {
"SA": {"default": "3POS"},
"SB": {"default": "3POS"},
"SC": {"default": "3POS"},
"SD": {"default": "3POS"},
"SE": {"default": "2POS"},
"SF": {"default": "TOGGLE"},
# custom switches
"SG": {"default": "2POS"},
"SH": {"default": "2POS"},
"SI": {"default": "2POS"},
"SJ": {"default": "2POS"},
"SK": {"default": "2POS"},
"SL": {"default": "2POS"},
},
"tx16s": {
"SA": {"default": "3POS"},
"SB": {"default": "3POS"},
+3
View File
@@ -116,6 +116,9 @@ get_target_build_options() {
t18)
BUILD_OPTIONS+="-DPCB=X10 -DPCBREV=T18"
;;
tx15)
BUILD_OPTIONS+="-DPCB=TX15 -DNANO=NO"
;;
tx16s)
BUILD_OPTIONS+="-DPCB=X10 -DPCBREV=TX16S"
;;
+1 -1
View File
@@ -208,7 +208,7 @@ declare -a simulator_plugins=(
t8 t12 t12max tx12 tx12mk2 t15 t16 t18 t20 t20v2
xlite xlites
x10 x10express x12s
zorro tx16s
zorro tx16s tx15
commando8 boxer pocket mt12 gx12
tlite tpro tprov2 tpros bumblebee lr3pro t14
nv14 el18 pl18 pl18ev pl18u st16 pa01
+1 -2
View File
@@ -86,8 +86,7 @@ do
rm -f CMakeCache.txt arm-none-eabi/CMakeCache.txt
#if [ -f arm-none-eabi/firmware.uf2 ]; then
if [ "$target_name" = "st16" ]; then
if [ -f "arm-none-eabi/firmware.uf2" ]; then
mv arm-none-eabi/firmware.uf2 "../${fw_name}.uf2"
else
mv arm-none-eabi/firmware.bin "../${fw_name}.bin"
+1 -1
View File
@@ -9,7 +9,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
: "${SRCDIR:=$(dirname "$(pwd)/$0")/..}"
: ${FLAVOR:="nv14;el18;pl18;pl18ev;nb4p;st16;t12;t12max;t15;t16;t18;t8;zorro;pocket;commando8;tlite;tpro;tprov2;tpros;bumblebee;t20;t20v2;t14;lr3pro;mt12;gx12;tx12;tx12mk2;boxer;tx16s;x10;x10express;x12s;x7;x7access;x9d;x9dp;x9dp2019;x9e;x9lite;x9lites;xlite;xlites;f16;v14;v12"}
: ${FLAVOR:="nv14;el18;pl18;pl18ev;nb4p;st16;t12;t12max;t15;t16;t18;t8;zorro;pocket;commando8;tlite;tpro;tprov2;tpros;bumblebee;t20;t20v2;t14;lr3pro;mt12;gx12;tx12;tx12mk2;boxer;tx16s;x10;x10express;x12s;x7;x7access;x9d;x9dp;x9dp2019;x9e;x9lite;x9lites;xlite;xlites;f16;v14;v12;tx15"}
: ${COMMON_OPTIONS:="-DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_RULE_MESSAGES=OFF -Wno-dev -DCMAKE_MESSAGE_LOG_LEVEL=WARNING"}
# wipe build directory clean
+1 -1
View File
@@ -11,7 +11,7 @@ if [[ -n ${GCC_ARM} ]] ; then
export PATH=${GCC_ARM}:$PATH
fi
: ${FLAVOR:="t15;tx16s;pl18;nv14;pl18u;nb4p;x9d;x9dp2019;x9e;xlite;xlites;x7;tpro;t20;f16;gx12;st16;pa01"}
: ${FLAVOR:="t15;tx16s;pl18;nv14;pl18u;nb4p;x9d;x9dp2019;x9e;xlite;xlites;x7;tpro;t20;f16;gx12;st16;pa01;tx15"}
: ${SRCDIR:=$(dirname "$(pwd)/$0")/..}
: ${COMMON_OPTIONS:="-DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_RULE_MESSAGES=OFF -Wno-dev -DDISABLE_COMPANION=YES -DCMAKE_MESSAGE_LOG_LEVEL=WARNING"}
+4 -1
View File
@@ -9,7 +9,7 @@
# -----------------------------------------------------------------------------
export BRANCH_NAME="main" # main|2.9|...
export RADIO_TYPE="tx16s" # tx16s|x10|x10express|x12s|x9d|x9dp|x9lite|x9lites|x7|x7access|t12|t12max|tx12|tx12mk2|mt12|gx12|boxer|t8|zorro|pocket|tlite|tpro|t20|t20v2|t14|lr3pro|xlite|xlites|x9dp2019|x9e|x9e-hall|t15|t16|t18|nv14|commando8
export RADIO_TYPE="tx16s" # tx16s|x10|x10express|x12s|x9d|x9dp|x9lite|x9lites|x7|x7access|t12|t12max|tx12|tx12mk2|mt12|gx12|boxer|t8|zorro|pocket|tlite|tpro|t20|t20v2|t14|lr3pro|xlite|xlites|x9dp2019|x9e|x9e-hall|t15|t16|t18|nv14|commando8|tx15
export BUILD_OPTIONS="-DDEFAULT_MODE=2 -DGVARS=YES"
@@ -114,6 +114,9 @@ case $RADIO_TYPE in
t18)
BUILD_OPTIONS+=" -DPCB=X10 -DPCBREV=T18"
;;
tx15)
BUILD_OPTIONS+=" -DPCB=TX15"
;;
tx16s)
BUILD_OPTIONS+=" -DPCB=X10 -DPCBREV=TX16S"
;;