Skip to content

Instantly share code, notes, and snippets.

@nerdCopter
Created November 20, 2022 17:22
Show Gist options
  • Save nerdCopter/70860db0df4f9a4d0add1a942d8476f5 to your computer and use it in GitHub Desktop.
Save nerdCopter/70860db0df4f9a4d0add1a942d8476f5 to your computer and use it in GitHub Desktop.
diff_of_port_roberts_HESP_to_BF411.diff
diff --git a/make/mcu/STM32F7.mk b/make/mcu/STM32F7.mk
index 6d8f71568..e3c747612 100644
--- a/make/mcu/STM32F7.mk
+++ b/make/mcu/STM32F7.mk
@@ -14,8 +14,6 @@ STDPERIPH_DIR = $(ROOT)/lib/main/STM32F7/Drivers/STM32F7xx_HAL_Driver
STDPERIPH_SRC = $(notdir $(wildcard $(STDPERIPH_DIR)/Src/*.c))
EXCLUDES = stm32f7xx_hal_can.c \
stm32f7xx_hal_cec.c \
- stm32f7xx_hal_crc.c \
- stm32f7xx_hal_crc_ex.c \
stm32f7xx_hal_cryp.c \
stm32f7xx_hal_cryp_ex.c \
stm32f7xx_hal_dcmi.c \
diff --git a/src/main/cli/cli.c b/src/main/cli/cli.c
old mode 100644
new mode 100755
index b55bca0f5..17fe0e58b
--- a/src/main/cli/cli.c
+++ b/src/main/cli/cli.c
@@ -71,6 +71,7 @@ bool cliMode = false;
#include "drivers/compass/compass.h"
#include "drivers/display.h"
#include "drivers/dma.h"
+#include "drivers/dma_spi.h"
#include "drivers/flash.h"
#include "drivers/inverter.h"
#include "drivers/io.h"
@@ -174,6 +175,10 @@ bool cliMode = false;
#include "cli.h"
+#ifdef USE_GYRO_IMUF9001
+#include "drivers/accgyro/accgyro_imuf9001.h"
+#endif
+
static serialPort_t *cliPort = NULL;
#ifdef STM32F1
@@ -214,6 +219,15 @@ static bool signatureUpdated = false;
static const char* const emptyName = "-";
static const char* const emptyString = "";
+#ifdef USE_GYRO_IMUF9001
+#define IMUF_CUSTOM_BUFF_LENGTH 26000
+static uint8_t imuf_custom_buff[IMUF_CUSTOM_BUFF_LENGTH];
+static uint32_t imuf_buff_ptr = 0;
+static uint32_t imuf_checksum = 0;
+static int imuf_bin_safe = 0;
+
+#endif
+
#if !defined(USE_CUSTOM_DEFAULTS)
#define CUSTOM_DEFAULTS_START ((char*)0)
#define CUSTOM_DEFAULTS_END ((char *)0)
@@ -3392,6 +3406,64 @@ void cliRxBind(char *cmdline){
}
#endif
+static void hex2byte(char *string, uint8_t *output)
+{
+ char tempBuff[3];
+ tempBuff[0] = string[0];
+ tempBuff[1] = string[1];
+ tempBuff[2] = 0;
+ *output = (uint8_t)strtol(tempBuff, NULL, 16);
+}
+
+
+#ifdef MSP_OVER_CLI
+sbuf_t buft;
+uint8_t bufPtr[256];
+
+void cliMsp(char *cmdline){
+ int len = strlen(cmdline);
+ if (len == 0) {
+ cliPrintLine("No MSP command present");
+
+ return;
+ } else {
+ uint8_t mspCommand = atoi(cmdline);
+ uint8_t start = 2;
+ if (mspCommand > 99) {
+ start = 4;
+ } else if (mspCommand > 9) {
+ start= 3;
+ }
+ uint8_t inBuff[len];
+ uint8_t output;
+ for (int i = 0; i < len; i++) {
+ hex2byte(&cmdline[(i*2) + start], &output);
+ inBuff[i] = output;
+ }
+ sbuf_t inBuf = {.ptr = inBuff, .end = &inBuff[len-1]};
+ //TODO need to fill inPtr with the rest of the bytes from the command line
+
+ buft.ptr = buft.end = bufPtr;
+ if (mspCommonProcessOutCommand(mspCommand, &buft, NULL) || mspProcessOutCommand(mspCommand, &buft)
+ || mspCommonProcessInCommand(mspCommand, &inBuf, NULL) > -1 || mspProcessInCommand(mspCommand, &inBuf) > -1)
+ {
+
+ bufWriterAppend(cliWriter, '.'); //"." is success
+ bufWriterAppend(cliWriter, mspCommand); //msp command sent
+ bufWriterAppend(cliWriter, inBuf.ptr - inBuf.end); //msp command sent
+ bufWriterAppend(cliWriter, buft.ptr - buft.end); //number of chars
+
+ while (buft.end <= buft.ptr)
+ bufWriterAppend(cliWriter, *(buft.end)++); //send data
+ }
+ else
+ {
+ bufWriterAppend(cliWriter, '!'); //"!" is failure
+ }
+ }
+}
+#endif
+
static void printMap(dumpFlags_t dumpMask, const rxConfig_t *rxConfig, const rxConfig_t *defaultRxConfig, const char *headingStr)
{
bool equalsDefault = true;
@@ -3546,6 +3618,116 @@ static void cliExit(char *cmdline)
cliReboot();
}
+
+#ifdef USE_GYRO_IMUF9001
+
+
+static void cliImufBootloaderMode(char *cmdline)
+{
+ (void)(cmdline);
+ if(imufBootloader())
+ {
+ cliPrintLine("BOOTLOADER");
+ }
+ else
+ {
+ cliPrintLine("FAIL");
+ }
+}
+
+
+static void cliImufLoadBin(char *cmdline)
+{
+ #define TEMP_BUFF 256
+ uint32_t dataSize;
+ uint8_t output;
+ uint8_t dataBuff[TEMP_BUFF] = {0,};
+ uint32_t x;
+
+ if(cmdline[0] == '!')
+ {
+ imuf_bin_safe = 1;
+ imuf_buff_ptr = 0;
+ imuf_checksum = 0;
+ memset(imuf_custom_buff, 0, IMUF_CUSTOM_BUFF_LENGTH);
+ cliPrintLine("SUCCESS");
+ }
+ else if(cmdline[0] == '.')
+ {
+ cliPrintLinef("%d", imuf_buff_ptr);
+ }
+ else if(cmdline[0] == 'c')
+ {
+ cliPrintLinef("%d", imuf_checksum);
+ }
+ else if(cmdline[0] == 'l')
+ {
+ if (imuf_bin_safe)
+ {
+ //get the datasize
+ hex2byte(&cmdline[1], &output);
+ dataSize = ((output & 0xff) << 0 );
+ hex2byte(&cmdline[3], &output);
+ dataSize += ((output & 0xff) << 8 );
+ hex2byte(&cmdline[5], &output);
+ dataSize += ((output & 0xff) << 16);
+ hex2byte(&cmdline[7], &output);
+ dataSize += ((output & 0xff) << 24);
+
+ if(dataSize < TEMP_BUFF)
+ {
+ //fill the temp buffer
+ for(x=0; x< dataSize; x++)
+ {
+ hex2byte(&cmdline[(x*2)+9], &output);
+ dataBuff[x] = output;
+ imuf_checksum += output;
+ //cliPrintLinef("out:%d:%d:%d:%d", dataSize, x, (x*2)+9, output, checksum);
+ }
+ if ( (imuf_buff_ptr+dataSize) < IMUF_CUSTOM_BUFF_LENGTH )
+ {
+ memcpy(imuf_custom_buff+imuf_buff_ptr, dataBuff, dataSize);
+ imuf_buff_ptr += dataSize;
+ cliPrintLine("LOADED");
+ }
+ else
+ {
+ cliPrintLine("WOAH!");
+ }
+ }
+ else
+ {
+ cliPrintLine("CRAP!");
+ }
+ }
+ else
+ {
+ cliPrintLine("PFFFT!");
+ }
+ }
+}
+
+static void cliImufFlashBin(char *cmdline)
+{
+ (void)(cmdline);
+ if (imufUpdate(imuf_custom_buff, imuf_buff_ptr))
+ {
+ cliPrintLine("SUCCESS");
+ bufWriterFlush(cliWriter);
+ delay(5000);
+
+ *cliBuffer = '\0';
+ bufferIndex = 0;
+ cliMode = 0;
+ // incase a motor was left running during motortest, clear it here
+ mixerResetDisarmedMotors();
+ cliReboot();
+
+ cliWriter = NULL;
+ }
+}
+#endif
+
#ifdef USE_GPS
static void cliGpsPassthrough(char *cmdline)
{
@@ -4627,7 +4809,7 @@ static void cliStatus(char *cmdline)
// Sensors
-#if defined(USE_SENSOR_NAMES)
+#if defined(USE_SENSOR_NAMES) && !defined(USE_GYRO_IMUF9001)
const uint32_t detectedSensorsMask = sensorsMask();
for (uint32_t i = 0; ; i++) {
if (sensorTypeNames[i] == NULL) {
@@ -4649,6 +4831,12 @@ static void cliStatus(char *cmdline)
}
}
cliPrintLinefeed();
+#else
+ #if defined(USE_GYRO_IMUF9001)
+ UNUSED(sensorHardwareNames);
+ UNUSED(sensorTypeNames);
+ cliPrintf(" | IMU-F Version: %lu", imufCurrentVersion);
+ #endif
#endif /* USE_SENSOR_NAMES */
// Uptime and wall clock
@@ -4783,6 +4971,10 @@ static void cliVersion(char *cmdline)
cliPrintLinefeed();
#endif
+#ifdef USE_GYRO_IMUF9001
+ cliPrintLinef("# IMU-F Version: %lu", imufCurrentVersion);
+#endif
+
#ifdef USE_UNIFIED_TARGET
cliPrint("# ");
#ifdef USE_BOARD_INFO
@@ -6239,6 +6431,10 @@ typedef struct {
}
#endif
+#ifdef USE_GYRO_IMUF9001
+static void cliReportImufErrors(char *cmdline);
+#endif
+
static void cliHelp(char *cmdline);
// should be sorted a..z for bsearch()
@@ -6319,6 +6515,11 @@ const clicmd_t cmdTable[] = {
CLI_COMMAND_DEF("gyroregisters", "dump gyro config registers contents", NULL, cliDumpGyroRegisters),
#endif
CLI_COMMAND_DEF("help", NULL, NULL, cliHelp),
+#ifdef USE_GYRO_IMUF9001
+ CLI_COMMAND_DEF("imufbootloader", NULL, NULL, cliImufBootloaderMode),
+ CLI_COMMAND_DEF("imufloadbin", NULL, NULL, cliImufLoadBin),
+ CLI_COMMAND_DEF("imufflashbin", NULL, NULL, cliImufFlashBin),
+#endif
#ifdef USE_LED_STRIP_STATUS_MODE
CLI_COMMAND_DEF("led", "configure leds", NULL, cliLed),
#endif
@@ -6353,6 +6554,9 @@ const clicmd_t cmdTable[] = {
#endif // USE_RC_SMOOTHING_FILTER
#ifdef USE_RESOURCE_MGMT
CLI_COMMAND_DEF("resource", "show/set resources", "<> | <resource name> <index> [<pin>|none] | show [all]", cliResource),
+#endif
+#ifdef USE_GYRO_IMUF9001
+ CLI_COMMAND_DEF("reportimuferrors", "report imu-f comm errors", NULL, cliReportImufErrors),
#endif
CLI_COMMAND_DEF("rxfail", "show/set rx failsafe settings", NULL, cliRxFailsafe),
CLI_COMMAND_DEF("rxrange", "configure rx channel ranges", NULL, cliRxRange),
@@ -6401,6 +6605,15 @@ const clicmd_t cmdTable[] = {
#endif
};
+#ifdef USE_GYRO_IMUF9001
+static void cliReportImufErrors(char *cmdline)
+{
+ UNUSED(cmdline);
+ cliPrintf("Current Comm Errors: %lu", crcErrorCount);
+ cliPrintLinefeed();
+}
+#endif
+
static void cliHelp(char *cmdline)
{
UNUSED(cmdline);
diff --git a/src/main/cms/cms_menu_imu.c b/src/main/cms/cms_menu_imu.c
index 13d089c1f..c1fe7bb45 100644
--- a/src/main/cms/cms_menu_imu.c
+++ b/src/main/cms/cms_menu_imu.c
@@ -73,6 +73,11 @@ static uint8_t rateProfileIndex;
static char rateProfileIndexString[MAX_RATE_PROFILE_NAME_LENGTH + 5];
static controlRateConfig_t rateProfile;
+// HELIOSPRING
+static const char * const cms_offOnLabels[] = {
+ "OFF", "ON"
+};
+
static const char * const osdTableThrottleLimitType[] = {
"OFF", "SCALE", "CLIP"
};
@@ -373,6 +378,53 @@ static uint8_t cmsx_iterm_relax_type;
static uint8_t cmsx_iterm_relax_cutoff;
#endif
+// HELIOSPRING
+#if defined(USE_GYRO_IMUF9001)
+static uint16_t gyroConfig_imuf_roll_q;
+static uint16_t gyroConfig_imuf_pitch_q;
+static uint16_t gyroConfig_imuf_yaw_q;
+static uint16_t gyroConfig_imuf_w;
+static uint16_t gyroConfig_imuf_pitch_lpf_cutoff_hz;
+static uint16_t gyroConfig_imuf_roll_lpf_cutoff_hz;
+static uint16_t gyroConfig_imuf_yaw_lpf_cutoff_hz;
+static uint8_t gyroConfig_imuf_roll_af;
+static uint8_t gyroConfig_imuf_pitch_af;
+static uint8_t gyroConfig_imuf_yaw_af;
+#endif
+#if defined(USE_GYRO_IMUF9001)
+static long cmsx_menuImuf_onEnter(void)
+{
+ gyroConfig_imuf_roll_q = gyroConfig()->imuf_roll_q;
+ gyroConfig_imuf_pitch_q = gyroConfig()->imuf_pitch_q;
+ gyroConfig_imuf_yaw_q = gyroConfig()->imuf_yaw_q;
+ gyroConfig_imuf_w = gyroConfig()->imuf_w;
+ gyroConfig_imuf_pitch_lpf_cutoff_hz = gyroConfig()->imuf_pitch_lpf_cutoff_hz;
+ gyroConfig_imuf_roll_lpf_cutoff_hz = gyroConfig()->imuf_roll_lpf_cutoff_hz;
+ gyroConfig_imuf_yaw_lpf_cutoff_hz = gyroConfig()->imuf_yaw_lpf_cutoff_hz;
+ gyroConfig_imuf_roll_af = gyroConfigMutable()->imuf_roll_af;
+ gyroConfig_imuf_pitch_af = gyroConfigMutable()->imuf_pitch_af;
+ gyroConfig_imuf_yaw_af = gyroConfigMutable()->imuf_yaw_af;
+ return 0;
+}
+#endif
+#if defined(USE_GYRO_IMUF9001)
+static long cmsx_menuImuf_onExit(const OSD_Entry *self)
+{
+ UNUSED(self);
+ gyroConfigMutable()->imuf_roll_q = gyroConfig_imuf_roll_q;
+ gyroConfigMutable()->imuf_pitch_q = gyroConfig_imuf_pitch_q;
+ gyroConfigMutable()->imuf_yaw_q = gyroConfig_imuf_yaw_q;
+ gyroConfigMutable()->imuf_w = gyroConfig_imuf_w;
+ gyroConfigMutable()->imuf_roll_lpf_cutoff_hz = gyroConfig_imuf_roll_lpf_cutoff_hz;
+ gyroConfigMutable()->imuf_pitch_lpf_cutoff_hz = gyroConfig_imuf_pitch_lpf_cutoff_hz;
+ gyroConfigMutable()->imuf_yaw_lpf_cutoff_hz = gyroConfig_imuf_yaw_lpf_cutoff_hz;
+ gyroConfigMutable()->imuf_roll_af = gyroConfig_imuf_roll_af;
+ gyroConfigMutable()->imuf_pitch_af = gyroConfig_imuf_pitch_af;
+ gyroConfigMutable()->imuf_yaw_af = gyroConfig_imuf_yaw_af;
+ return 0;
+}
+#endif
+
static long cmsx_profileOtherOnEnter(void)
{
setProfileIndexString(pidProfileIndexString, pidProfileIndex, currentPidProfile->profileName);
@@ -485,6 +537,39 @@ static const OSD_Entry cmsx_menuProfileOtherEntries[] = {
{ NULL, OME_END, NULL, NULL, 0 }
};
+// HELIOSPRING
+#if defined(USE_GYRO_IMUF9001)
+static OSD_Entry cmsx_menuImufEntries[] =
+{
+ { "-- SPRING IMU-F --", OME_Label, NULL, NULL, 0 },
+ { "-- CHANGES REQUIRE REBOOT --", OME_Label, NULL, NULL, 0 },
+ { "IMUF W", OME_UINT16, NULL, &(OSD_UINT16_t) { &gyroConfig_imuf_w, 0, 300, 1 }, 0 },
+ { "ROLL Q", OME_UINT16, NULL, &(OSD_UINT16_t) { &gyroConfig_imuf_roll_q, 0, 16000, 50 }, 0 },
+ { "PITCH Q", OME_UINT16, NULL, &(OSD_UINT16_t) { &gyroConfig_imuf_pitch_q, 0, 16000, 50 }, 0 },
+ { "YAW Q", OME_UINT16, NULL, &(OSD_UINT16_t) { &gyroConfig_imuf_yaw_q, 0, 16000, 50 }, 0 },
+ { "ROLL LPF", OME_UINT16, NULL, &(OSD_UINT16_t) { &gyroConfig_imuf_roll_lpf_cutoff_hz, 0, 450, 1 }, 0 },
+ { "PITCH LPF", OME_UINT16, NULL, &(OSD_UINT16_t) { &gyroConfig_imuf_pitch_lpf_cutoff_hz, 0, 450, 1 }, 0 },
+ { "YAW LPF", OME_UINT16, NULL, &(OSD_UINT16_t) { &gyroConfig_imuf_yaw_lpf_cutoff_hz, 0, 450, 1 }, 0 },
+ { "ROLL AF", OME_TAB, NULL, &(OSD_TAB_t) { &gyroConfig_imuf_roll_af, 0, cms_offOnLabels}, 0 },
+ { "PITCH AF", OME_TAB, NULL, &(OSD_TAB_t) { &gyroConfig_imuf_pitch_af, 0, cms_offOnLabels}, 0 },
+ { "YAW AF", OME_TAB, NULL, &(OSD_TAB_t) { &gyroConfig_imuf_yaw_af, 0, cms_offOnLabels}, 0 },
+ { "BACK", OME_Back, NULL, NULL, 0},
+ { "SAVE&REBOOT", OME_OSD_Exit, cmsMenuExit, (void *)CMS_EXIT_SAVEREBOOT, 0},
+ { NULL, OME_END, NULL, NULL, 0 }
+};
+#endif
+#if defined(USE_GYRO_IMUF9001)
+static CMS_Menu cmsx_menuImuf = {
+#ifdef CMS_MENU_DEBUG
+ .GUARD_text = "XIMUF",
+ .GUARD_type = OME_MENU,
+#endif
+ .onEnter = cmsx_menuImuf_onEnter,
+ .onExit = cmsx_menuImuf_onExit,
+ .entries = cmsx_menuImufEntries,
+};
+#endif
+
static CMS_Menu cmsx_menuProfileOther = {
#ifdef CMS_MENU_DEBUG
.GUARD_text = "XPROFOTHER",
@@ -794,6 +879,12 @@ static const OSD_Entry cmsx_menuImuEntries[] =
{"RATE", OME_Submenu, cmsMenuChange, &cmsx_menuRateProfile, 0},
{"FILT GLB", OME_Submenu, cmsMenuChange, &cmsx_menuFilterGlobal, 0},
+
+// HELIOSPRING
+#if defined(USE_GYRO_IMUF9001)
+ {"IMUF", OME_Submenu, cmsMenuChange, &cmsx_menuImuf, 0},
+#endif
+
#if (defined(USE_GYRO_DATA_ANALYSE) || defined(USE_DYN_LPF)) && defined(USE_EXTENDED_CMS_MENUS)
{"DYN FILT", OME_Submenu, cmsMenuChange, &cmsx_menuDynFilt, 0},
#endif
diff --git a/src/main/common/sensor_alignment.h b/src/main/common/sensor_alignment.h
index e158c6052..8ed6af449 100644
--- a/src/main/common/sensor_alignment.h
+++ b/src/main/common/sensor_alignment.h
@@ -37,8 +37,18 @@ typedef enum {
CW90_DEG_FLIP = 6, // 00,10,01
CW180_DEG_FLIP = 7, // 00,10,10
CW270_DEG_FLIP = 8, // 00,10,11
-
- ALIGN_CUSTOM = 9, // arbitrary sensor angles, e.g. for external sensors
+// HELIOSPRING
+#ifdef USE_GYRO_IMUF9001
+ CW45_DEG = 9,
+ CW135_DEG = 10,
+ CW225_DEG = 11,
+ CW315_DEG = 12,
+ CW45_DEG_FLIP = 13,
+ CW135_DEG_FLIP = 14,
+ CW225_DEG_FLIP = 15,
+ CW315_DEG_FLIP = 16,
+#endif
+ ALIGN_CUSTOM = 17, // arbitrary sensor angles, e.g. for external sensors
} sensor_align_e;
typedef union sensorAlignment_u {
diff --git a/src/main/drivers/accgyro/accgyro.h b/src/main/drivers/accgyro/accgyro.h
index d2f7f6ee2..a21082761 100644
--- a/src/main/drivers/accgyro/accgyro.h
+++ b/src/main/drivers/accgyro/accgyro.h
@@ -53,6 +53,7 @@ typedef enum {
GYRO_ICM20649,
GYRO_ICM20689,
GYRO_BMI160,
+ GYRO_IMUF9001, // HELIOSPRING
GYRO_FAKE
} gyroHardware_e;
diff --git a/src/main/drivers/accgyro/accgyro_imuf9001.c b/src/main/drivers/accgyro/accgyro_imuf9001.c
new file mode 100755
index 000000000..7f903fd26
--- /dev/null
+++ b/src/main/drivers/accgyro/accgyro_imuf9001.c
@@ -0,0 +1,655 @@
+/*
+ * This file is part of Cleanflight.
+ *
+ * Cleanflight is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Cleanflight 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "platform.h"
+
+#include "sensors/gyro.h"
+#include "accgyro.h"
+#include "accgyro_mpu.h"
+#include "accgyro_imuf9001.h"
+
+#include "common/axis.h"
+#include "build/debug.h"
+#include "common/maths.h"
+#include "drivers/serial.h"
+#include "drivers/bus_spi.h"
+#include "drivers/dma_spi.h"
+#include "drivers/exti.h"
+#include "drivers/io.h"
+#include "drivers/light_led.h"
+#include "drivers/sensor.h"
+#include "drivers/time.h"
+#include "fc/config.h"
+#include "fc/runtime_config.h"
+
+#include "sensors/boardalignment.h"
+#include "sensors/gyro.h"
+#include "sensors/acceleration.h"
+
+#ifdef USE_HAL_F7_CRC
+//CRC stuff should really go in a separate CRC driver, but only IMUF uses it
+#include "stm32f7xx_hal.h"
+#include "drivers/system.h"
+#endif
+
+
+#ifdef USE_GYRO_IMUF9001
+
+#define MPU_INT_EXTI PB0
+
+volatile uint16_t imufCurrentVersion = IMUF_FIRMWARE_MIN_VERSION;
+FAST_RAM_ZERO_INIT volatile uint32_t isImufCalibrating;
+FAST_RAM_ZERO_INIT volatile imuFrame_t imufQuat;
+FAST_RAM_ZERO_INIT busDevice_t *imufDev;
+
+#ifdef USE_HAL_F7_CRC
+//CRC stuff should really go in a separate CRC driver, but only IMUF uses it
+FAST_RAM_ZERO_INIT CRC_HandleTypeDef CrcHandle;
+#endif
+
+void crcConfig(void)
+{
+ #ifdef USE_HAL_F7_CRC
+ __HAL_RCC_CRC_CLK_ENABLE();
+ CrcHandle.Instance = CRC;
+ CrcHandle.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_DISABLE;
+ CrcHandle.Init.GeneratingPolynomial = 0x04C11DB7;
+ CrcHandle.Init.CRCLength = CRC_POLYLENGTH_32B;
+ CrcHandle.InputDataFormat = CRC_INPUTDATA_FORMAT_WORDS;
+
+ HAL_CRC_Init(&CrcHandle);
+ #endif
+ //F4 std per doesn't need to be init
+ return;
+}
+
+FAST_CODE uint32_t getCrcImuf9001(uint32_t* data, uint32_t size)
+{
+ #ifdef USE_HAL_F7_CRC
+ return HAL_CRC_Calculate(&CrcHandle, data, size);
+ #else
+ CRC_ResetDR(); //reset data register
+ for(uint32_t x=0; x<size; x++ )
+ {
+ CRC_CalcCRC(data[x]);
+ }
+ return CRC_GetCRC();
+ #endif
+}
+
+FAST_CODE void appendCrcToData(uint32_t* data, uint32_t size)
+{
+ data[size] = getCrcImuf9001(data, size);;
+}
+
+FAST_CODE static void gpio_write_pin(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin, gpioState_t pinState)
+{
+ //GPIO manipulation should go into a fast GPIO driver and should be separate from the befhal
+
+ #ifdef USE_HAL_F7_CRC
+ HAL_GPIO_WritePin(GPIOx, GPIO_Pin, pinState);
+ #else
+ if (pinState == GPIO_HI)
+ {
+ GPIOx->BSRRL = (uint32_t)GPIO_Pin;
+ }
+ else
+ {
+ GPIOx->BSRRH = (uint32_t)GPIO_Pin;
+ }
+ #endif
+}
+
+void resetImuf9001(void)
+{
+ gpio_write_pin(IMUF_RST_PORT, IMUF_RST_PIN, GPIO_LO);
+ //blink
+ for(uint32_t x = 0; x<40; x++)
+ {
+ LED0_TOGGLE;
+ delay(20);
+ }
+ LED0_OFF;
+ gpio_write_pin(IMUF_RST_PORT, IMUF_RST_PIN, GPIO_HI);
+ delay(100);
+}
+
+
+#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)
+#define GPIO_GET_INDEX(__GPIOx__) (uint8_t)(((__GPIOx__) == (GPIOA))? 0U :\
+ ((__GPIOx__) == (GPIOB))? 1U :\
+ ((__GPIOx__) == (GPIOC))? 2U :\
+ ((__GPIOx__) == (GPIOD))? 3U :\
+ ((__GPIOx__) == (GPIOE))? 4U :\
+ ((__GPIOx__) == (GPIOF))? 5U :\
+ ((__GPIOx__) == (GPIOG))? 6U :\
+ ((__GPIOx__) == (GPIOH))? 7U : 8U)
+#endif
+
+void imufDeinitGpio(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin)
+{
+ uint32_t position;
+ uint32_t ioposition = 0x00U;
+ uint32_t iocurrent = 0x00U;
+ uint32_t tmp = 0x00U;
+
+ /* Configure the port pins */
+ for(position = 0U; position < 16; position++)
+ {
+ /* Get the IO position */
+ ioposition = 0x01U << position;
+ /* Get the current IO position */
+ iocurrent = (GPIO_Pin) & ioposition;
+
+ if(iocurrent == ioposition)
+ {
+ /*------------------------- GPIO Mode Configuration --------------------*/
+ /* Configure IO Direction in Input Floating Mode */
+ GPIOx->MODER &= ~(GPIO_MODER_MODER0 << (position * 2U));
+
+ /* Configure the default Alternate Function in current IO */
+ GPIOx->AFR[position >> 3U] &= ~(0xFU << ((uint32_t)(position & 0x07U) * 4U)) ;
+
+ /* Configure the default value for IO Speed */
+ GPIOx->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR0 << (position * 2U));
+
+ /* Configure the default value IO Output Type */
+ GPIOx->OTYPER &= ~(GPIO_OTYPER_OT_0 << position) ;
+
+ /* Deactivate the Pull-up and Pull-down resistor for the current IO */
+ GPIOx->PUPDR &= ~(GPIO_PUPDR_PUPDR0 << (position * 2U));
+
+ /*------------------------- EXTI Mode Configuration --------------------*/
+ tmp = SYSCFG->EXTICR[position >> 2U];
+ tmp &= (0x0FU << (4U * (position & 0x03U)));
+ if(tmp == ((uint32_t)(GPIO_GET_INDEX(GPIOx)) << (4U * (position & 0x03U))))
+ {
+ /* Configure the External Interrupt or event for the current IO */
+ tmp = 0x0FU << (4U * (position & 0x03U));
+ SYSCFG->EXTICR[position >> 2U] &= ~tmp;
+
+ /* Clear EXTI line configuration */
+ EXTI->IMR &= ~((uint32_t)iocurrent);
+ EXTI->EMR &= ~((uint32_t)iocurrent);
+
+ /* Clear Rising Falling edge configuration */
+ EXTI->RTSR &= ~((uint32_t)iocurrent);
+ EXTI->FTSR &= ~((uint32_t)iocurrent);
+ }
+ }
+ }
+}
+
+void initImuf9001(void)
+{
+ //GPIO manipulation should go into a fast GPIO driver and should be separate from the befhal
+ #ifdef USE_HAL_F7_CRC
+ HAL_GPIO_DeInit(IMUF_RST_PORT, IMUF_RST_PIN);
+ GPIO_InitTypeDef GPIO_InitStruct;
+ GPIO_InitStruct.Pin = IMUF_RST_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
+
+ HAL_GPIO_Init(IMUF_RST_PORT, &GPIO_InitStruct);
+ #else
+ //GPIO_DeInit(IMUF_RST_PORT);
+ imufDeinitGpio(IMUF_RST_PORT, IMUF_RST_PIN);
+ GPIO_InitTypeDef gpioInitStruct;
+ gpioInitStruct.GPIO_Pin = IMUF_RST_PIN;
+ gpioInitStruct.GPIO_Mode = GPIO_Mode_OUT;
+ gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
+ gpioInitStruct.GPIO_OType = GPIO_OType_OD;
+ gpioInitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(IMUF_RST_PORT, &gpioInitStruct);
+ #endif
+
+ resetImuf9001();
+}
+
+FAST_CODE bool imufSendReceiveSpiBlocking(const busDevice_t *bus, uint8_t *dataTx, uint8_t *daRx, uint8_t length)
+{
+ spiBusTransfer(bus, dataTx, daRx, length);
+ return true;
+}
+
+FAST_CODE static int imuf9001SendReceiveCommand(const busDevice_t *gyro, gyroCommands_t commandToSend, imufCommand_t *reply, imufCommand_t *data)
+{
+
+ imufCommand_t command;
+ volatile uint32_t attempt, crcCalc;
+ int failCount = 5000;
+
+ memset(reply, 0, sizeof(command));
+
+ if (data)
+ {
+ memcpy(&command, data, sizeof(command));
+ }
+ else
+ {
+ memset(&command, 0, sizeof(command));
+ }
+
+ command.command = commandToSend;
+ command.crc = getCrcImuf9001((uint32_t *)&command, 11);;
+
+
+ while (failCount-- > 0)
+ {
+ delayMicroseconds(1000);
+ if( IORead(IOGetByTag(IO_TAG(MPU_INT_EXTI))) ) //IMU is ready to talk
+ {
+ failCount -= 100;
+ if (imufSendReceiveSpiBlocking(gyro, (uint8_t *)&command, (uint8_t *)reply, sizeof(imufCommand_t)))
+ {
+ crcCalc = getCrcImuf9001((uint32_t *)reply, 11);
+ //this is the only valid reply we'll get if we're in BL mode
+ if(crcCalc == reply->crc && (reply->command == IMUF_COMMAND_LISTENING || reply->command == BL_LISTENING)) //this tells us the IMU was listening for a command, else we need to reset synbc
+ {
+ for (attempt = 0; attempt < 100; attempt++)
+ {
+ //reset command, just waiting for reply data now
+ command.command = IMUF_COMMAND_NONE;
+ command.crc = getCrcImuf9001((uint32_t *)&command, 11);
+ if (commandToSend == BL_ERASE_ALL){
+ delay(600);
+ }
+ if(commandToSend == BL_WRITE_FIRMWARES)
+ {
+ delay(10);
+ }
+ delayMicroseconds(1000); //give pin time to set
+
+ if( IORead(IOGetByTag(IO_TAG(MPU_INT_EXTI))) ) //IMU is ready to talk
+ {
+ //reset attempts
+ attempt = 100;
+
+ delayMicroseconds(1000); //give pin time to set
+ imufSendReceiveSpiBlocking(gyro, (uint8_t *)&command, (uint8_t *)reply, sizeof(imufCommand_t));
+ crcCalc = getCrcImuf9001((uint32_t *)reply, 11);
+
+ if(crcCalc == reply->crc && reply->command == commandToSend ) //this tells us the IMU understood the last command
+ {
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int imufBootloader()
+{
+
+ imufCommand_t reply;
+ imufCommand_t data;
+ memset(&data, 0, sizeof(data));
+
+ //config BL pin as output (shared with EXTI, this happens before EXTI init though)
+ //config pins
+ #ifdef USE_HAL_F7_CRC
+ HAL_GPIO_DeInit(IMUF_EXTI_PORT, IMUF_EXTI_PIN);
+ GPIO_InitTypeDef GPIO_InitStruct;
+ GPIO_InitStruct.Pin = IMUF_EXTI_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
+
+ HAL_GPIO_Init(IMUF_EXTI_PORT, &GPIO_InitStruct);
+ #else
+ //GPIO_DeInit(IMUF_EXTI_PORT);
+ imufDeinitGpio(IMUF_EXTI_PORT, IMUF_EXTI_PIN);
+ GPIO_InitTypeDef gpioInitStruct;
+ gpioInitStruct.GPIO_Pin = IMUF_EXTI_PIN;
+ gpioInitStruct.GPIO_Mode = GPIO_Mode_OUT;
+ gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
+ gpioInitStruct.GPIO_OType = GPIO_OType_PP;
+ gpioInitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(IMUF_EXTI_PORT, &gpioInitStruct);
+ #endif
+ //config pins
+ delay(200);
+
+ gpio_write_pin(IMUF_EXTI_PORT, IMUF_EXTI_PIN, 1); //set bl pin Hi
+ initImuf9001(); //reset imuf, make three blinks
+ resetImuf9001(); //reset imuf, make three blinks
+ resetImuf9001(); //reset imuf, make three blinks
+ delay(1000); //delay 100 ms. give IMUF BL time to look for bl init pin
+ gpio_write_pin(IMUF_EXTI_PORT, IMUF_EXTI_PIN, 0); //set bl pin Lo
+
+ //config EXTI as input so we can check imuf status
+ //config pins
+ #ifdef USE_HAL_F7_CRC
+ HAL_GPIO_DeInit(IMUF_EXTI_PORT, IMUF_EXTI_PIN);
+ GPIO_InitStruct.Pin = IMUF_EXTI_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStruct.Pull = GPIO_PULLDOWN;
+ GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
+
+ HAL_GPIO_Init(IMUF_EXTI_PORT, &GPIO_InitStruct);
+ #else
+ imufDeinitGpio(IMUF_EXTI_PORT, IMUF_EXTI_PIN);
+ gpioInitStruct.GPIO_Pin = IMUF_EXTI_PIN;
+ gpioInitStruct.GPIO_Mode = GPIO_Mode_IN;
+ gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
+ gpioInitStruct.GPIO_OType = GPIO_OType_PP;
+ gpioInitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;
+ GPIO_Init(IMUF_EXTI_PORT, &gpioInitStruct);
+ #endif
+ //config pins
+ delay(200);
+
+ if (imuf9001SendReceiveCommand(imufDev, BL_REPORT_INFO, &reply, &data))
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+volatile int checkCount = 0;
+
+int imufUpdate(uint8_t *buff, uint32_t bin_length)
+{
+ imufCommand_t reply;
+ imufCommand_t data;
+ memset(&data, 0, sizeof(data));
+
+ //check if BL is active
+ if (imuf9001SendReceiveCommand(imufDev, BL_REPORT_INFO, &reply, &data))
+ {
+ //erase firmware on MCU
+ if( imuf9001SendReceiveCommand(imufDev, BL_ERASE_ALL, &reply, &data) )
+ {
+ //good data
+ if( imuf9001SendReceiveCommand(imufDev, BL_PREPARE_PROGRAM, &reply, &data) )
+ {
+
+ //blink
+ for(uint32_t x = 0; x<10; x++)
+ {
+ LED0_TOGGLE;
+ delay(200);
+ }
+ LED0_OFF;
+
+ volatile uint32_t chunk_start = (uint32_t)buff;
+ for(uint32_t x=0;x<(bin_length);x+=32)
+ {
+ data.param1 = 0x08002000+x;
+ data.param2 = (*(__IO uint32_t *)(chunk_start+x));
+ data.param3 = (*(__IO uint32_t *)(chunk_start+x+4));
+ data.param4 = (*(__IO uint32_t *)(chunk_start+x+8));
+ data.param5 = (*(__IO uint32_t *)(chunk_start+x+12));
+ data.param6 = (*(__IO uint32_t *)(chunk_start+x+16));
+ data.param7 = (*(__IO uint32_t *)(chunk_start+x+20));
+ data.param8 = (*(__IO uint32_t *)(chunk_start+x+24));
+ data.param9 = (*(__IO uint32_t *)(chunk_start+x+28));
+
+ if( imuf9001SendReceiveCommand(imufDev, BL_WRITE_FIRMWARES, &reply, &data) )
+ {
+ //continue writing
+ LED0_TOGGLE;
+ }
+ else
+ {
+ //error handler
+ for(uint32_t x = 0; x<40; x++)
+ {
+ LED0_TOGGLE;
+ delay(200);
+ }
+ LED0_OFF;
+ return 0;
+ }
+ }
+
+ if (imuf9001SendReceiveCommand(imufDev, BL_END_PROGRAM, &reply, &data) )
+ {
+ //blink
+ for (uint32_t x = 0; x<40; x++)
+ {
+ LED0_TOGGLE;
+ delay(20);
+ }
+ LED0_OFF;
+ return 1;
+ }
+ }
+ else
+ {
+ checkCount++;
+ if (checkCount > 40)
+ {
+ checkCount = 0;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+int imuf9001Whoami(const busDevice_t *gyro)
+{
+ imufDev = (busDevice_t *)gyro;
+ uint32_t attempt;
+ imufCommand_t reply;
+
+ for (attempt = 0; attempt < 5; attempt++)
+ {
+ if (imuf9001SendReceiveCommand(gyro, IMUF_COMMAND_REPORT_INFO, &reply, NULL))
+ {
+ imufCurrentVersion = (*(imufVersion_t *)&(reply.param1)).firmware;
+ if (imufCurrentVersion >= IMUF_FIRMWARE_MIN_VERSION) {
+ return IMUF_9001_SPI;
+ }
+ }
+ }
+ imufCurrentVersion = 9999;
+ return 0;
+}
+
+uint8_t imuf9001SpiDetect(const busDevice_t *gyro)
+{
+ static bool hardwareInitialised = false;
+ int returnCheck;
+
+ if (hardwareInitialised) {
+ return(0);
+ }
+
+ //config crc
+ crcConfig();
+
+ //config exti as input, not exti for now
+ IOInit(IOGetByTag( IO_TAG(MPU_INT_EXTI) ), OWNER_GYRO_EXTI, 0);
+ IOConfigGPIO(IOGetByTag( IO_TAG(MPU_INT_EXTI) ), IOCFG_IPD);
+
+ delayMicroseconds(100);
+
+ IOInit(gyro->busdev_u.spi.csnPin, OWNER_GYRO_CS, 0);
+ IOConfigGPIO(gyro->busdev_u.spi.csnPin, SPI_IO_CS_CFG);
+ IOHi(gyro->busdev_u.spi.csnPin);
+
+ hardwareInitialised = true;
+
+ for (int x=0; x<3; x++)
+ {
+ if (x)
+ {
+ initImuf9001();
+ delay(200 * x);
+ }
+
+ returnCheck = imuf9001Whoami(gyro);
+ if(returnCheck)
+ {
+ return returnCheck;
+ }
+ }
+ return 0;
+}
+
+void imufSpiAccInit(accDev_t *acc)
+{
+ acc->acc_1G = 512 * 4;
+}
+
+static gyroToBoardCommMode_t VerifyAllowedCommMode(uint32_t commMode)
+{
+ switch (commMode)
+ {
+ case GTBCM_SETUP:
+ case GTBCM_GYRO_ONLY_PASSTHRU:
+ case GTBCM_GYRO_ACC_PASSTHRU:
+ case GTBCM_GYRO_ONLY_FILTER_F:
+ case GTBCM_GYRO_ACC_FILTER_F:
+ case GTBCM_GYRO_ACC_QUAT_FILTER_F:
+ return (gyroToBoardCommMode_t)commMode;
+ break;
+ default:
+ return GTBCM_DEFAULT;
+ }
+}
+
+uint16_t imufGyroAlignment(void)
+{
+ if (isBoardAlignmentStandard(boardAlignment()))
+ {
+ if(gyroConfig()->gyro_align <= 1)
+ {
+ return 0;
+ }
+ else
+ {
+ return (uint16_t)(gyroConfig()->gyro_align - 1);
+ }
+ }
+ else
+ {
+ return (uint16_t)IMU_CW0;
+ }
+}
+
+void setupImufParams(imufCommand_t * data)
+{
+ if (imufCurrentVersion < 107) {
+ //backwards compatibility for Caprica
+ data->param2 = ( (uint16_t)(gyroConfig()->imuf_rate+1) << 16 );
+ data->param3 = ( (uint16_t)gyroConfig()->imuf_pitch_q << 16 ) | (uint16_t)constrain(gyroConfig()->imuf_w, 6, 10);
+ data->param4 = ( (uint16_t)gyroConfig()->imuf_roll_q << 16 ) | (uint16_t)constrain(gyroConfig()->imuf_w, 6, 10);
+ data->param5 = ( (uint16_t)gyroConfig()->imuf_yaw_q << 16 ) | (uint16_t)constrain(gyroConfig()->imuf_w, 6, 10);
+ data->param6 = ( (uint16_t)gyroConfig()->imuf_pitch_lpf_cutoff_hz << 16) | (uint16_t)gyroConfig()->imuf_roll_lpf_cutoff_hz;
+ data->param7 = ( (uint16_t)gyroConfig()->imuf_yaw_lpf_cutoff_hz << 16) | (uint16_t)0;
+ data->param8 = ( (int16_t)boardAlignment()->rollDegrees << 16 ) | imufGyroAlignment();
+ data->param9 = ( (int16_t)boardAlignment()->yawDegrees << 16 ) | (int16_t)boardAlignment()->pitchDegrees;
+ } else {
+ //Odin contract.
+ data->param2 = ( (uint16_t)(gyroConfig()->imuf_rate+1) << 16) | (uint16_t)gyroConfig()->imuf_w;
+ data->param3 = ( (uint16_t)gyroConfig()->imuf_roll_q << 16) | (uint16_t)gyroConfig()->imuf_pitch_q;
+ data->param4 = ( (uint16_t)gyroConfig()->imuf_yaw_q << 16) | (uint16_t)gyroConfig()->imuf_roll_lpf_cutoff_hz;
+ data->param5 = ( (uint16_t)gyroConfig()->imuf_pitch_lpf_cutoff_hz << 16) | (uint16_t)gyroConfig()->imuf_yaw_lpf_cutoff_hz;
+ data->param6 = ( (uint32_t)((gyroConfig()->imuf_roll_af & 1) |
+ (gyroConfig()->imuf_pitch_af & 1) << 1 |
+ (gyroConfig()->imuf_yaw_af & 1) << 2 ));
+ data->param7 = ( (uint16_t)0 << 16) | (uint16_t)0;
+ data->param8 = ( (int16_t)boardAlignment()->rollDegrees << 16 ) | imufGyroAlignment();
+ data->param9 = ( (int16_t)boardAlignment()->yawDegrees << 16 ) | (int16_t)boardAlignment()->pitchDegrees;
+ }
+}
+
+void imufSpiGyroInit(gyroDev_t *gyro)
+{
+ uint32_t attempt = 0;
+ imufCommand_t txData;
+ imufCommand_t rxData;
+
+ rxData.param1 = VerifyAllowedCommMode(gyroConfig()->imuf_mode);
+
+ setupImufParams(&rxData);
+
+ for (attempt = 0; attempt < 10; attempt++)
+ {
+ if(attempt)
+ {
+ resetImuf9001();
+ delay(300 * attempt);
+ }
+
+ if (imuf9001SendReceiveCommand(&(gyro->bus), IMUF_COMMAND_SETUP, &txData, &rxData))
+ {
+ //enable EXTI
+ mpuGyroInit(gyro);
+ return;
+ }
+ }
+ setArmingDisabled(ARMING_DISABLED_NO_GYRO);
+}
+
+FAST_CODE bool imufReadAccData(accDev_t *acc) {
+ UNUSED(acc);
+ return true;
+}
+
+bool imufSpiAccDetect(accDev_t *acc)
+{
+ acc->initFn = imufSpiAccInit;
+ acc->readFn = imufReadAccData;
+
+ return true;
+}
+
+bool imufSpiGyroDetect(gyroDev_t *gyro)
+{
+ // MPU6500 is used as a equivalent of other gyros by some flight controllers
+ switch (gyro->mpuDetectionResult.sensor) {
+ case IMUF_9001_SPI:
+ break;
+ default:
+ return false;
+ }
+
+ gyro->initFn = imufSpiGyroInit;
+ gyro->scale = 1.0f;
+ return true;
+}
+
+FAST_CODE void imufStartCalibration(void)
+{
+ isImufCalibrating = IMUF_IS_CALIBRATING; //reset by EXTI
+}
+
+FAST_CODE void imufEndCalibration(void)
+{
+ isImufCalibrating = IMUF_NOT_CALIBRATING; //reset by EXTI
+}
+
+#endif
diff --git a/src/main/drivers/accgyro/accgyro_imuf9001.h b/src/main/drivers/accgyro/accgyro_imuf9001.h
new file mode 100755
index 000000000..4ae8ae079
--- /dev/null
+++ b/src/main/drivers/accgyro/accgyro_imuf9001.h
@@ -0,0 +1,235 @@
+/*
+ * This file is part of Cleanflight.
+ *
+ * Cleanflight is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Cleanflight 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "drivers/bus.h"
+
+uint8_t imuf9001SpiDetect(const busDevice_t *bus);
+
+bool imufSpiAccDetect(accDev_t *acc);
+bool imufSpiGyroDetect(gyroDev_t *gyro);
+
+void imufSpiGyroInit(gyroDev_t *gyro);
+void imufSpiAccInit(accDev_t *acc);
+
+void imufStartCalibration(void);
+void imufEndCalibration(void);
+
+#ifndef IMUF_DEFAULT_PITCH_Q
+#define IMUF_DEFAULT_PITCH_Q 3000
+#endif
+#ifndef IMUF_DEFAULT_ROLL_Q
+#define IMUF_DEFAULT_ROLL_Q 3000
+#endif
+#ifndef IMUF_DEFAULT_YAW_Q
+#define IMUF_DEFAULT_YAW_Q 3000
+#endif
+#ifndef IMUF_IMUF_W
+#define IMUF_IMUF_W 32
+#endif
+#ifndef IMUF_DEFAULT_ROLL_AF
+#define IMUF_DEFAULT_ROLL_AF 0
+#endif
+#ifndef IMUF_DEFAULT_PITCH_AF
+#define IMUF_DEFAULT_PITCH_AF 0
+#endif
+#ifndef IMUF_DEFAULT_YAW_AF
+#define IMUF_DEFAULT_YAW_AF 0
+#endif
+
+
+#define IMUF_FIRMWARE_MIN_VERSION 106
+extern volatile uint16_t imufCurrentVersion;
+typedef struct imufVersion
+{
+ uint32_t hardware;
+ uint32_t firmware;
+ uint32_t bootloader;
+ uint32_t uid1;
+ uint32_t uid2;
+ uint32_t uid3;
+} __attribute__((__packed__)) imufVersion_t;
+
+typedef struct imufCommand {
+ uint32_t command;
+ uint32_t param1;
+ uint32_t param2;
+ uint32_t param3;
+ uint32_t param4;
+ uint32_t param5;
+ uint32_t param6;
+ uint32_t param7;
+ uint32_t param8;
+ uint32_t param9;
+ uint32_t param10;
+ uint32_t crc;
+ uint32_t tail;
+} __attribute__ ((__packed__)) imufCommand_t;
+
+typedef struct imufData
+{
+ float gyroX;
+ float gyroY;
+ float gyroZ;
+ float accX;
+ float accY;
+ float accZ;
+ float tempC;
+ float quaternionW;
+ float quaternionX;
+ float quaternionY;
+ float quaternionZ;
+ uint32_t crc;
+ uint32_t tail;
+} __attribute__((__packed__)) imufData_t;
+
+typedef enum gyroCommands
+{
+ BL_ERASE_ALL = 22,
+ BL_REPORT_INFO = 24,
+ BL_WRITE_FIRMWARES = 29,
+ BL_PREPARE_PROGRAM = 30,
+ BL_END_PROGRAM = 31,
+ BL_LISTENING = 32,
+ IMUF_COMMAND_NONE = 0,
+ IMUF_COMMAND_CALIBRATE = 99,
+ IMUF_COMMAND_LISTENING = 108,
+ IMUF_COMMAND_REPORT_INFO = 121,
+ IMUF_COMMAND_SETUP = 122,
+ IMUF_COMMAND_SETPOINT = 126,
+ IMUF_COMMAND_RESTART = 127
+} gyroCommands_t;
+
+typedef struct gyroFrame
+{
+ float gyroX;
+ float gyroY;
+ float gyroZ;
+ float accelX;
+ float accelY;
+ float accelZ;
+ float temp;
+} __attribute__((__packed__)) gyroFrame_t;
+
+typedef struct imuFrame
+{
+ float w;
+ float x;
+ float y;
+ float z;
+} __attribute__((__packed__)) imuFrame_t;
+
+typedef struct imuCommFrame
+{
+ gyroFrame_t gyroFrame;
+ imuFrame_t imuFrame;
+ uint32_t tail;
+} __attribute__((__packed__)) imuCommFrame_t;
+
+typedef enum imufLoopHz
+{
+ IMUF_32000 = 0,
+ IMUF_16000 = 1,
+ IMUF_8000 = 2,
+ IMUF_4000 = 3,
+ IMUF_2000 = 4,
+ IMUF_1000 = 5,
+ IMUF_500 = 6,
+ IMUF_250 = 7,
+} imufLoopHz_t;
+
+typedef enum imufOutput
+{
+ IMUF_GYRO_OUTPUT = 1 << 0,
+ IMUF_TEMP_OUTPUT = 1 << 1,
+ IMUF_ACC_OUTPUT = 1 << 2,
+ IMUF_QUAT_OUTPUT = 1 << 3,
+} imufOutput_t;
+
+typedef enum imufOreintation
+{
+ IMU_CW0 = 0,
+ IMU_CW90 = 1,
+ IMU_CW180 = 2,
+ IMU_CW270 = 3,
+ IMU_CW0_INV = 4,
+ IMU_CW90_INV = 5,
+ IMU_CW180_INV = 6,
+ IMU_CW270_INV = 7,
+ IMU_CW45 = 8,
+ IMU_CW135 = 9,
+ IMU_CW225 = 10,
+ IMU_CW315 = 11,
+ IMU_CW45_INV = 12,
+ IMU_CW135_INV = 13,
+ IMU_CW225_INV = 14,
+ IMU_CW315_INV = 15,
+ IMU_CUSTOM = 16,
+} imufOrientation_t;
+
+typedef struct imufMode
+{
+ uint8_t command; //output Hz
+ uint8_t hz; //output Hz
+ uint8_t dataOut; //what data to send
+ uint8_t filterLevelX; //what filter level, 0% to 100% as a uint8_t
+ uint8_t filterLevelY; //what filter level, 0% to 100% as a uint8_t
+ uint8_t filterLevelZ; //what filter level, 0% to 100% as a uint8_t
+ uint8_t orientation; //what orienetation is the IMU? 0 gives raw output, if you want to use quats this must be set right
+ uint16_t rotationX; //custom orientation X, used when orientation is set to IMU_CUSTOM
+ uint16_t rotationY; //custom orientation Y, used when orientation is set to IMU_CUSTOM
+ uint16_t rotationZ; //custom orientation Z, used when orientation is set to IMU_CUSTOM
+ uint8_t param4; //future parameters
+ uint8_t param5; //future parameters
+ uint8_t param6; //future parameters
+ uint8_t param7; //future parameters
+ uint8_t param8; //future parameters
+} __attribute__((__packed__)) imufMode_t;
+
+typedef enum gyroToBoardCommMode
+{
+ GTBCM_SETUP = 53, //setup
+ GTBCM_GYRO_ONLY_PASSTHRU = 6, //no crc, gyro, 3*2 bytes
+ GTBCM_GYRO_ACC_PASSTHRU = 14, //no crc, acc, temp, gyro, 3*2, 1*2, 3*2 bytes
+ GTBCM_GYRO_ONLY_FILTER_F = 20, //gyro filtered, 3*4 bytes, 4 bytes crc
+ GTBCM_GYRO_ACC_FILTER_F = 32, //gyro filtered, acc filtered, temp, crc
+ GTBCM_GYRO_ACC_QUAT_FILTER_F = 48, //gyro filtered, acc filtered, temp, quaternions filtered, crc
+ GTBCM_DEFAULT = GTBCM_GYRO_ACC_QUAT_FILTER_F, //default mode
+} gyroToBoardCommMode_t;
+
+typedef enum imufCalibrationSteps
+{
+ IMUF_NOT_CALIBRATING = 0,
+ IMUF_IS_CALIBRATING = 1,
+ IMUF_DONE_CALIBRATING = 2
+
+} imufCalibrationSteps_t;
+
+typedef enum gpioState
+{
+ GPIO_LO = 0,
+ GPIO_HI = 1
+} gpioState_t;
+
+extern volatile imuFrame_t imufQuat;
+extern volatile uint32_t isImufCalibrating;
+
+extern void initImuf9001(void);
+extern uint32_t getCrcImuf9001(uint32_t* data, uint32_t size);
+extern int imufUpdate(uint8_t *buff, uint32_t bin_length);
+extern int imufBootloader(void);
\ No newline at end of file
diff --git a/src/main/drivers/accgyro/accgyro_mpu.c b/src/main/drivers/accgyro/accgyro_mpu.c
index 5f0dfae6c..e3b608aa7 100644
--- a/src/main/drivers/accgyro/accgyro_mpu.c
+++ b/src/main/drivers/accgyro/accgyro_mpu.c
@@ -42,6 +42,13 @@
#include "drivers/system.h"
#include "drivers/time.h"
+// HELIOSPRING
+#ifdef USE_DMA_SPI_DEVICE
+#include "drivers/dma_spi.h"
+#include "sensors/gyro.h"
+#include "sensors/acceleration.h"
+#endif //USE_DMA_SPI_DEVICE
+
#include "drivers/accgyro/accgyro.h"
#include "drivers/accgyro/accgyro_mpu3050.h"
#include "drivers/accgyro/accgyro_mpu6050.h"
@@ -55,9 +62,22 @@
#include "drivers/accgyro/accgyro_spi_l3gd20.h"
#include "drivers/accgyro/accgyro_mpu.h"
+// HELIOSPRING
+#ifdef USE_GYRO_IMUF9001
+#include "drivers/accgyro/accgyro_imuf9001.h"
+#include "rx/rx.h"
+#include "fc/rc.h"
+#include "fc/runtime_config.h"
+#endif //USE_GYRO_IMUF9001
+
#include "pg/pg.h"
#include "pg/gyrodev.h"
+// HELIOSPRING
+#ifdef USE_GYRO_IMUF9001
+ imufData_t imufData;
+#endif
+
#ifndef MPU_ADDRESS
#define MPU_ADDRESS 0x68
#endif
@@ -106,6 +126,11 @@ static void mpu6050FindRevision(gyroDev_t *gyro)
#ifdef USE_GYRO_EXTI
static void mpuIntExtiHandler(extiCallbackRec_t *cb)
{
+#ifdef USE_DMA_SPI_DEVICE // HELIOSPRING
+ //start dma read
+ (void)(cb);
+ gyroDmaSpiStartRead();
+#else // not HELIOSPRING
#ifdef DEBUG_MPU_DATA_READY_INTERRUPT
static uint32_t lastCalledAtUs = 0;
const uint32_t nowUs = micros();
@@ -118,6 +143,7 @@ static void mpuIntExtiHandler(extiCallbackRec_t *cb)
const uint32_t now2Us = micros();
debug[1] = (uint16_t)(now2Us - nowUs);
#endif
+#endif // USE_DMA_SPI_DEVICE // HELIOSPRING
}
static void mpuIntExtiInit(gyroDev_t *gyro)
@@ -134,8 +160,34 @@ static void mpuIntExtiInit(gyroDev_t *gyro)
return;
}
#endif
-
+ // original code
+ // IOInit(mpuIntIO, OWNER_GYRO_EXTI, 0);
+ // EXTIHandlerInit(&gyro->exti, mpuIntExtiHandler);
+ // EXTIConfig(mpuIntIO, &gyro->exti, NVIC_PRIO_MPU_INT_EXTI, IOCFG_IN_FLOATING, EXTI_TRIGGER_RISING);
+ // EXTIEnable(mpuIntIO, true);
+
+ // robert's spaghetti
+// #if defined (STM32F7)
+// IOInit(mpuIntIO, OWNER_GYRO_EXTI, 0);
+// EXTIHandlerInit(&gyro->exti, mpuIntExtiHandler);
+// // EXTIConfig(mpuIntIO, &gyro->exti, NVIC_PRIO_MPU_INT_
+// GPIO_MODE_INPUT,0,GPIO_NOPULL)); // TODO - maybe pull
+// EXTIConfig(mpuIntIO, &gyro->exti, NVIC_PRIO_MPU_INT_EX
+// EXTI_TRIGGER_RISING);
+// #else
+// IOInit(mpuIntIO, OWNER_GYRO_EXTI, 0);
+// IOConfigGPIO(mpuIntIO, IOCFG_IN_FLOATING); // TODO -
+// EXTIHandlerInit(&gyro->exti, mpuIntExtiHandler);
+// EXTIConfig(mpuIntIO, &gyro->exti, NVIC_PRIO_MPU_INT_EX
+// EXTI_TRIGGER_RISING);
+// #endif
+// EXTIEnable(mpuIntIO, true);
+
+// Fixed logic based on robert's
IOInit(mpuIntIO, OWNER_GYRO_EXTI, 0);
+#if !defined (STM32F7)
+ IOConfigGPIO(mpuIntIO, IOCFG_IN_FLOATING); // TODO - maybe pullup / pulldown ?
+#endif
EXTIHandlerInit(&gyro->exti, mpuIntExtiHandler);
EXTIConfig(mpuIntIO, &gyro->exti, NVIC_PRIO_MPU_INT_EXTI, IOCFG_IN_FLOATING, EXTI_TRIGGER_RISING);
EXTIEnable(mpuIntIO, true);
@@ -174,6 +226,84 @@ bool mpuGyroRead(gyroDev_t *gyro)
return true;
}
+// HELIOSPRING
+#ifdef USE_DMA_SPI_DEVICE
+FAST_CODE bool mpuGyroDmaSpiReadStart(gyroDev_t * gyro)
+{
+ (void)(gyro); ///not used at this time
+ //no reason not to get acc and gyro data at the same time
+#ifdef USE_GYRO_IMUF9001
+ if (isImufCalibrating == IMUF_IS_CALIBRATING) //calibrating
+ {
+ //two steps
+ //step 1 is isImufCalibrating=1, this starts the calibration command and sends it to the IMU-f
+ //step 2 is isImufCalibrating=2, this sets the tx buffer back to 0 so we don't keep sending the calibration command over and over
+ memset(dmaTxBuffer, 0, sizeof(imufCommand_t)); //clear buffer
+ //set calibration command with CRC, typecast the dmaTxBuffer as imufCommand_t
+ (*(imufCommand_t *)(dmaTxBuffer)).command = IMUF_COMMAND_CALIBRATE;
+ (*(imufCommand_t *)(dmaTxBuffer)).crc = getCrcImuf9001((uint32_t *)dmaTxBuffer, 11); //typecast the dmaTxBuffer as a uint32_t array which is what the crc command needs
+ //set isImufCalibrating to step 2, which is just used so the memset to 0 runs after the calibration commmand is sent
+ isImufCalibrating = IMUF_DONE_CALIBRATING; //go to step two
+ }
+ else if (isImufCalibrating == IMUF_DONE_CALIBRATING)
+ {
+ // step 2, memset of the tx buffer has run, set isImufCalibrating to 0.
+ (*(imufCommand_t *)(dmaTxBuffer)).command = 0;
+ (*(imufCommand_t *)(dmaTxBuffer)).crc = 0; //typecast the dmaTxBuffer as a uint32_t array which is what the crc command needs
+ imufEndCalibration();
+ }
+ else
+ {
+ if (isSetpointNew) {
+ //send setpoint and arm status
+ (*(imufCommand_t *)(dmaTxBuffer)).command = IMUF_COMMAND_SETPOINT;
+ (*(imufCommand_t *)(dmaTxBuffer)).param1 = getSetpointRateInt(0);
+ (*(imufCommand_t *)(dmaTxBuffer)).param2 = getSetpointRateInt(1);
+ (*(imufCommand_t *)(dmaTxBuffer)).param3 = getSetpointRateInt(2);
+ (*(imufCommand_t *)(dmaTxBuffer)).crc = getCrcImuf9001((uint32_t *)dmaTxBuffer, 11); //typecast the dmaTxBuffer as a uint32_t array which is what the crc command needs
+ isSetpointNew = 0;
+ }
+ }
+ memset(dmaRxBuffer, 0, gyroConfig()->imuf_mode); //clear buffer
+ //send and receive data using SPI and DMA
+ dmaSpiTransmitReceive(dmaTxBuffer, dmaRxBuffer, gyroConfig()->imuf_mode, 0);
+#else
+ dmaTxBuffer[0] = MPU_RA_ACCEL_XOUT_H | 0x80;
+ dmaSpiTransmitReceive(dmaTxBuffer, dmaRxBuffer, 15, 0);
+#endif // USE_GYRO_IMUF9001
+ return true;
+}
+FAST_CODE void mpuGyroDmaSpiReadFinish(gyroDev_t * gyro)
+{
+ //spi rx dma callback
+#ifdef USE_GYRO_IMUF9001
+ memcpy(&imufData, dmaRxBuffer, sizeof(imufData_t));
+ acc.dev.ADCRaw[X] = (int16_t)(imufData.accX * acc.dev.acc_1G);
+ acc.dev.ADCRaw[Y] = (int16_t)(imufData.accY * acc.dev.acc_1G);
+ acc.dev.ADCRaw[Z] = (int16_t)(imufData.accZ * acc.dev.acc_1G);
+ gyro->gyroADC[X] = imufData.gyroX;
+ gyro->gyroADC[Y] = imufData.gyroY;
+ gyro->gyroADC[Z] = imufData.gyroZ;
+ gyro->gyroADCRaw[X] = (int16_t)(imufData.gyroX * 16.4f);
+ gyro->gyroADCRaw[Y] = (int16_t)(imufData.gyroY * 16.4f);
+ gyro->gyroADCRaw[Z] = (int16_t)(imufData.gyroZ * 16.4f);
+ if (gyroConfig()->imuf_mode == GTBCM_GYRO_ACC_QUAT_FILTER_F) {
+ imufQuat.w = imufData.quaternionW;
+ imufQuat.x = imufData.quaternionX;
+ imufQuat.y = imufData.quaternionY;
+ imufQuat.z = imufData.quaternionZ;
+ }
+#else
+ acc.dev.ADCRaw[X] = (int16_t)((dmaRxBuffer[1] << 8) | dmaRxBuffer[2]);
+ acc.dev.ADCRaw[Y] = (int16_t)((dmaRxBuffer[3] << 8) | dmaRxBuffer[4]);
+ acc.dev.ADCRaw[Z] = (int16_t)((dmaRxBuffer[5] << 8) | dmaRxBuffer[6]);
+ gyro->gyroADCRaw[X] = (int16_t)((dmaRxBuffer[9] << 8) | dmaRxBuffer[10]);
+ gyro->gyroADCRaw[Y] = (int16_t)((dmaRxBuffer[11] << 8) | dmaRxBuffer[12]);
+ gyro->gyroADCRaw[Z] = (int16_t)((dmaRxBuffer[13] << 8) | dmaRxBuffer[14]);
+#endif // USE_GYRO_IMUF9001
+}
+#endif
+
#ifdef USE_SPI_GYRO
bool mpuGyroReadSPI(gyroDev_t *gyro)
{
@@ -201,6 +331,9 @@ static gyroSpiDetectFn_t gyroSpiDetectFnTable[] = {
#ifdef USE_GYRO_SPI_MPU6500
mpu6500SpiDetect, // some targets using MPU_9250_SPI, ICM_20608_SPI or ICM_20602_SPI state sensor is MPU_65xx_SPI
#endif
+#ifdef USE_GYRO_IMUF9001 // HELIOSPRING
+ imuf9001SpiDetect,
+#endif
#ifdef USE_GYRO_SPI_MPU9250
mpu9250SpiDetect,
#endif
@@ -280,7 +413,7 @@ bool mpuDetect(gyroDev_t *gyro, const gyroDeviceConfig_t *config)
gyro->bus.bustype = config->bustype;
}
-#ifdef USE_I2C_GYRO
+#ifdef USE_I2C_GYRO && !defined(USE_DMA_SPI_DEVICE) // HELIOSPRING (&& !def)
if (gyro->bus.bustype == BUSTYPE_I2C) {
gyro->bus.busdev_u.i2c.device = I2C_CFG_TO_DEV(config->i2cBus);
gyro->bus.busdev_u.i2c.address = config->i2cAddress ? config->i2cAddress : MPU_ADDRESS;
diff --git a/src/main/drivers/accgyro/accgyro_mpu.h b/src/main/drivers/accgyro/accgyro_mpu.h
index a90fa2f01..285ea8f67 100644
--- a/src/main/drivers/accgyro/accgyro_mpu.h
+++ b/src/main/drivers/accgyro/accgyro_mpu.h
@@ -200,6 +200,7 @@ typedef enum {
ICM_20689_SPI,
BMI_160_SPI,
L3GD20_SPI,
+ IMUF_9001_SPI, // HELIOSPRING
} mpuSensor_e;
typedef enum {
@@ -224,3 +225,9 @@ uint8_t mpuGyroReadRegister(const busDevice_t *bus, uint8_t reg);
struct accDev_s;
bool mpuAccRead(struct accDev_s *acc);
+
+// HELIOSPRING
+#ifdef USE_DMA_SPI_DEVICE
+extern bool mpuGyroDmaSpiReadStart(struct gyroDev_s *gyro);
+extern void mpuGyroDmaSpiReadFinish(struct gyroDev_s *gyro);
+#endif
diff --git a/src/main/drivers/bus.c b/src/main/drivers/bus.c
index 45ec93683..b2b20e2a0 100644
--- a/src/main/drivers/bus.c
+++ b/src/main/drivers/bus.c
@@ -29,6 +29,9 @@
bool busWriteRegister(const busDevice_t *busdev, uint8_t reg, uint8_t data)
{
+#ifdef USE_DMA_SPI_DEVICE // HELIOSPRING
+ return spiBusWriteRegister(busdev, reg & 0x7f, data);
+#else // not HELIOSPRING
#if !defined(USE_SPI) && !defined(USE_I2C)
UNUSED(reg);
UNUSED(data);
@@ -50,8 +53,10 @@ bool busWriteRegister(const busDevice_t *busdev, uint8_t reg, uint8_t data)
default:
return false;
}
+#endif // not HELIOSPRING
}
+
bool busWriteRegisterStart(const busDevice_t *busdev, uint8_t reg, uint8_t data)
{
#if !defined(USE_SPI) && !defined(USE_I2C)
@@ -157,6 +162,11 @@ bool busBusy(const busDevice_t *busdev, bool *error)
uint8_t busReadRegister(const busDevice_t *busdev, uint8_t reg)
{
+#ifdef USE_DMA_SPI_DEVICE // HELIOSPRING
+ uint8_t data;
+ busReadRegisterBuffer(busdev, reg, &data, 1);
+ return data;
+#else // not HELIOSPRING
#if !defined(USE_SPI) && !defined(USE_I2C)
UNUSED(busdev);
UNUSED(reg);
@@ -166,4 +176,5 @@ uint8_t busReadRegister(const busDevice_t *busdev, uint8_t reg)
busReadRegisterBuffer(busdev, reg, &data, 1);
return data;
#endif
+#endif // HELIOSPRING
}
diff --git a/src/main/drivers/bus_spi.c b/src/main/drivers/bus_spi.c
index 5f869b37f..e3bd5093a 100644
--- a/src/main/drivers/bus_spi.c
+++ b/src/main/drivers/bus_spi.c
@@ -33,6 +33,15 @@
#include "drivers/io.h"
#include "drivers/rcc.h"
+// HELIOSPRING
+#ifdef USE_DMA_SPI_DEVICE
+#ifndef GYRO_READ_TIMEOUT
+ #define GYRO_READ_TIMEOUT 20
+#endif //GYRO_READ_TIMEOUT
+#include "drivers/dma_spi.h"
+#include "drivers/time.h"
+#endif //USE_DMA_SPI_DEVICE
+
spiDevice_t spiDevice[SPIDEV_COUNT];
SPIDevice spiDeviceByInstance(SPI_TypeDef *instance)
@@ -138,9 +147,37 @@ uint32_t spiTimeoutUserCallback(SPI_TypeDef *instance)
bool spiBusTransfer(const busDevice_t *bus, const uint8_t *txData, uint8_t *rxData, int length)
{
+#ifdef USE_DMA_SPI_DEVICE // HELIOSPRING
+ if(USE_DMA_SPI_DEVICE == bus->busdev_u.spi.instance)
+ {
+ uint32_t timeoutCheck = millis();
+ memcpy(dmaTxBuffer, (uint8_t *)txData, length);
+ dmaSpiTransmitReceive(dmaTxBuffer, dmaRxBuffer, length, 1);
+ while(dmaSpiReadStatus != DMA_SPI_READ_DONE)
+ {
+ if(millis() - timeoutCheck > GYRO_READ_TIMEOUT)
+ {
+ //GYRO_READ_TIMEOUT ms max, read failed, cleanup spi and return 0
+ IOHi(bus->busdev_u.spi.csnPin);
+ #ifndef STM32F7
+ dmaSpicleanupspi();
+ #endif //STM32F7
+ return false;
+ }
+ }
+ memcpy((uint8_t *)rxData, dmaRxBuffer, length);
+ }
+ else
+ {
+ IOLo(bus->busdev_u.spi.csnPin);
+ spiTransfer(bus->busdev_u.spi.instance, txData, rxData, length);
+ IOHi(bus->busdev_u.spi.csnPin);
+ }
+#else // not HELIOSPRING
IOLo(bus->busdev_u.spi.csnPin);
spiTransfer(bus->busdev_u.spi.instance, txData, rxData, length);
IOHi(bus->busdev_u.spi.csnPin);
+#endif // HELIOSPRING
return true;
}
@@ -185,21 +222,77 @@ bool spiBusRawTransfer(const busDevice_t *bus, const uint8_t *txData, uint8_t *r
bool spiBusWriteRegister(const busDevice_t *bus, uint8_t reg, uint8_t data)
{
+#ifdef USE_DMA_SPI_DEVICE // HELIOSPRING
+ if(USE_DMA_SPI_DEVICE == bus->busdev_u.spi.instance)
+ {
+ uint32_t timeoutCheck = millis();
+ dmaTxBuffer[0] = reg;
+ dmaTxBuffer[1] = data;
+ dmaSpiTransmitReceive(dmaTxBuffer, dmaRxBuffer, 2, 1);
+ while(dmaSpiReadStatus != DMA_SPI_READ_DONE)
+ {
+ if(millis() - timeoutCheck > GYRO_READ_TIMEOUT)
+ {
+ //GYRO_READ_TIMEOUT ms max, read failed, cleanup spi and return 0
+ IOHi(bus->busdev_u.spi.csnPin);
+ #ifndef STM32F7
+ dmaSpicleanupspi();
+ #endif //STM32F7
+ return false;
+ }
+ }
+ }
+ else
+ {
+ IOLo(bus->busdev_u.spi.csnPin);
+ spiTransferByte(bus->busdev_u.spi.instance, reg);
+ spiTransferByte(bus->busdev_u.spi.instance, data);
+ IOHi(bus->busdev_u.spi.csnPin);
+ }
+#else // not HELIOSPRING
IOLo(bus->busdev_u.spi.csnPin);
spiTransferByte(bus->busdev_u.spi.instance, reg);
spiTransferByte(bus->busdev_u.spi.instance, data);
IOHi(bus->busdev_u.spi.csnPin);
-
+#endif // not HELIOSPRING
return true;
}
bool spiBusRawReadRegisterBuffer(const busDevice_t *bus, uint8_t reg, uint8_t *data, uint8_t length)
{
+#ifdef USE_DMA_SPI_DEVICE // HELIOSPRING
+ if(USE_DMA_SPI_DEVICE == bus->busdev_u.spi.instance)
+ {
+ uint32_t timeoutCheck = millis();
+ dmaTxBuffer[0] = reg | 0x80;
+ dmaSpiTransmitReceive(dmaTxBuffer, dmaRxBuffer, length+1, 1);
+ while(dmaSpiReadStatus != DMA_SPI_READ_DONE)
+ {
+ if(millis() - timeoutCheck > GYRO_READ_TIMEOUT)
+ {
+ //GYRO_READ_TIMEOUT ms max, read failed, cleanup spi and return 0
+ IOHi(bus->busdev_u.spi.csnPin);
+ #ifndef STM32F7
+ dmaSpicleanupspi();
+ #endif //STM32F7
+ return false;
+ }
+ }
+ memcpy(data, dmaRxBuffer+1, length);
+ }
+ else
+ {
+ IOLo(bus->busdev_u.spi.csnPin);
+ spiTransferByte(bus->busdev_u.spi.instance, reg);
+ spiTransfer(bus->busdev_u.spi.instance, NULL, data, length);
+ IOHi(bus->busdev_u.spi.csnPin);
+ }
+#else //not HELIOSPRING
IOLo(bus->busdev_u.spi.csnPin);
spiTransferByte(bus->busdev_u.spi.instance, reg);
spiTransfer(bus->busdev_u.spi.instance, NULL, data, length);
IOHi(bus->busdev_u.spi.csnPin);
-
+#endif // not HELIOSPRING
return true;
}
@@ -218,6 +311,36 @@ void spiBusWriteRegisterBuffer(const busDevice_t *bus, uint8_t reg, const uint8_
uint8_t spiBusRawReadRegister(const busDevice_t *bus, uint8_t reg)
{
+#ifdef USE_DMA_SPI_DEVICE // HELIOSPRING
+ if(USE_DMA_SPI_DEVICE == bus->busdev_u.spi.instance)
+ {
+ uint32_t timeoutCheck = millis();
+ dmaTxBuffer[0] = reg | 0x80;
+ dmaSpiTransmitReceive(dmaTxBuffer, dmaRxBuffer, 2, 1);
+ while(dmaSpiReadStatus != DMA_SPI_READ_DONE)
+ {
+ if(millis() - timeoutCheck > GYRO_READ_TIMEOUT)
+ {
+ //GYRO_READ_TIMEOUT ms max, read failed, cleanup spi and return 0
+ IOHi(bus->busdev_u.spi.csnPin);
+ #ifndef STM32F7
+ dmaSpicleanupspi();
+ #endif //STM32F7
+ return 0;
+ }
+ }
+ return dmaRxBuffer[1];
+ }
+ else
+ {
+ uint8_t data;
+ IOLo(bus->busdev_u.spi.csnPin);
+ spiTransferByte(bus->busdev_u.spi.instance, reg);
+ spiTransfer(bus->busdev_u.spi.instance, NULL, &data, 1);
+ IOHi(bus->busdev_u.spi.csnPin);
+ return data;
+ }
+#else // not HELIOSPRING
uint8_t data;
IOLo(bus->busdev_u.spi.csnPin);
spiTransferByte(bus->busdev_u.spi.instance, reg);
@@ -225,6 +348,7 @@ uint8_t spiBusRawReadRegister(const busDevice_t *bus, uint8_t reg)
IOHi(bus->busdev_u.spi.csnPin);
return data;
+#endif // not HELIOSPRING
}
uint8_t spiBusReadRegister(const busDevice_t *bus, uint8_t reg)
diff --git a/src/main/drivers/dma_spi.c b/src/main/drivers/dma_spi.c
new file mode 100755
index 000000000..d475840d5
--- /dev/null
+++ b/src/main/drivers/dma_spi.c
@@ -0,0 +1,227 @@
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "platform.h"
+#include "dma_spi.h"
+#include "common/time.h"
+#include "sensors/gyro.h"
+#include "drivers/accgyro/accgyro.h"
+#include "drivers/accgyro/accgyro_mpu.h"
+#ifdef USE_GYRO_IMUF9001
+#include "drivers/accgyro/accgyro_imuf9001.h"
+volatile uint32_t crcErrorCount = 0;
+#endif
+
+
+#ifdef USE_DMA_SPI_DEVICE
+
+volatile bool dmaSpiDeviceDataReady = false;
+volatile dma_spi_read_status_t dmaSpiReadStatus = DMA_SPI_READ_UNKNOWN;
+
+//must be static to avoid overflow/corruption by DMA
+uint8_t dmaTxBuffer[58];
+uint8_t dmaRxBuffer[58];
+
+static inline void gpio_write_pin(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin, uint32_t pinState)
+{
+ if (pinState != 0)
+ {
+ GPIOx->BSRRL = (uint32_t)GPIO_Pin;
+ }
+ else
+ {
+ GPIOx->BSRRH = (uint32_t)GPIO_Pin;
+ }
+}
+
+static inline void dmaSpiCsLo(void)
+{
+ gpio_write_pin(DMA_SPI_NSS_PORT, DMA_SPI_NSS_PIN, 0);
+}
+
+static inline void dmaSpiCsHi(void)
+{
+ gpio_write_pin(DMA_SPI_NSS_PORT, DMA_SPI_NSS_PIN, 1);
+}
+
+void dmaSpicleanupspi(void)
+{
+ //clear DMA flags
+ DMA_ClearFlag(DMA_SPI_TX_DMA_STREAM, DMA_SPI_TX_DMA_FLAG_ALL);
+ DMA_ClearFlag(DMA_SPI_RX_DMA_STREAM, DMA_SPI_RX_DMA_FLAG_ALL);
+
+ //disable DMAs
+ DMA_Cmd(DMA_SPI_TX_DMA_STREAM,DISABLE);
+ DMA_Cmd(DMA_SPI_RX_DMA_STREAM,DISABLE);
+
+ //disable SPI DMA requests
+ SPI_I2S_DMACmd(DMA_SPI_SPI, SPI_I2S_DMAReq_Tx, DISABLE);
+ SPI_I2S_DMACmd(DMA_SPI_SPI, SPI_I2S_DMAReq_Rx, DISABLE);
+
+ // Reset SPI (clears TXFIFO).
+
+ //disable SPI
+ SPI_Cmd(DMA_SPI_SPI, DISABLE);
+}
+
+void DMA_SPI_RX_DMA_HANDLER(void)
+{
+ dmaSpiCsHi();
+ dmaSpicleanupspi();
+
+ //spi rx dma callback
+ #ifdef USE_GYRO_IMUF9001
+ volatile uint32_t crc1 = ( (*(uint32_t *)(dmaRxBuffer+gyroConfig()->imuf_mode-4)) & 0xFF );
+ volatile uint32_t crc2 = ( getCrcImuf9001((uint32_t *)(dmaRxBuffer), (gyroConfig()->imuf_mode >> 2)-1) & 0xFF );
+ if(crc1 == crc2)
+ {
+ if(dmaSpiReadStatus != DMA_SPI_BLOCKING_READ_IN_PROGRESS)
+ {
+ gyroDmaSpiFinishRead();
+ }
+ dmaSpiDeviceDataReady = true;
+ }
+ else
+ {
+ if (crcErrorCount > 100000)
+ {
+ crcErrorCount = 0;
+ }
+ //error handler
+ crcErrorCount++; //check every so often and cause a failsafe is this number is above a certain amount
+ }
+ #else
+ if(dmaSpiReadStatus != DMA_SPI_BLOCKING_READ_IN_PROGRESS)
+ {
+ gyroDmaSpiFinishRead();
+ }
+ dmaSpiDeviceDataReady = true;
+ #endif
+ DMA_ClearITPendingBit(DMA_SPI_RX_DMA_STREAM, DMA_SPI_RX_DMA_FLAG_TC);
+ dmaSpiReadStatus = DMA_SPI_READ_DONE;
+}
+
+bool isDmaSpiDataReady(timeUs_t currentTimeUs, timeDelta_t currentDeltaTimeUs)
+{
+ (void)(currentTimeUs);
+ (void)(currentDeltaTimeUs);
+ return dmaSpiDeviceDataReady;
+}
+
+void dmaSpiInit(void)
+{
+ GPIO_InitTypeDef gpioInitStruct;
+ SPI_InitTypeDef spiInitStruct;
+ DMA_InitTypeDef dmaInitStruct;
+ NVIC_InitTypeDef nvicInitStruct;
+
+ //reset SPI periphreal
+ DMA_SPI_PER |= DMA_SPI_RST_MSK;
+ DMA_SPI_PER &= ~DMA_SPI_RST_MSK;
+
+ //config pins
+ gpioInitStruct.GPIO_Pin = DMA_SPI_NSS_PIN;
+ gpioInitStruct.GPIO_Mode = GPIO_Mode_OUT;
+ gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
+ gpioInitStruct.GPIO_OType = GPIO_OType_PP;
+ gpioInitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;
+ GPIO_Init(DMA_SPI_NSS_PORT, &gpioInitStruct);
+
+ //set default CS state (high)
+ GPIO_SetBits(DMA_SPI_NSS_PORT, DMA_SPI_NSS_PIN);
+
+ gpioInitStruct.GPIO_Mode = GPIO_Mode_AF;
+ gpioInitStruct.GPIO_Pin = DMA_SPI_SCK_PIN;
+ GPIO_Init(DMA_SPI_SCK_PORT, &gpioInitStruct);
+
+ gpioInitStruct.GPIO_Pin = DMA_SPI_MISO_PIN;
+ GPIO_Init(DMA_SPI_MISO_PORT, &gpioInitStruct);
+
+ gpioInitStruct.GPIO_Pin = DMA_SPI_MOSI_PIN;
+ GPIO_Init(DMA_SPI_MOSI_PORT, &gpioInitStruct);
+
+ //set AF map
+ GPIO_PinAFConfig(DMA_SPI_SCK_PORT, DMA_SPI_SCK_PIN_SRC, DMA_SPI_SCK_AF);
+ GPIO_PinAFConfig(DMA_SPI_MISO_PORT, DMA_SPI_MISO_PIN_SRC, DMA_SPI_MISO_AF);
+ GPIO_PinAFConfig(DMA_SPI_MOSI_PORT, DMA_SPI_MOSI_PIN_SRC, DMA_SPI_MOSI_AF);
+
+ //config SPI
+ SPI_StructInit(&spiInitStruct);
+ spiInitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
+ spiInitStruct.SPI_Mode = SPI_Mode_Master;
+ spiInitStruct.SPI_DataSize = SPI_DataSize_8b;
+ spiInitStruct.SPI_CPOL = DMA_SPI_CPOL;
+ spiInitStruct.SPI_CPHA = DMA_SPI_CPHA;
+ spiInitStruct.SPI_NSS = SPI_NSS_Soft;
+ spiInitStruct.SPI_BaudRatePrescaler = DMA_SPI_BAUDRATE;
+ spiInitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
+ SPI_Init(DMA_SPI_SPI, &spiInitStruct);
+
+ //set DMA to default state
+ DMA_DeInit(DMA_SPI_TX_DMA_STREAM);
+ DMA_DeInit(DMA_SPI_RX_DMA_STREAM);
+
+ DMA_StructInit(&dmaInitStruct);
+ dmaInitStruct.DMA_Channel = DMA_SPI_TX_DMA_CHANNEL;
+ dmaInitStruct.DMA_Mode = DMA_Mode_Normal;
+ dmaInitStruct.DMA_Priority = DMA_Priority_VeryHigh;
+ dmaInitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
+
+ dmaInitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
+ dmaInitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+ dmaInitStruct.DMA_PeripheralBaseAddr = (uint32_t)&DMA_SPI_SPI->DR;
+
+ dmaInitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
+ dmaInitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
+ dmaInitStruct.DMA_Memory0BaseAddr = 0; //this is set later when we fire the DMA
+
+ dmaInitStruct.DMA_BufferSize = 1; //this is set later when we fire the DMA, can't be 0
+
+ DMA_Init(DMA_SPI_TX_DMA_STREAM, &dmaInitStruct);
+
+ dmaInitStruct.DMA_Channel = DMA_SPI_RX_DMA_CHANNEL;
+ dmaInitStruct.DMA_Priority = DMA_Priority_High;
+ dmaInitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;
+
+ DMA_Init(DMA_SPI_RX_DMA_STREAM, &dmaInitStruct);
+
+ //setup interrupt
+ nvicInitStruct.NVIC_IRQChannel = DMA_SPI_RX_DMA_IRQn;
+ nvicInitStruct.NVIC_IRQChannelPreemptionPriority = 0;
+ nvicInitStruct.NVIC_IRQChannelSubPriority = 2;
+ nvicInitStruct.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&nvicInitStruct);
+ DMA_ITConfig(DMA_SPI_RX_DMA_STREAM, DMA_IT_TC, ENABLE);
+}
+
+void dmaSpiTransmitReceive(uint8_t* txBuffer, uint8_t* rxBuffer, uint32_t size, uint32_t blockingRead)
+{
+ //set buffer size
+ DMA_SetCurrDataCounter(DMA_SPI_TX_DMA_STREAM, size);
+ DMA_SetCurrDataCounter(DMA_SPI_RX_DMA_STREAM, size);
+
+ //set buffer
+ DMA_SPI_TX_DMA_STREAM->M0AR = (uint32_t)txBuffer;
+ DMA_SPI_RX_DMA_STREAM->M0AR = (uint32_t)rxBuffer;
+
+ //enable DMA SPI streams
+ DMA_Cmd(DMA_SPI_TX_DMA_STREAM, ENABLE);
+ DMA_Cmd(DMA_SPI_RX_DMA_STREAM, ENABLE);
+
+ //enable CS
+ dmaSpiCsLo();
+
+ //enable DMA SPI requests
+ SPI_I2S_DMACmd(DMA_SPI_SPI, SPI_I2S_DMAReq_Tx, ENABLE);
+ SPI_I2S_DMACmd(DMA_SPI_SPI, SPI_I2S_DMAReq_Rx, ENABLE);
+
+ //enable and send
+ SPI_Cmd(DMA_SPI_SPI, ENABLE);
+
+ if(!blockingRead)
+ dmaSpiReadStatus = DMA_SPI_READ_IN_PROGRESS;
+ else
+ dmaSpiReadStatus = DMA_SPI_BLOCKING_READ_IN_PROGRESS;
+}
+#endif
diff --git a/src/main/drivers/dma_spi.h b/src/main/drivers/dma_spi.h
new file mode 100755
index 000000000..ea73a365b
--- /dev/null
+++ b/src/main/drivers/dma_spi.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "common/time.h"
+
+#ifdef USE_DMA_SPI_DEVICE
+
+typedef enum dma_spi_read_status_e {
+ DMA_SPI_READ_UNKNOWN = 0,
+ DMA_SPI_READ_IN_PROGRESS = 1,
+ DMA_SPI_READ_DONE = 2,
+ DMA_SPI_BLOCKING_READ_IN_PROGRESS = 3,
+} dma_spi_read_status_t;
+
+extern volatile uint32_t crcErrorCount;
+extern volatile dma_spi_read_status_t dmaSpiReadStatus;
+extern volatile bool dmaSpiDeviceDataReady;
+extern uint8_t dmaTxBuffer[58];
+extern uint8_t dmaRxBuffer[58];
+extern bool isDmaSpiDataReady(timeUs_t currentTimeUs, timeDelta_t currentDeltaTimeUs);
+extern void dmaSpicleanupspi(void);
+extern void dmaSpiInit(void);
+extern void dmaSpiTransmitReceive(uint8_t* txBuffer, uint8_t* rxBuffer, uint32_t size, uint32_t blockingRead);
+
+#endif
\ No newline at end of file
diff --git a/src/main/drivers/dma_spi_hal.c b/src/main/drivers/dma_spi_hal.c
new file mode 100755
index 000000000..6960b7b57
--- /dev/null
+++ b/src/main/drivers/dma_spi_hal.c
@@ -0,0 +1,226 @@
+
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "platform.h"
+#include "dma_spi.h"
+#include "common/time.h"
+#include "sensors/gyro.h"
+#include "drivers/accgyro/accgyro.h"
+#include "drivers/accgyro/accgyro_mpu.h"
+#ifdef USE_GYRO_IMUF9001
+#include "drivers/accgyro/accgyro_imuf9001.h"
+FAST_RAM_ZERO_INIT volatile uint32_t crcErrorCount;
+#endif
+
+#ifdef USE_DMA_SPI_DEVICE
+
+FAST_RAM_ZERO_INIT SPI_HandleTypeDef dmaSpiHandle;
+FAST_RAM_ZERO_INIT DMA_HandleTypeDef SpiRxDmaHandle;
+FAST_RAM_ZERO_INIT DMA_HandleTypeDef SpiTxDmaHandle;
+FAST_RAM_ZERO_INIT volatile dma_spi_read_status_t dmaSpiReadStatus;
+FAST_RAM_ZERO_INIT volatile bool dmaSpiDeviceDataReady = false;
+FAST_RAM_ZERO_INIT uint8_t dmaTxBuffer[58];
+FAST_RAM_ZERO_INIT uint8_t dmaRxBuffer[58];
+
+
+FAST_CODE static inline void dmaSpiCsLo(void)
+{
+ HAL_GPIO_WritePin(DMA_SPI_NSS_PORT, DMA_SPI_NSS_PIN, 0);
+}
+
+FAST_CODE static inline void dmaSpiCsHi(void)
+{
+ HAL_GPIO_WritePin(DMA_SPI_NSS_PORT, DMA_SPI_NSS_PIN, 1);
+}
+
+
+// FAST_CODE void dmaSpicleanupspi(void)
+// {
+// }
+
+FAST_CODE_NOINLINE void DMA_SPI_TX_DMA_HANDLER(void)
+{
+ HAL_NVIC_ClearPendingIRQ(DMA_SPI_TX_DMA_IRQn);
+ HAL_DMA_IRQHandler(&SpiTxDmaHandle);
+}
+
+FAST_CODE_NOINLINE void DMA_SPI_RX_DMA_HANDLER(void)
+{
+ HAL_NVIC_ClearPendingIRQ(DMA_SPI_RX_DMA_IRQn);
+ HAL_DMA_IRQHandler(&SpiRxDmaHandle);
+
+ if (HAL_DMA_GetState(&SpiRxDmaHandle) == HAL_DMA_STATE_READY)
+ {
+ dmaSpiCsHi();
+ //spi rx dma callback
+ #ifdef USE_GYRO_IMUF9001
+ volatile uint32_t crc1 = ( (*(uint32_t *)(dmaRxBuffer+gyroConfig()->imuf_mode-4)) & 0xFF );
+ volatile uint32_t crc2 = ( getCrcImuf9001((uint32_t *)(dmaRxBuffer), (gyroConfig()->imuf_mode >> 2)-1) & 0xFF );
+ if(crc1 == crc2)
+ {
+ if(dmaSpiReadStatus != DMA_SPI_BLOCKING_READ_IN_PROGRESS)
+ {
+ gyroDmaSpiFinishRead();
+ }
+ dmaSpiDeviceDataReady = true;
+ }
+ else
+ {
+ if (crcErrorCount > 100000)
+ {
+ crcErrorCount = 0;
+ }
+ //error handler
+ crcErrorCount++; //check every so often and cause a failsafe is this number is above a certain ammount
+ }
+ #else
+ if(dmaSpiReadStatus != DMA_SPI_BLOCKING_READ_IN_PROGRESS)
+ {
+ gyroDmaSpiFinishRead();
+ }
+ dmaSpiDeviceDataReady = true;
+ #endif
+ }
+
+ dmaSpiCsHi();
+ // dmaSpicleanupspi();
+
+ dmaSpiReadStatus = DMA_SPI_READ_DONE;
+}
+
+FAST_CODE inline bool isDmaSpiDataReady(timeUs_t currentTimeUs, timeDelta_t currentDeltaTimeUs)
+{
+ (void)(currentTimeUs);
+ (void)(currentDeltaTimeUs);
+ return dmaSpiDeviceDataReady;
+}
+
+void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ DMA_SPI_CLOCK_INIT_FUNC;
+
+ HAL_GPIO_WritePin(DMA_SPI_NSS_PORT, DMA_SPI_NSS_PIN, 1);
+ HAL_GPIO_DeInit(DMA_SPI_NSS_PORT, DMA_SPI_NSS_PIN);
+ GPIO_InitStruct.Pin = DMA_SPI_NSS_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+ HAL_GPIO_Init(DMA_SPI_NSS_PORT, &GPIO_InitStruct);
+ HAL_GPIO_WritePin(DMA_SPI_NSS_PORT, DMA_SPI_NSS_PIN, 1);
+
+ HAL_GPIO_DeInit(DMA_SPI_SCK_PORT, DMA_SPI_SCK_PIN);
+ HAL_GPIO_DeInit(DMA_SPI_MISO_PORT, DMA_SPI_MISO_PIN);
+ HAL_GPIO_DeInit(DMA_SPI_MOSI_PORT, DMA_SPI_MOSI_PIN);
+
+ GPIO_InitStruct.Pin = DMA_SPI_SCK_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_PULLDOWN;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+ GPIO_InitStruct.Alternate = DMA_SPI_SCK_AF;
+ HAL_GPIO_Init(DMA_SPI_SCK_PORT, &GPIO_InitStruct);
+
+ GPIO_InitStruct.Pin = DMA_SPI_MISO_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_PULLDOWN;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+ GPIO_InitStruct.Alternate = DMA_SPI_MISO_AF;
+ HAL_GPIO_Init(DMA_SPI_MISO_PORT, &GPIO_InitStruct);
+
+ GPIO_InitStruct.Pin = DMA_SPI_MOSI_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_PULLDOWN;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+ GPIO_InitStruct.Alternate = DMA_SPI_MOSI_AF;
+ HAL_GPIO_Init(DMA_SPI_MOSI_PORT, &GPIO_InitStruct);
+
+
+ SpiRxDmaHandle.Instance = DMA_SPI_RX_DMA_STREAM;
+ SpiRxDmaHandle.Init.Channel = DMA_SPI_RX_DMA_CHANNEL;
+ SpiRxDmaHandle.Init.Direction = DMA_PERIPH_TO_MEMORY;
+ SpiRxDmaHandle.Init.PeriphInc = DMA_PINC_DISABLE;
+ SpiRxDmaHandle.Init.MemInc = DMA_MINC_ENABLE;
+ SpiRxDmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
+ SpiRxDmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
+ SpiRxDmaHandle.Init.Mode = DMA_NORMAL;
+ SpiRxDmaHandle.Init.Priority = DMA_PRIORITY_HIGH;
+ SpiRxDmaHandle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
+
+ HAL_DMA_UnRegisterCallback(&SpiRxDmaHandle, HAL_DMA_XFER_ALL_CB_ID);
+
+ HAL_DMA_Init(&SpiRxDmaHandle);
+
+ __HAL_LINKDMA(hspi, hdmarx, SpiRxDmaHandle);
+
+ HAL_NVIC_SetPriority(DMA_SPI_RX_DMA_IRQn, DMA_SPI_DMA_RX_PRE_PRI, DMA_SPI_DMA_RX_SUB_PRI);
+ HAL_NVIC_EnableIRQ(DMA_SPI_RX_DMA_IRQn);
+
+ SpiTxDmaHandle.Instance = DMA_SPI_TX_DMA_STREAM;
+ SpiTxDmaHandle.Init.Channel = DMA_SPI_TX_DMA_CHANNEL;
+ SpiTxDmaHandle.Init.Direction = DMA_MEMORY_TO_PERIPH;
+ SpiTxDmaHandle.Init.PeriphInc = DMA_PINC_DISABLE;
+ SpiTxDmaHandle.Init.MemInc = DMA_MINC_ENABLE;
+ SpiTxDmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
+ SpiTxDmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
+ SpiTxDmaHandle.Init.Mode = DMA_NORMAL;
+ SpiTxDmaHandle.Init.Priority = DMA_PRIORITY_VERY_HIGH;
+ SpiTxDmaHandle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
+
+ HAL_DMA_UnRegisterCallback(&SpiTxDmaHandle, HAL_DMA_XFER_ALL_CB_ID);
+
+ HAL_DMA_Init(&SpiTxDmaHandle);
+
+ __HAL_LINKDMA(hspi, hdmatx, SpiTxDmaHandle);
+
+ HAL_NVIC_SetPriority(DMA_SPI_TX_DMA_IRQn, DMA_SPI_DMA_TX_PRE_PRI, DMA_SPI_DMA_TX_SUB_PRI);
+ HAL_NVIC_EnableIRQ(DMA_SPI_TX_DMA_IRQn);
+
+}
+
+void dmaSpiInit(void)
+{
+ dmaSpiHandle.Instance = DMA_SPI_SPI;
+ HAL_SPI_DeInit(&dmaSpiHandle);
+
+ dmaSpiHandle.Init.Mode = SPI_MODE_MASTER;
+ dmaSpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
+ dmaSpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
+ dmaSpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
+ dmaSpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
+ dmaSpiHandle.Init.NSS = SPI_NSS_SOFT;
+ dmaSpiHandle.Init.BaudRatePrescaler = DMA_SPI_BAUDRATE;
+ dmaSpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
+ dmaSpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
+ dmaSpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
+ dmaSpiHandle.Init.CRCPolynomial = 7;
+
+ HAL_SPI_Init(&dmaSpiHandle);
+
+}
+
+FAST_CODE_NOINLINE void dmaSpiTransmitReceive(uint8_t* txBuffer, uint8_t* rxBuffer, uint32_t size, uint32_t blockingRead)
+{
+
+ if (HAL_SPI_GetState(&dmaSpiHandle) == HAL_SPI_STATE_READY)
+ {
+ dmaSpiCsLo();
+ if(!blockingRead)
+ {
+ dmaSpiReadStatus = DMA_SPI_READ_IN_PROGRESS;
+ HAL_SPI_TransmitReceive_DMA(&dmaSpiHandle, txBuffer, rxBuffer, size);
+ }
+ else
+ {
+ dmaSpiReadStatus = DMA_SPI_BLOCKING_READ_IN_PROGRESS;
+ HAL_SPI_TransmitReceive(&dmaSpiHandle, txBuffer, rxBuffer, size, 40);
+ dmaSpiCsHi();
+ dmaSpiReadStatus = DMA_SPI_READ_DONE;
+ }
+ }
+}
+
+#endif // USE_HAL_DMA_SPI_DEVICE
diff --git a/src/main/drivers/dma_spi_hal.h b/src/main/drivers/dma_spi_hal.h
new file mode 100755
index 000000000..81b90be35
--- /dev/null
+++ b/src/main/drivers/dma_spi_hal.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "common/time.h"
+
+#ifdef USE_DMA_SPI_DEVICE
+
+typedef enum dma_spi_read_status_e {
+ DMA_SPI_READ_UNKNOWN = 0,
+ DMA_SPI_READ_IN_PROGRESS = 1,
+ DMA_SPI_READ_DONE = 2,
+ DMA_SPI_BLOCKING_READ_IN_PROGRESS = 3,
+} dma_spi_read_status_t;
+
+extern volatile uint32_t crcErrorCount;
+extern volatile dma_spi_read_status_t dmaSpiReadStatus;
+extern volatile bool dmaSpiDeviceDataReady;
+extern uint8_t dmaTxBuffer[58];
+extern uint8_t dmaRxBuffer[58];
+extern bool isDmaSpiDataReady(timeUs_t currentTimeUs, timeDelta_t currentDeltaTimeUs);
+// extern void dmaSpicleanupspi(void);
+extern void dmaSpiInit(void);
+extern void dmaSpiTransmitReceive(uint8_t* txBuffer, uint8_t* rxBuffer, uint32_t size, uint32_t blockingRead);
+
+#endif
\ No newline at end of file
diff --git a/src/main/drivers/dma_stm32f4xx.c b/src/main/drivers/dma_stm32f4xx.c
index 25359bc37..a62b5a6f7 100644
--- a/src/main/drivers/dma_stm32f4xx.c
+++ b/src/main/drivers/dma_stm32f4xx.c
@@ -66,7 +66,9 @@ DEFINE_DMA_IRQ_HANDLER(1, 6, DMA1_ST6_HANDLER)
DEFINE_DMA_IRQ_HANDLER(1, 7, DMA1_ST7_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 0, DMA2_ST0_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 1, DMA2_ST1_HANDLER)
+#ifndef USE_DMA_SPI_DEVICE // modded for HELIOSPRING
DEFINE_DMA_IRQ_HANDLER(2, 2, DMA2_ST2_HANDLER)
+#endif
DEFINE_DMA_IRQ_HANDLER(2, 3, DMA2_ST3_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 4, DMA2_ST4_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 5, DMA2_ST5_HANDLER)
diff --git a/src/main/drivers/dma_stm32f7xx.c b/src/main/drivers/dma_stm32f7xx.c
index 38a0b653d..22f435201 100644
--- a/src/main/drivers/dma_stm32f7xx.c
+++ b/src/main/drivers/dma_stm32f7xx.c
@@ -67,8 +67,10 @@ DEFINE_DMA_IRQ_HANDLER(1, 6, DMA1_ST6_HANDLER)
DEFINE_DMA_IRQ_HANDLER(1, 7, DMA1_ST7_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 0, DMA2_ST0_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 1, DMA2_ST1_HANDLER)
+#ifndef USE_DMA_SPI_DEVICE // modded for HELIOSPRING
DEFINE_DMA_IRQ_HANDLER(2, 2, DMA2_ST2_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 3, DMA2_ST3_HANDLER)
+#endif
DEFINE_DMA_IRQ_HANDLER(2, 4, DMA2_ST4_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 5, DMA2_ST5_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 6, DMA2_ST6_HANDLER)
diff --git a/src/main/fc/config.c b/src/main/fc/config.c
index 73e47962d..08712b451 100644
--- a/src/main/fc/config.c
+++ b/src/main/fc/config.c
@@ -82,6 +82,11 @@
#include "common/sensor_alignment.h"
+// HELIOSPRING
+#ifdef USE_GYRO_IMUF9001
+#include "drivers/accgyro/accgyro_imuf9001.h"
+#endif
+
static bool configIsDirty; /* someone indicated that the config is modified and it is not yet saved */
static bool rebootRequired = false; // set if a config change requires a reboot to take effect
@@ -179,6 +184,33 @@ static void adjustFilterLimit(uint16_t *parm, uint16_t resetValue)
}
}
+// HELIOPRING
+#ifdef USE_GYRO_IMUF9001
+int getImufRateFromGyroSyncDenom(int gyroSyncDenom){
+ switch (gyroSyncDenom) {
+ case 1:
+ return IMUF_RATE_32K;
+ break;
+ case 2:
+ default:
+ return IMUF_RATE_16K;
+ break;
+ case 4:
+ return IMUF_RATE_8K;
+ break;
+ case 8:
+ return IMUF_RATE_4K;
+ break;
+ case 16:
+ return IMUF_RATE_2K;
+ break;
+ case 32:
+ return IMUF_RATE_1K;
+ break;
+ }
+}
+#endif
+
static void validateAndFixConfig(void)
{
#if !defined(USE_QUAD_MIXER_ONLY)
@@ -558,6 +590,18 @@ void validateAndFixGyroConfig(void)
}
#endif
+// HELIOSPRING
+#ifdef USE_GYRO_IMUF9001
+ //keeop imuf_rate in sync with the gyro.
+ uint8_t imuf_rate = getImufRateFromGyroSyncDenom(gyroConfigMutable()->gyro_sync_denom);
+ gyroConfigMutable()->imuf_rate = imuf_rate;
+ if (imuf_rate == IMUF_RATE_32K) {
+ gyroConfigMutable()->imuf_mode = GTBCM_GYRO_ACC_FILTER_F;
+ } else {
+ gyroConfigMutable()->imuf_mode = GTBCM_DEFAULT;
+ }
+#endif
+
// Fix gyro filter settings to handle cases where an older configurator was used that
// allowed higher cutoff limits from previous firmware versions.
adjustFilterLimit(&gyroConfigMutable()->gyro_lowpass_hz, FILTER_FREQUENCY_MAX);
diff --git a/src/main/fc/init.c b/src/main/fc/init.c
index 42888336d..fb1c50bfb 100644
--- a/src/main/fc/init.c
+++ b/src/main/fc/init.c
@@ -67,6 +67,7 @@
#include "drivers/serial.h"
#include "drivers/serial_softserial.h"
#include "drivers/serial_uart.h"
+#include "drivers/serial_usb_vcp.h" // HELIOSPRING
#include "drivers/sdcard.h"
#include "drivers/sdio.h"
#include "drivers/sound_beeper.h"
@@ -82,6 +83,14 @@
#include "drivers/vtx_rtc6705.h"
#include "drivers/vtx_table.h"
+// HELIOSPRING
+#ifdef USE_DMA_SPI_DEVICE
+#include "drivers/dma_spi.h"
+#endif //USE_DMA_SPI_DEVICE
+#ifdef USE_GYRO_IMUF9001
+#include "drivers/accgyro/accgyro_imuf9001.h"
+#endif //USE_GYRO_IMUF9001
+
#include "fc/board_info.h"
#include "fc/config.h"
#include "fc/dispatch.h"
@@ -223,6 +232,9 @@ static void configureSPIAndQuadSPI(void)
#ifdef USE_SPI_DEVICE_1
spiInit(SPIDEV_1);
#endif
+#ifdef USE_DMA_SPI_DEVICE // HELIOSPRING
+ dmaSpiInit();
+#endif
#ifdef USE_SPI_DEVICE_2
spiInit(SPIDEV_2);
#endif
@@ -264,6 +276,14 @@ void init(void)
systemInit();
+// HELIOSPRING
+#ifdef USE_GYRO_IMUF9001
+ if (isMPUSoftReset()) {
+ // reset imuf before befhal mucks with the pins
+ initImuf9001();
+ }
+#endif
+
// initialize IO (needed for all IO operations)
IOInitGlobal();
@@ -486,6 +506,23 @@ void init(void)
#endif
#ifdef USE_OVERCLOCK
+// HELIOSPRING
+#if defined(STM32F3) && defined(USE_VCP)
+ if (systemConfig()->cpu_overclock > OVERCLOCK_128MHZ) {
+ usbVcpOpen();
+ uint32_t us = micros();
+ bool usbConnected = false;
+ while(cmpTimeUs(micros(), us) < 1500000 && !usbConnected) {
+ usbConnected = usbVcpIsConnected() != 0;
+ }
+
+ /* void indicate(uint8_t count, uint16_t duration); */
+ /* indicate((RCC->CFGR & (0xf << 18)) >> 18, 500); */
+ if (!usbConnected) {
+ OverclockRebootIfNecessary(systemConfig()->cpu_overclock);
+ }
+ } else
+#endif
OverclockRebootIfNecessary(systemConfig()->cpu_overclock);
#endif
diff --git a/src/main/fc/rc.c b/src/main/fc/rc.c
index 869458698..1affbeaf9 100644
--- a/src/main/fc/rc.c
+++ b/src/main/fc/rc.c
@@ -20,6 +20,7 @@
#include <stdbool.h>
#include <stdint.h>
+#include <string.h> // HELIOSPRING
#include <math.h>
#include "platform.h"
@@ -62,6 +63,7 @@ static float oldRcCommand[XYZ_AXIS_COUNT];
static bool isDuplicateFrame;
#endif
static float setpointRate[3], rcDeflection[3], rcDeflectionAbs[3];
+static volatile uint32_t setpointRateInt[3]; // HELIOSPRING
static float throttlePIDAttenuation;
static bool reverseMotors = false;
static applyRatesFn *applyRates;
@@ -70,6 +72,11 @@ uint16_t currentRxRefreshRate;
FAST_RAM_ZERO_INIT uint8_t interpolationChannels;
static FAST_RAM_ZERO_INIT uint32_t rcFrameNumber;
+// HELIOSPRING
+#ifdef USE_GYRO_IMUF9001
+ volatile bool isSetpointNew;
+#endif
+
enum {
ROLL_FLAG = 1 << ROLL,
PITCH_FLAG = 1 << PITCH,
@@ -101,6 +108,12 @@ float getSetpointRate(int axis)
return setpointRate[axis];
}
+// HELIOSPRING
+uint32_t getSetpointRateInt(int axis)
+{
+ return setpointRateInt[axis];
+}
+
float getRcDeflection(int axis)
{
return rcDeflection[axis];
@@ -228,6 +241,8 @@ static void calculateSetpointRate(int axis)
// Rate limit from profile (deg/sec)
setpointRate[axis] = constrainf(angleRate, -1.0f * currentControlRateProfile->rate_limit[axis], 1.0f * currentControlRateProfile->rate_limit[axis]);
+ memcpy((uint32_t*)&setpointRateInt[axis], (uint32_t*)&setpointRate[axis], sizeof(float)); // HELIOSPRING
+
DEBUG_SET(DEBUG_ANGLERATE, axis, angleRate);
}
@@ -652,6 +667,11 @@ FAST_CODE void processRcCommand(void)
calculateSetpointRate(axis);
}
+// HELIOSPRING
+#ifdef USE_GYRO_IMUF9001
+ isSetpointNew = 1;
+#endif
+
DEBUG_SET(DEBUG_RC_INTERPOLATION, 3, setpointRate[0]);
// Scaling of AngleRate to camera angle (Mixing Roll and Yaw)
diff --git a/src/main/fc/rc.h b/src/main/fc/rc.h
index d28f5d31a..5a3c3a8e9 100644
--- a/src/main/fc/rc.h
+++ b/src/main/fc/rc.h
@@ -30,10 +30,16 @@ typedef enum {
INTERPOLATION_CHANNELS_RPT,
} interpolationChannels_e;
+// HELIOSPRING
+#ifdef USE_GYRO_IMUF9001
+extern volatile bool isSetpointNew;
+#endif
+
extern uint16_t currentRxRefreshRate;
void processRcCommand(void);
float getSetpointRate(int axis);
+uint32_t getSetpointRateInt(int axis); // HELIOSPRING
float getRcDeflection(int axis);
float getRcDeflectionAbs(int axis);
float getThrottlePIDAttenuation(void);
diff --git a/src/main/fc/tasks.c b/src/main/fc/tasks.c
index a1ed90677..f0e7938e3 100644
--- a/src/main/fc/tasks.c
+++ b/src/main/fc/tasks.c
@@ -391,8 +391,13 @@ cfTask_t cfTasks[TASK_COUNT] = {
[TASK_GYROPID] = DEFINE_TASK("PID", "GYRO", NULL, taskMainPidLoop, TASK_GYROPID_DESIRED_PERIOD, TASK_PRIORITY_REALTIME),
#ifdef USE_ACC
+#ifdef USE_ACC_IMUF9001 // HELIOSPRING
[TASK_ACCEL] = DEFINE_TASK("ACC", NULL, NULL, taskUpdateAccelerometer, TASK_PERIOD_HZ(1000), TASK_PRIORITY_MEDIUM),
- [TASK_ATTITUDE] = DEFINE_TASK("ATTITUDE", NULL, NULL, imuUpdateAttitude, TASK_PERIOD_HZ(100), TASK_PRIORITY_MEDIUM),
+ [TASK_ATTITUDE] = DEFINE_TASK("ATTITUDE", NULL, NULL, imuUpdateAttitude, TASK_PERIOD_HZ(500), TASK_PRIORITY_MEDIUM),
+#else // not HELIOSPRING
+ [TASK_ACCEL] = DEFINE_TASK("ACC", NULL, NULL, taskUpdateAccelerometer, TASK_PERIOD_HZ(1000), TASK_PRIORITY_MEDIUM),
+ [TASK_ATTITUDE] = DEFINE_TASK("ATTITUDE", NULL, NULL, imuUpdateAttitude, TASK_PERIOD_HZ(1000), TASK_PRIORITY_MEDIUM),
+#endif
#endif
[TASK_RX] = DEFINE_TASK("RX", NULL, rxUpdateCheck, taskUpdateRxMain, TASK_PERIOD_HZ(33), TASK_PRIORITY_HIGH), // If event-based scheduling doesn't work, fallback to periodic scheduling
[TASK_DISPATCH] = DEFINE_TASK("DISPATCH", NULL, NULL, dispatchProcess, TASK_PERIOD_HZ(1000), TASK_PRIORITY_HIGH),
diff --git a/src/main/flight/imu.c b/src/main/flight/imu.c
index 053cdd9c1..f05b554ef 100644
--- a/src/main/flight/imu.c
+++ b/src/main/flight/imu.c
@@ -38,6 +38,8 @@
#include "fc/runtime_config.h"
+#include "fc/rc_controls.h" // HELIOSPRING
+
#include "flight/gps_rescue.h"
#include "flight/imu.h"
#include "flight/mixer.h"
diff --git a/src/main/sensors/acceleration.c b/src/main/sensors/acceleration.c
index a57f8294e..1720797d7 100644
--- a/src/main/sensors/acceleration.c
+++ b/src/main/sensors/acceleration.c
@@ -65,6 +65,11 @@
#include "drivers/accgyro_legacy/accgyro_mma845x.h"
#endif
+// HELIOSPRING
+#ifdef USE_ACC_IMUF9001
+#include "drivers/accgyro/accgyro_imuf9001.h"
+#endif //USE_ACC_IMUF9001
+
#include "drivers/bus_spi.h"
#include "fc/config.h"
@@ -260,6 +265,16 @@ retry:
FALLTHROUGH;
#endif
+// HELIOSPRING
+#ifdef USE_ACC_IMUF9001
+ case ACC_IMUF9001:
+ if (imufSpiAccDetect(dev)) {
+ accHardware = ACC_IMUF9001;
+ break;
+ }
+ FALLTHROUGH;
+#endif
+
#ifdef USE_ACC_SPI_ICM20689
case ACC_ICM20689:
if (icm20689SpiAccDetect(dev)) {
@@ -309,6 +324,12 @@ retry:
return true;
}
+// HELIOSPRING
+int accGetSamplingIntervall(void)
+{
+ return acc.accSamplingInterval;
+}
+
bool accInit(uint32_t gyroSamplingInverval)
{
memset(&acc, 0, sizeof(acc));
@@ -351,6 +372,11 @@ bool accInit(uint32_t gyroSamplingInverval)
default:
acc.accSamplingInterval = 1000;
}
+
+#ifdef USE_ACC_IMUF9001 // HELIOSPRING
+ acc.accSamplingInterval = 500;
+#endif
+
if (accLpfCutHz) {
for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
biquadFilterInitLPF(&accFilter[axis], accLpfCutHz, acc.accSamplingInterval);
diff --git a/src/main/sensors/acceleration.h b/src/main/sensors/acceleration.h
index 4ad1b1642..29b1f176e 100644
--- a/src/main/sensors/acceleration.h
+++ b/src/main/sensors/acceleration.h
@@ -43,6 +43,7 @@ typedef enum {
ACC_ICM20649,
ACC_ICM20689,
ACC_BMI160,
+ ACC_IMUF9001, // HELIOSPRING
ACC_FAKE
} accelerationSensor_e;
@@ -87,3 +88,5 @@ union flightDynamicsTrims_u;
void setAccelerationTrims(union flightDynamicsTrims_u *accelerationTrimsToUse);
void accInitFilters(void);
void applyAccelerometerTrimsDelta(union rollAndPitchTrims_u *rollAndPitchTrimsDelta);
+
+int accGetSamplingIntervall(void); // HELIOSPRING
\ No newline at end of file
diff --git a/src/main/sensors/boardalignment.c b/src/main/sensors/boardalignment.c
index de312b070..d081e2711 100644
--- a/src/main/sensors/boardalignment.c
+++ b/src/main/sensors/boardalignment.c
@@ -43,7 +43,8 @@ static fp_rotationMatrix_t boardRotation;
// no template required since defaults are zero
PG_REGISTER(boardAlignment_t, boardAlignment, PG_BOARD_ALIGNMENT, 0);
-static bool isBoardAlignmentStandard(const boardAlignment_t *boardAlignment)
+//static bool isBoardAlignmentStandard(const boardAlignment_t *boardAlignment)
+bool isBoardAlignmentStandard(const boardAlignment_t *boardAlignment)
{
return !boardAlignment->rollDegrees && !boardAlignment->pitchDegrees && !boardAlignment->yawDegrees;
}
diff --git a/src/main/sensors/boardalignment.h b/src/main/sensors/boardalignment.h
index e2be2ba84..58051ad09 100644
--- a/src/main/sensors/boardalignment.h
+++ b/src/main/sensors/boardalignment.h
@@ -37,3 +37,5 @@ void alignSensorViaMatrix(float *dest, fp_rotationMatrix_t* rotationMatrix);
void alignSensorViaRotation(float *dest, uint8_t rotation);
void initBoardAlignment(const boardAlignment_t *boardAlignment);
+
+bool isBoardAlignmentStandard(const boardAlignment_t *boardAlignment); // HELIOSPRING
diff --git a/src/main/sensors/gyro.c b/src/main/sensors/gyro.c
index 2eae9232f..548b08d2a 100644
--- a/src/main/sensors/gyro.c
+++ b/src/main/sensors/gyro.c
@@ -51,6 +51,12 @@
#include "drivers/accgyro/accgyro_spi_mpu6500.h"
#include "drivers/accgyro/accgyro_spi_mpu9250.h"
+// HELIOSPRING
+#ifdef USE_GYRO_IMUF9001
+#include "drivers/accgyro/accgyro_imuf9001.h"
+#include "drivers/time.h"
+#endif //USE_GYRO_IMUF9001
+
#ifdef USE_GYRO_L3GD20
#include "drivers/accgyro/accgyro_spi_l3gd20.h"
#endif
@@ -196,6 +202,24 @@ void pgResetFn_gyroConfig(gyroConfig_t *gyroConfig)
gyroConfig->dyn_notch_q = 120;
gyroConfig->dyn_notch_min_hz = 150;
gyroConfig->gyro_filter_debug_axis = FD_ROLL;
+
+// HELIOSPRING
+#if defined(USE_GYRO_IMUF9001)
+ gyroConfig->imuf_mode = GTBCM_DEFAULT;
+ gyroConfig->imuf_rate = IMUF_RATE_16K;
+ gyroConfig->imuf_roll_q = IMUF_DEFAULT_ROLL_Q;
+ gyroConfig->imuf_pitch_q = IMUF_DEFAULT_PITCH_Q;
+ gyroConfig->imuf_yaw_q = IMUF_DEFAULT_YAW_Q;
+ gyroConfig->imuf_w = IMUF_DEFAULT_W;
+ gyroConfig->imuf_roll_lpf_cutoff_hz = IMUF_DEFAULT_LPF_HZ;
+ gyroConfig->imuf_pitch_lpf_cutoff_hz = IMUF_DEFAULT_LPF_HZ;
+ gyroConfig->imuf_yaw_lpf_cutoff_hz = IMUF_DEFAULT_LPF_HZ;
+ gyroConfig->imuf_roll_af = IMUF_DEFAULT_ROLL_AF;
+ gyroConfig->imuf_pitch_af = IMUF_DEFAULT_PITCH_AF;
+ gyroConfig->imuf_yaw_af = IMUF_DEFAULT_YAW_AF;
+ gyroConfig->gyro_offset_yaw = 0;
+ gyroConfig->gyro_align = ALIGN_DEFAULT;
+#endif
}
#ifdef USE_MULTI_GYRO
@@ -330,6 +354,16 @@ STATIC_UNIT_TESTED gyroHardware_e gyroDetect(gyroDev_t *dev)
FALLTHROUGH;
#endif
+// HELIOSPRING
+#ifdef USE_GYRO_IMUF9001
+ case GYRO_IMUF9001:
+ if (imufSpiGyroDetect(dev)) {
+ gyroHardware = GYRO_IMUF9001;
+ break;
+ }
+ FALLTHROUGH;
+#endif //USE_GYRO_IMUF9001
+
#ifdef USE_GYRO_SPI_ICM20689
case GYRO_ICM20689:
if (icm20689SpiGyroDetect(dev)) {
@@ -372,7 +406,7 @@ STATIC_UNIT_TESTED gyroHardware_e gyroDetect(gyroDev_t *dev)
static void gyroPreInitSensor(const gyroDeviceConfig_t *config)
{
#if defined(USE_GYRO_MPU6050) || defined(USE_GYRO_MPU3050) || defined(USE_GYRO_MPU6500) || defined(USE_GYRO_SPI_MPU6500) || defined(USE_GYRO_SPI_MPU6000) \
- || defined(USE_ACC_MPU6050) || defined(USE_GYRO_SPI_MPU9250) || defined(USE_GYRO_SPI_ICM20601) || defined(USE_GYRO_SPI_ICM20649) || defined(USE_GYRO_SPI_ICM20689)
+ || defined(USE_ACC_MPU6050) || defined(USE_GYRO_SPI_MPU9250) || defined(USE_GYRO_SPI_ICM20601) || defined(USE_GYRO_SPI_ICM20649) || defined(USE_GYRO_SPI_ICM20689) || defined(USE_GYRO_IMUF9001)
mpuPreInit(config);
#else
UNUSED(config);
@@ -382,7 +416,7 @@ static void gyroPreInitSensor(const gyroDeviceConfig_t *config)
static bool gyroDetectSensor(gyroSensor_t *gyroSensor, const gyroDeviceConfig_t *config)
{
#if defined(USE_GYRO_MPU6050) || defined(USE_GYRO_MPU3050) || defined(USE_GYRO_MPU6500) || defined(USE_GYRO_SPI_MPU6500) || defined(USE_GYRO_SPI_MPU6000) \
- || defined(USE_ACC_MPU6050) || defined(USE_GYRO_SPI_MPU9250) || defined(USE_GYRO_SPI_ICM20601) || defined(USE_GYRO_SPI_ICM20649) || defined(USE_GYRO_SPI_ICM20689) || defined(USE_GYRO_L3GD20)
+ || defined(USE_ACC_MPU6050) || defined(USE_GYRO_SPI_MPU9250) || defined(USE_GYRO_SPI_ICM20601) || defined(USE_GYRO_SPI_ICM20649) || defined(USE_GYRO_SPI_ICM20689) || defined(USE_GYRO_L3GD20) || defined(USE_GYRO_IMUF9001)
bool gyroFound = mpuDetect(&gyroSensor->gyroDev, config);
@@ -429,6 +463,7 @@ static void gyroInitSensor(gyroSensor_t *gyroSensor, const gyroDeviceConfig_t *c
case GYRO_MPU6000:
case GYRO_MPU6500:
case GYRO_MPU9250:
+ case GYRO_IMUF9001: // HELIOSPRING
gyroSensor->gyroDev.gyroHasOverflowProtection = true;
break;
@@ -808,6 +843,9 @@ static bool isOnFirstGyroCalibrationCycle(const gyroCalibration_t *gyroCalibrati
static void gyroSetCalibrationCycles(gyroSensor_t *gyroSensor)
{
+#ifdef USE_GYRO_IMUF9001 // HELIOSPRING
+ imufStartCalibration();
+#endif
#if defined(USE_FAKE_GYRO) && !defined(UNIT_TEST)
if (gyroSensor->gyroDev.gyroHardware == GYRO_FAKE) {
gyroSensor->calibration.cyclesRemaining = 0;
@@ -821,6 +859,9 @@ void gyroStartCalibration(bool isFirstArmingCalibration)
{
if (!(isFirstArmingCalibration && firstArmingCalibrationWasStarted)) {
gyroSetCalibrationCycles(&gyroSensor1);
+#ifdef USE_GYRO_IMUF9001 // HELIOSPRING
+ imufStartCalibration();
+#endif
#ifdef USE_MULTI_GYRO
gyroSetCalibrationCycles(&gyroSensor2);
#endif
@@ -1005,11 +1046,32 @@ static FAST_CODE void checkForYawSpin(timeUs_t currentTimeUs)
static FAST_CODE FAST_CODE_NOINLINE void gyroUpdateSensor(gyroSensor_t *gyroSensor)
{
+#ifndef USE_DMA_SPI_DEVICE // HELIORING
if (!gyroSensor->gyroDev.readFn(&gyroSensor->gyroDev)) {
return;
}
+#endif
gyroSensor->gyroDev.dataReady = false;
+#ifdef USE_GYRO_IMUF9001 // HELIOSPRING
+ for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
+ // NOTE: this branch optimized for when there is no gyro debugging, ensure it is kept in step with non-optimized branch
+ DEBUG_SET(DEBUG_GYRO_SCALED, axis, lrintf(gyroSensor->gyroDev.gyroADC[axis]));
+ if (!overflowDetected) {
+ // integrate using trapezium rule to avoid bias
+ accumulatedMeasurements[axis] += 0.5f * (gyroPrevious[axis] + gyroSensor->gyroDev.gyroADC[axis]) * gyro.targetLooptime;
+ gyroPrevious[axis] = gyroSensor->gyroDev.gyroADC[axis];
+ }
+ }
+ if (!isGyroSensorCalibrationComplete(gyroSensor)) {
+ performGyroCalibration(gyroSensor, gyroConfig()->gyroMovementCalibrationThreshold);
+ // Reset gyro values to zero to prevent other code from using uncalibrated data
+ gyroSensor->gyroDev.gyroADC[X] = 0.0f;
+ gyroSensor->gyroDev.gyroADC[Y] = 0.0f;
+ gyroSensor->gyroDev.gyroADC[Z] = 0.0f;
+ // still calibrating, so no need to further process gyro data
+ }
+#else // not HELIOSPRING
if (isGyroSensorCalibrationComplete(gyroSensor)) {
// move 16-bit gyro data into 32-bit variables to avoid overflows in calculations
@@ -1031,7 +1093,22 @@ static FAST_CODE FAST_CODE_NOINLINE void gyroUpdateSensor(gyroSensor_t *gyroSens
} else {
performGyroCalibration(gyroSensor, gyroConfig()->gyroMovementCalibrationThreshold);
}
+#endif // not HELIOSPRING
+}
+
+// HELIOSPRING
+#ifdef USE_DMA_SPI_DEVICE
+FAST_CODE_NOINLINE void gyroDmaSpiFinishRead(void)
+{
+ //called by dma callback
+ mpuGyroDmaSpiReadFinish(&gyroSensor1.gyroDev);
+}
+FAST_CODE_NOINLINE void gyroDmaSpiStartRead(void)
+{
+ //called by exti
+ mpuGyroDmaSpiReadStart(&gyroSensor1.gyroDev);
}
+#endif // HELIOSPRING
#define GYRO_FILTER_FUNCTION_NAME filterGyro
#define GYRO_FILTER_DEBUG_SET(mode, index, value) { UNUSED(mode); UNUSED(index); UNUSED(value); }
@@ -1052,9 +1129,15 @@ FAST_CODE void gyroUpdate(timeUs_t currentTimeUs)
case GYRO_CONFIG_USE_GYRO_1:
gyroUpdateSensor(&gyroSensor1);
if (isGyroSensorCalibrationComplete(&gyroSensor1)) {
+#ifdef USE_GYRO_IMUF9001 // HELIOSPRING
+ gyro.gyroADC[X] = gyroSensor1.gyroDev.gyroADC[X];
+ gyro.gyroADC[Y] = gyroSensor1.gyroDev.gyroADC[Y];
+ gyro.gyroADC[Z] = gyroSensor1.gyroDev.gyroADC[Z];
+#else // not HELIOSPRING
gyro.gyroADC[X] = gyroSensor1.gyroDev.gyroADC[X] * gyroSensor1.gyroDev.scale;
gyro.gyroADC[Y] = gyroSensor1.gyroDev.gyroADC[Y] * gyroSensor1.gyroDev.scale;
gyro.gyroADC[Z] = gyroSensor1.gyroDev.gyroADC[Z] * gyroSensor1.gyroDev.scale;
+#endif
}
break;
#ifdef USE_MULTI_GYRO
@@ -1203,7 +1286,11 @@ int16_t gyroGetTemperature(void)
int16_t gyroRateDps(int axis)
{
+#if defined(USE_GYRO_IMUF9001) // HELIOSPRING
+ return lrintf(gyro.gyroADCf[axis]);
+#else // not HELIOSPRING
return lrintf(gyro.gyroADCf[axis] / ACTIVE_GYRO->gyroDev.scale);
+#endif
}
bool gyroOverflowDetected(void)
diff --git a/src/main/sensors/gyro.h b/src/main/sensors/gyro.h
index fc8351173..f614d2028 100644
--- a/src/main/sensors/gyro.h
+++ b/src/main/sensors/gyro.h
@@ -36,6 +36,18 @@
#define FILTER_FREQUENCY_MAX 4000 // maximum frequency for filter cutoffs (nyquist limit of 8K max sampling)
+// HELIOSPRING
+#if defined(USE_GYRO_IMUF9001)
+typedef enum {
+ IMUF_RATE_32K = 0,
+ IMUF_RATE_16K = 1,
+ IMUF_RATE_8K = 2,
+ IMUF_RATE_4K = 3,
+ IMUF_RATE_2K = 4,
+ IMUF_RATE_1K = 5
+} imufRate_e;
+#endif
+
typedef union gyroLowpassFilter_u {
pt1Filter_t pt1FilterState;
biquadFilter_t biquadFilterState;
@@ -152,6 +164,22 @@ typedef struct gyroConfig_s {
uint16_t dyn_notch_q;
uint16_t dyn_notch_min_hz;
uint8_t gyro_filter_debug_axis;
+
+#if defined(USE_GYRO_IMUF9001) // HELIOSPRING
+ uint16_t imuf_mode;
+ uint16_t imuf_rate;
+ uint16_t imuf_pitch_q;
+ uint16_t imuf_roll_q;
+ uint16_t imuf_yaw_q;
+ uint16_t imuf_w;
+ uint16_t imuf_pitch_lpf_cutoff_hz;
+ uint16_t imuf_roll_lpf_cutoff_hz;
+ uint16_t imuf_yaw_lpf_cutoff_hz;
+ uint8_t imuf_pitch_af;
+ uint8_t imuf_roll_af;
+ uint8_t imuf_yaw_af;
+ uint8_t gyro_align; // gyro alignment
+#endif
} gyroConfig_t;
PG_DECLARE(gyroConfig_t, gyroConfig);
@@ -180,3 +208,9 @@ gyroDetectionFlags_t getGyroDetectionFlags(void);
float dynThrottle(float throttle);
void dynLpfGyroUpdate(float throttle);
#endif
+
+// HELIOSPRING
+#ifdef USE_DMA_SPI_DEVICE
+void gyroDmaSpiFinishRead(void);
+void gyroDmaSpiStartRead(void);
+#endif
diff --git a/src/main/startup/stm32f7xx_hal_conf.h b/src/main/startup/stm32f7xx_hal_conf.h
index c6c2504d9..eca6bee1f 100644
--- a/src/main/startup/stm32f7xx_hal_conf.h
+++ b/src/main/startup/stm32f7xx_hal_conf.h
@@ -52,7 +52,7 @@
#define HAL_ADC_MODULE_ENABLED
/* #define HAL_CAN_MODULE_ENABLED */
/* #define HAL_CEC_MODULE_ENABLED */
-/* #define HAL_CRC_MODULE_ENABLED */
+#define HAL_CRC_MODULE_ENABLED // HELIOSPRING
/* #define HAL_CRYP_MODULE_ENABLED */
#define HAL_DAC_MODULE_ENABLED
/* #define HAL_DCMI_MODULE_ENABLED */
diff --git a/src/main/target/HELIOSPRING/config.c b/src/main/target/HELIOSPRING/config.c
new file mode 100755
index 000000000..908717998
--- /dev/null
+++ b/src/main/target/HELIOSPRING/config.c
@@ -0,0 +1,57 @@
+/*
+ * This file is part of Cleanflight.
+ *
+ * Cleanflight is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Cleanflight 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+
+#include <platform.h>
+
+#include "config/config_eeprom.h"
+#include "drivers/pwm_output.h"
+#include "common/filter.h"
+#include "sensors/acceleration.h"
+#include "sensors/gyro.h"
+#include "sensors/battery.h"
+#include "telemetry/telemetry.h"
+#include "flight/mixer.h"
+#include "flight/pid.h"
+#include "fc/config.h"
+#include "fc/rc.h"
+#include "fc/rc_controls.h"
+#include "rx/rx.h"
+#include "drivers/pwm_output.h"
+#include "pg/motor.h"
+
+
+void targetConfiguration(void) {
+ telemetryConfigMutable()->halfDuplex = false;
+ voltageSensorADCConfigMutable(VOLTAGE_SENSOR_ADC_VBAT)->vbatscale = VBAT_SCALE;
+ rxConfigMutable()->rcInterpolation = RC_SMOOTHING_MANUAL;
+ rxConfigMutable()->rcInterpolationInterval = 14;
+ rxConfigMutable()->rcInterpolationChannels = INTERPOLATION_CHANNELS_RPYT;
+ motorConfigMutable()->dev.motorPwmProtocol = PWM_TYPE_DSHOT300;
+// gyroConfigMutable()->gyro_sync_denom = 1; // 8kHz gyro
+// pidConfigMutable()->pid_process_denom = 1; // 8kHz PID
+ gyroConfigMutable()->gyro_sync_denom = 2; // 16KHZ GYRO
+ pidConfigMutable()->pid_process_denom = 1; // 16KHZ PID
+ systemConfigMutable()->cpu_overclock = 1; //192MHz makes Multishot run a little better because of maths.
+
+// for (uint8_t pidProfileIndex = 0; pidProfileIndex < MAX_PROFILE_COUNT; pidProfileIndex++) {
+// pidProfile_t *pidProfile = pidProfilesMutable(pidProfileIndex);
+// pidProfile->dterm_notch_cutoff = 0;
+// }
+}
+
diff --git a/src/main/target/HELIOSPRING/target.c b/src/main/target/HELIOSPRING/target.c
new file mode 100755
index 000000000..e4f0434fa
--- /dev/null
+++ b/src/main/target/HELIOSPRING/target.c
@@ -0,0 +1,40 @@
+/*
+ * This file is part of Cleanflight.
+ *
+ * Cleanflight is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Cleanflight 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+
+#include <platform.h>
+#include "drivers/io.h"
+
+#include "drivers/dma.h"
+#include "drivers/timer.h"
+#include "drivers/timer_def.h"
+
+const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
+
+ DEF_TIM(TIM4, CH1, PB6, TIM_USE_ANY, 0, 0), // CAMERA_CONTROL_PIN
+ DEF_TIM(TIM12, CH1, PB14, TIM_USE_PWM | TIM_USE_PPM, 0, 0),
+
+ // Motors
+ DEF_TIM(TIM8, CH1, PC6, TIM_USE_MOTOR, 0, 0), // S1_OUT D1_ST7
+ DEF_TIM(TIM8, CH2, PC7, TIM_USE_MOTOR, 0, 0), // S2_OUT D1_ST2
+ DEF_TIM(TIM8, CH3, PC8, TIM_USE_MOTOR, 0, 1), // S3_OUT D1_ST6
+ DEF_TIM(TIM8, CH4, PC9, TIM_USE_MOTOR, 0, 0), // S4_OUT D1_ST1
+
+ // LED strip
+ DEF_TIM(TIM1, CH1, PA8, TIM_USE_LED, 0, 0), // D1_ST0
+};
diff --git a/src/main/target/HELIOSPRING/target.h b/src/main/target/HELIOSPRING/target.h
new file mode 100755
index 000000000..a9f157c3f
--- /dev/null
+++ b/src/main/target/HELIOSPRING/target.h
@@ -0,0 +1,232 @@
+/*
+ * This file is part of Cleanflight.
+ *
+ * Cleanflight is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Cleanflight 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#define TARGET_BOARD_IDENTIFIER "HESP"
+#define USBD_PRODUCT_STRING "HELIOSPRING"
+
+//#define MSP_OVER_CLI
+//#define USE_DYN_LPF
+
+#define LED0_PIN PB7
+
+#define USE_BEEPER
+#define BEEPER_PIN PC15
+#define BEEPER_INVERTED
+
+
+#define USE_GYRO
+#define USE_ACC
+#define GYRO_1_SPI_INSTANCE SPI1
+#define GYRO_1_CS_PIN PB1
+#define GYRO_1_ALIGN CW0_DEG
+#define GYRO_1_EXTI_PIN PB0
+
+#define USE_SPI
+#define USE_SPI_DEVICE_1
+
+#define GYRO_CONFIG_USE_GYRO_DEFAULT GYRO_CONFIG_USE_GYRO_1
+
+#define DEFAULT_ATTITUDE_UPDATE_INTERVAL 1000
+#define DEFAULT_ACC_SAMPLE_INTERVAL 1000
+
+#define USE_FAST_SPI_DRIVER
+#define USE_GYRO_IMUF9001
+#define USE_QUAT_IMUF9001
+#define USE_ACC_IMUF9001
+#define IMUF9001_CS_PIN PB1
+#define IMUF9001_RST_PIN PA4
+#define IMUF9001_SPI_INSTANCE SPI1
+#define USE_EXTI
+
+#define USE_MPU_DATA_READY_SIGNAL
+
+#define ENABLE_DSHOT_DMAR DSHOT_DMAR_ON
+
+#define FLASH_CS_PIN PC14
+#define FLASH_SPI_INSTANCE SPI3
+#define USE_FLASHFS
+#define USE_FLASH_M25P16
+
+#define USE_VCP
+
+#define VBUS_SENSING_PIN PC5
+
+#define USE_OSD
+#define USE_MAX7456
+#define MAX7456_SPI_INSTANCE SPI3
+#define MAX7456_SPI_CS_PIN PA15
+#define MAX7456_SPI_CLK (SPI_CLOCK_STANDARD) // 10MHz
+#define MAX7456_RESTORE_CLK (SPI_CLOCK_FAST)
+
+#define USE_UART1
+#define UART1_RX_PIN PA10
+#define UART1_TX_PIN PA9
+
+#define USE_UART2
+#define UART2_RX_PIN PA3
+#define UART2_TX_PIN PA2
+
+#define USE_UART3
+#define UART3_RX_PIN PB11
+#define UART3_TX_PIN PB10
+
+#define USE_UART4
+#define UART4_RX_PIN PC11
+//#define UART4_TX_PIN NONE // defaults to the vbat adc pin
+
+#define USE_UART5
+#define UART5_RX_PIN PD2
+#define UART5_TX_PIN PC12
+
+#define SERIAL_PORT_COUNT 6 //VCP, USART1, USART2, USART3, UART4, USART5
+
+#define USE_SPI
+
+#define USE_SPI_DEVICE_1
+#define SPI1_NSS_PIN PB1
+#define SPI1_SCK_PIN PB3
+#define SPI1_MISO_PIN PA6
+#define SPI1_MOSI_PIN PA7
+
+#define USE_DMA_SPI_DEVICE SPI1
+
+#define DMA_SPI_NSS_PIN_SRC GPIO_PinSource1
+#define DMA_SPI_NSS_PIN GPIO_Pin_1
+#define DMA_SPI_NSS_PORT GPIOB
+#define DMA_SPI_NSS_AF GPIO_AF_SPI1
+#define DMA_SPI_SCK_PIN_SRC GPIO_PinSource3
+#define DMA_SPI_SCK_PIN GPIO_Pin_3
+#define DMA_SPI_SCK_PORT GPIOB
+#define DMA_SPI_SCK_AF GPIO_AF_SPI1
+#define DMA_SPI_MISO_PIN_SRC GPIO_PinSource6
+#define DMA_SPI_MISO_PIN GPIO_Pin_6
+#define DMA_SPI_MISO_PORT GPIOA
+#define DMA_SPI_MISO_AF GPIO_AF_SPI1
+#define DMA_SPI_MOSI_PIN_SRC GPIO_PinSource7
+#define DMA_SPI_MOSI_PIN GPIO_Pin_7
+#define DMA_SPI_MOSI_PORT GPIOA
+#define DMA_SPI_MOSI_AF GPIO_AF_SPI1
+#define DMA_SPI_RST_MSK RCC_APB2RSTR_SPI1RST
+#define DMA_SPI_PER RCC->APB2RSTR
+
+#define DMA_SPI_SPI SPI1
+#define DMA_SPI_BAUDRATE SPI_BaudRatePrescaler_4
+#define DMA_SPI_CPOL SPI_CPOL_Low
+#define DMA_SPI_CPHA SPI_CPHA_1Edge
+
+#define DMA_SPI_DMA DMA2
+#define DMA_SPI_TX_DMA_STREAM DMA2_Stream3
+#define DMA_SPI_RX_DMA_STREAM DMA2_Stream2
+#define DMA_SPI_TX_DMA_CHANNEL DMA_Channel_3
+#define DMA_SPI_RX_DMA_CHANNEL DMA_Channel_3
+#define DMA_SPI_TX_DMA_HANDLER DMA2_Stream3_IRQHandler
+#define DMA_SPI_RX_DMA_HANDLER DMA2_Stream2_IRQHandler
+#define DMA_SPI_TX_DMA_IRQn DMA2_Stream3_IRQn
+#define DMA_SPI_RX_DMA_IRQn DMA2_Stream2_IRQn
+
+#define DMA_SPI_DMA_RX_PRE_PRI 0x0E
+#define DMA_SPI_DMA_RX_SUB_PRI 0x0E
+
+#define DMA_SPI_TX_DMA_FLAG_ALL DMA_FLAG_FEIF3 | DMA_FLAG_DMEIF3 | DMA_FLAG_TEIF3 | DMA_FLAG_HTIF3 | DMA_FLAG_TCIF3
+#define DMA_SPI_TX_DMA_FLAG_GL DMA_FLAG_TCIF3
+#define DMA_SPI_TX_DMA_FLAG_TC DMA_FLAG_TCIF3
+#define DMA_SPI_RX_DMA_FLAG_ALL DMA_FLAG_FEIF2 | DMA_FLAG_DMEIF2 | DMA_FLAG_TEIF2 | DMA_FLAG_HTIF2 | DMA_FLAG_TCIF2
+#define DMA_SPI_RX_DMA_FLAG_TC DMA_FLAG_TCIF2
+#define DMA_SPI_RX_DMA_FLAG_GL DMA_FLAG_TCIF2
+
+
+#define USE_SPI_DEVICE_2
+#define SPI2_NSS_PIN PB12
+#define SPI2_SCK_PIN PB13
+#define SPI2_MISO_PIN PC2
+#define SPI2_MOSI_PIN PC3
+
+#define USE_SPI_DEVICE_3
+#define SPI3_NSS_PIN PA15
+#define SPI3_SCK_PIN PC10
+#define SPI3_MISO_PIN PB4
+#define SPI3_MOSI_PIN PB5
+
+#define USE_I2C
+#define USE_I2C_DEVICE_2
+#define I2C2_SCL NONE // PB10, UART3_TX
+#define I2C2_SDA NONE // PB11, UART3_RX
+#define I2C_DEVICE (I2CDEV_2)
+
+#define USE_TARGET_CONFIG
+#define ENABLE_BLACKBOX_LOGGING_ON_SPIFLASH_BY_DEFAULT
+
+#define DEFAULT_RX_FEATURE FEATURE_RX_SERIAL
+#define SERIALRX_PROVIDER SERIALRX_SBUS
+#define SERIALRX_UART SERIAL_PORT_USART2
+#define DEFAULT_FEATURES (FEATURE_TELEMETRY | FEATURE_OSD | FEATURE_AIRMODE)
+
+#define USE_GPS
+#define USE_MAG
+#define USE_ESCSERIAL
+#define ESCSERIAL_TIMER_TX_PIN NONE // (HARDARE=0,PPM)
+//#define USE_SERIAL_4WAY_BLHELI_INTERFACE
+
+#define TARGET_IO_PORTA 0xffff
+#define TARGET_IO_PORTB 0xffff
+#define TARGET_IO_PORTC 0xffff
+#define TARGET_IO_PORTD (BIT(2))
+
+#define USABLE_TIMER_CHANNEL_COUNT 7
+#define USED_TIMERS ( TIM_N(1) | TIM_N(8) | TIM_N(4) | TIM_N(12) )
+
+#define USE_ACC_IMUF9001
+#define IMUF_RST_PIN GPIO_Pin_4
+#define IMUF_RST_PORT GPIOA
+#define IMUF_EXTI_PIN GPIO_Pin_0
+#define IMUF_EXTI_PORT GPIOB
+
+#define USE_ADC
+#define ADC_INSTANCE ADC1
+#define ADC1_DMA_OPT 0 // DMA 2 Stream 0 Channel 0
+
+#define DEFAULT_VOLTAGE_METER_SOURCE VOLTAGE_METER_ADC
+#define DEFAULT_CURRENT_METER_SOURCE CURRENT_METER_ADC
+#define CURRENT_METER_ADC_PIN PA1
+#define VBAT_ADC_PIN PA0
+#define CURRENT_METER_SCALE_DEFAULT 250
+#define VBAT_SCALE 109
+
+#define VBAT_SCALE 109
+
+#define CAMERA_CONTROL_PIN PB6 // define dedicated camera_osd_control pin
+
+#define IMUF_DEFAULT_PITCH_Q 3000
+#define IMUF_DEFAULT_ROLL_Q 3000
+#define IMUF_DEFAULT_YAW_Q 3000
+#define IMUF_DEFAULT_W 32
+#define IMUF_DEFAULT_LPF_HZ 120.0f
+
+#define USE_BUTTERED_PIDS true
+
+#define GYRO_1_CS_PIN PB1
+#define GYRO_1_RST_PIN PA4
+#define GYRO_1_SPI_INSTANCE SPI1
+#define USE_SPI_GYRO
+#define USE_EXTI
+#define USE_GYRO_EXTI
+#define GYRO_1_EXTI_PIN PB0
+#define GYRO_1_ALIGN CW0_DEG
+//#define ACC_1_ALIGN CW0_DEG
+#define TARGET_MANUFACTURER_IDENTIFIER "HESP"
diff --git a/src/main/target/HELIOSPRING/target.mk b/src/main/target/HELIOSPRING/target.mk
new file mode 100755
index 000000000..ced109e6f
--- /dev/null
+++ b/src/main/target/HELIOSPRING/target.mk
@@ -0,0 +1,8 @@
+
+F405_TARGETS += $(TARGET)
+FEATURES += VCP ONBOARDFLASH
+
+TARGET_SRC = stm32f4xx_crc.c \
+ drivers/dma_spi.c \
+ drivers/accgyro/accgyro_imuf9001.c \
+ drivers/max7456.c
\ No newline at end of file
diff --git a/src/main/target/STRIXF10/config.c b/src/main/target/STRIXF10/config.c
new file mode 100755
index 000000000..d4be21f6d
--- /dev/null
+++ b/src/main/target/STRIXF10/config.c
@@ -0,0 +1,57 @@
+/*
+ * This file is part of Cleanflight.
+ *
+ * Cleanflight is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Cleanflight 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+
+#include <platform.h>
+
+#include "config/config_eeprom.h"
+#include "drivers/pwm_output.h"
+#include "common/filter.h"
+#include "sensors/acceleration.h"
+#include "sensors/gyro.h"
+#include "sensors/battery.h"
+#include "telemetry/telemetry.h"
+#include "flight/mixer.h"
+#include "flight/pid.h"
+#include "fc/config.h"
+#include "fc/rc.h"
+#include "fc/rc_controls.h"
+#include "rx/rx.h"
+
+#include "pg/motor.h"
+
+#include "config_helper.h"
+
+
+void targetConfiguration(void) {
+ telemetryConfigMutable()->halfDuplex = false;
+ voltageSensorADCConfigMutable(VOLTAGE_SENSOR_ADC_VBAT)->vbatscale = VBAT_SCALE;
+ rxConfigMutable()->rcInterpolation = RC_SMOOTHING_MANUAL;
+ rxConfigMutable()->rcInterpolationInterval = 14;
+ rxConfigMutable()->rcInterpolationChannels = INTERPOLATION_CHANNELS_RPYT;
+ motorConfigMutable()->dev.motorPwmProtocol = PWM_TYPE_DSHOT600;
+ gyroConfigMutable()->gyro_sync_denom = 2; // 16KHZ GYRO
+ pidConfigMutable()->pid_process_denom = 1; // 16KHZ PID
+ systemConfigMutable()->cpu_overclock = 0; //192MHz makes Multishot run a little better because of maths.
+
+// for (uint8_t pidProfileIndex = 0; pidProfileIndex < MAX_PROFILE_COUNT; pidProfileIndex++) {
+// pidProfile_t *pidProfile = pidProfilesMutable(pidProfileIndex);
+// pidProfile->dterm_notch_cutoff = 0;
+// }
+}
+
diff --git a/src/main/target/STRIXF10/target.c b/src/main/target/STRIXF10/target.c
new file mode 100755
index 000000000..e4f0434fa
--- /dev/null
+++ b/src/main/target/STRIXF10/target.c
@@ -0,0 +1,40 @@
+/*
+ * This file is part of Cleanflight.
+ *
+ * Cleanflight is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Cleanflight 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+
+#include <platform.h>
+#include "drivers/io.h"
+
+#include "drivers/dma.h"
+#include "drivers/timer.h"
+#include "drivers/timer_def.h"
+
+const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
+
+ DEF_TIM(TIM4, CH1, PB6, TIM_USE_ANY, 0, 0), // CAMERA_CONTROL_PIN
+ DEF_TIM(TIM12, CH1, PB14, TIM_USE_PWM | TIM_USE_PPM, 0, 0),
+
+ // Motors
+ DEF_TIM(TIM8, CH1, PC6, TIM_USE_MOTOR, 0, 0), // S1_OUT D1_ST7
+ DEF_TIM(TIM8, CH2, PC7, TIM_USE_MOTOR, 0, 0), // S2_OUT D1_ST2
+ DEF_TIM(TIM8, CH3, PC8, TIM_USE_MOTOR, 0, 1), // S3_OUT D1_ST6
+ DEF_TIM(TIM8, CH4, PC9, TIM_USE_MOTOR, 0, 0), // S4_OUT D1_ST1
+
+ // LED strip
+ DEF_TIM(TIM1, CH1, PA8, TIM_USE_LED, 0, 0), // D1_ST0
+};
diff --git a/src/main/target/STRIXF10/target.h b/src/main/target/STRIXF10/target.h
new file mode 100755
index 000000000..ea68f9119
--- /dev/null
+++ b/src/main/target/STRIXF10/target.h
@@ -0,0 +1,228 @@
+/*
+ * This file is part of Cleanflight.
+ *
+ * Cleanflight is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Cleanflight 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#define TARGET_BOARD_IDENTIFIER "SX10"
+#define USBD_PRODUCT_STRING "STRIX Binary F10 by Helio"
+
+#define STM32F7
+//#undef USE_DSHOT_BITBANG
+
+#define LED0_PIN PB7
+
+#define BEEPER PC15
+#define BEEPER_INVERTED
+
+#define USE_GYRO
+#define USE_ACC
+#define GYRO_1_SPI_INSTANCE SPI1
+#define GYRO_1_CS_PIN PB1
+#define GYRO_1_ALIGN CW0_DEG
+#define GYRO_1_EXTI_PIN PB0
+
+#define USE_SPI
+#define USE_SPI_DEVICE_1
+
+#define GYRO_CONFIG_USE_GYRO_DEFAULT GYRO_CONFIG_USE_GYRO_1
+
+#define DEFAULT_ATTITUDE_UPDATE_INTERVAL 1000
+#define DEFAULT_ACC_SAMPLE_INTERVAL 1000
+
+#define USE_FAST_SPI_DRIVER
+#define USE_GYRO_IMUF9001
+#define USE_QUAT_IMUF9001
+#define USE_ACC_IMUF9001
+#define IMUF9001_CS_PIN PB1
+#define IMUF9001_RST_PIN PA4
+#define IMUF9001_SPI_INSTANCE SPI1
+#define USE_EXTI
+
+#define USE_MPU_DATA_READY_SIGNAL
+
+#define IMUF_RST_PIN GPIO_PIN_4
+#define IMUF_RST_PORT GPIOA
+#define IMUF_EXTI_PIN GPIO_PIN_0
+#define IMUF_EXTI_PORT GPIOB
+
+#define ENABLE_DSHOT_DMAR DSHOT_DMAR_ON
+
+#define FLASH_CS_PIN PC14
+#define M25P16_CS_PIN PC14
+#define FLASH_SPI_INSTANCE SPI3
+#define M25P16_SPI_INSTANCE SPI3
+#define USE_FLASH
+#define USE_FLASHFS
+#define USE_FLASH_M25P16
+
+#define USE_VCP
+
+#define VBUS_SENSING_PIN PC5
+
+#define USE_OSD
+#define USE_MAX7456
+#define MAX7456_SPI_INSTANCE SPI3
+#define MAX7456_SPI_CS_PIN PA15
+#define MAX7456_SPI_CLK (SPI_CLOCK_STANDARD) // 10MHz
+#define MAX7456_RESTORE_CLK (SPI_CLOCK_FAST)
+
+#define USE_UART1
+#define UART1_RX_PIN PA10
+#define UART1_TX_PIN PA9
+
+#define USE_UART2
+#define UART2_RX_PIN PA3
+#define UART2_TX_PIN PA2
+
+#define USE_UART3
+#define UART3_RX_PIN PB11
+#define UART3_TX_PIN PB10
+
+#define USE_UART4
+#define UART4_RX_PIN PC11
+#define UART4_TX_PIN NONE
+
+#define USE_UART5
+#define UART5_RX_PIN PD2
+#define UART5_TX_PIN PC12
+
+#define SERIAL_PORT_COUNT 6 //VCP, USART1, USART2, USART3, UART4, USART5
+
+#define USE_SPI
+
+#define USE_SPI_DEVICE_1
+#define SPI1_NSS_PIN PB1
+#define SPI1_SCK_PIN PB3
+#define SPI1_MISO_PIN PA6
+#define SPI1_MOSI_PIN PA7
+
+#define USE_HAL_F7_CRC
+
+#define USE_DMA_SPI_DEVICE SPI1
+
+#define DMA_SPI_NSS_PIN GPIO_PIN_1
+#define DMA_SPI_NSS_PORT GPIOB
+#define DMA_SPI_SCK_PIN GPIO_PIN_3
+#define DMA_SPI_SCK_PORT GPIOB
+#define DMA_SPI_SCK_AF GPIO_AF5_SPI1
+#define DMA_SPI_MISO_PIN GPIO_PIN_6
+#define DMA_SPI_MISO_PORT GPIOA
+#define DMA_SPI_MISO_AF GPIO_AF5_SPI1
+#define DMA_SPI_MOSI_PIN GPIO_PIN_7
+#define DMA_SPI_MOSI_PORT GPIOA
+#define DMA_SPI_MOSI_AF GPIO_AF5_SPI1
+
+#define DMA_SPI_SPI SPI1
+#define DMA_SPI_CLOCK_INIT_FUNC __HAL_RCC_SPI1_CLK_ENABLE()
+
+#define DMA_SPI_DMA DMA2
+#define DMA_SPI_TX_DMA_STREAM DMA2_Stream3
+#define DMA_SPI_RX_DMA_STREAM DMA2_Stream2
+#define DMA_SPI_TX_DMA_CHANNEL DMA_CHANNEL_3
+#define DMA_SPI_RX_DMA_CHANNEL DMA_CHANNEL_3
+#define DMA_SPI_TX_DMA_HANDLER DMA2_Stream3_IRQHandler
+#define DMA_SPI_RX_DMA_HANDLER DMA2_Stream2_IRQHandler
+#define DMA_SPI_TX_DMA_IRQn DMA2_Stream3_IRQn
+#define DMA_SPI_RX_DMA_IRQn DMA2_Stream2_IRQn
+
+#define DMA_SPI_DMA_RX_PRE_PRI 0x0E
+#define DMA_SPI_DMA_RX_SUB_PRI 0x0E
+#define DMA_SPI_DMA_TX_PRE_PRI 0x0D
+#define DMA_SPI_DMA_TX_SUB_PRI 0x0D
+
+#define DMA_SPI_BAUDRATE SPI_BAUDRATEPRESCALER_4
+
+#define USE_SPI_DEVICE_2
+#define SPI2_NSS_PIN PB12
+#define SPI2_SCK_PIN PB13
+#define SPI2_MISO_PIN PC2
+#define SPI2_MOSI_PIN PC3
+
+#define USE_SPI_DEVICE_3
+#define SPI3_NSS_PIN PA15
+#define SPI3_SCK_PIN PC10
+#define SPI3_MISO_PIN PB4
+#define SPI3_MOSI_PIN PB5
+
+#define USE_I2C
+#define USE_I2C_DEVICE_2
+#define I2C2_SCL NONE // PB10, UART3_TX
+#define I2C2_SDA NONE // PB11, UART3_RX
+#define I2C_DEVICE (I2CDEV_2)
+
+#define USE_TARGET_CONFIG
+#define ENABLE_BLACKBOX_LOGGING_ON_SPIFLASH_BY_DEFAULT
+
+#define DEFAULT_RX_FEATURE FEATURE_RX_SERIAL
+#define SERIALRX_PROVIDER SERIALRX_SBUS
+#define SERIALRX_UART SERIAL_PORT_USART2
+#define DEFAULT_FEATURES (FEATURE_TELEMETRY | FEATURE_OSD | FEATURE_AIRMODE)
+
+#define USE_GPS
+#define USE_MAG
+#define USE_ESCSERIAL
+#define ESCSERIAL_TIMER_TX_PIN NONE // (HARDARE=0,PPM)
+//#define USE_SERIAL_4WAY_BLHELI_INTERFACE
+
+#define TARGET_IO_PORTA 0xffff
+#define TARGET_IO_PORTB 0xffff
+#define TARGET_IO_PORTC 0xffff
+#define TARGET_IO_PORTD (BIT(2))
+
+#define USABLE_TIMER_CHANNEL_COUNT 7
+#define USED_TIMERS ( TIM_N(1) | TIM_N(8) | TIM_N(4) | TIM_N(12) )
+
+#define IMUF_BIT_I2C_IF_DIS (1 << 4)
+
+
+#define USE_ADC
+#define ADC_INSTANCE ADC1
+#define ADC1_DMA_OPT 0 // DMA 2 Stream 0 Channel 0
+
+#define DEFAULT_VOLTAGE_METER_SOURCE VOLTAGE_METER_ADC
+#define DEFAULT_CURRENT_METER_SOURCE CURRENT_METER_ADC
+#define CURRENT_METER_ADC_PIN PA1
+#define VBAT_ADC_PIN PA0
+#define CURRENT_METER_SCALE_DEFAULT 250
+#define VBAT_SCALE 109
+
+#define CAMERA_CONTROL_PIN PB6 // define dedicated camera_osd_control pin
+
+#define IMUF_DEFAULT_PITCH_Q 3000
+#define IMUF_DEFAULT_ROLL_Q 3000
+#define IMUF_DEFAULT_YAW_Q 3000
+#define IMUF_DEFAULT_W 32
+#define IMUF_DEFAULT_LPF_HZ 120.0f
+
+#define USE_BUTTERED_PIDS true
+
+#define DEFAULT_PIDS_ROLL {45, 50, 30, 0}
+#define DEFAULT_PIDS_PITCH {45, 50, 30, 0}
+#define DEFAULT_PIDS_YAW {45, 50, 30, 0}
+
+
+#define GYRO_1_CS_PIN PB1
+#define GYRO_1_RST_PIN PA4
+#define GYRO_1_SPI_INSTANCE SPI1
+#define USE_SPI_GYRO
+#define USE_EXTI
+#define USE_GYRO_EXTI
+#define GYRO_1_EXTI_PIN PB0
+#define GYRO_1_ALIGN CW0_DEG
+//#define ACC_1_ALIGN CW0_DEG
+
+#define TARGET_MANUFACTURER_IDENTIFIER "SF10"
diff --git a/src/main/target/STRIXF10/target.mk b/src/main/target/STRIXF10/target.mk
new file mode 100755
index 000000000..c0dc166ec
--- /dev/null
+++ b/src/main/target/STRIXF10/target.mk
@@ -0,0 +1,6 @@
+F7X2RE_TARGETS += $(TARGET)
+FEATURES += VCP ONBOARDFLASH
+
+TARGET_SRC = drivers/dma_spi_hal.c \
+ drivers/accgyro/accgyro_imuf9001.c \
+ drivers/max7456.c
\ No newline at end of file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment