Building custom firmware - iNavFlight/inav GitHub Wiki
Rationale
Prebuilt targets may not include the features you wish to use. If a target already exists, it is relatively simple to build your own custom firmware.
This guide provides a high level overview. It is not a detailed development guide.
Prerequisite
You need a working development environment. There is developer / build environment documentation for the major platforms (Linux, MacOS, Windows).
Target Specific Files
Overview
For basic configuration changes, the files are found under src/main/targets/NAME
. At the top level this includes a separate directory for each target.
This article considers a prototype flight controller QUARKVISION
that was never put into production.
$ cd inav/src/main/target
$ ls QUARKVISION
CMakeFiles CMakeLists.txt README.md target.h
cmake_install.cmake config.c target.c
The CMakefles
directory and cmake_install.cmake
are generated by the build system; the other files are:
CMakeLists.txt
: Mandatory, defines the target name and variantsREADME.md
: Optional, information about the targettarget.h
: Mandatory, defines capabilities and definitions (e.g. sensors, pin definitions)target.c
: Mandatory, defines timers and usage (e.g. for motors and servos)config.c
: Mandatory, defines configuration defaults (RX type etc).
CMakeLists.txt
The QUARKVISION
example contains a single line:
target_stm32f405xg(QUARKVISION HSE_MHZ 16 SKIP_RELEASES)
Here is the definition for:
- The processor class
stm32f405xg
- The target name
QUARKVISION
- Additional parameters
HSE_MHZ 16
(an optional parameter defining a non-default high-speed external (HSE) oscillator clock required by this board) andSKIP_RELEASES
as this is not an official target.
If we had other variants, for example a V2 variant with different sensors, we could add another line, for example:
target_stm32f405xg(QUARKVISION_V2 HSE_MHZ 16 SKIP_RELEASES)
We can then reference the QUARKVISION_V2
in target.c
or target.h
to handle the different capabilities of each variation.
See the developer documentation for more information, including a more detailed CMakeLists.txt
and a list of processor options.
target.h
target.h
contains hardware definitions, a fragment is below:
#pragma once
#define TARGET_BOARD_IDENTIFIER "QRKV"
#define USBD_PRODUCT_STRING "QuarkVision"
...
#define BEEPER PC15
#define BEEPER_INVERTED
#define USE_UART_INVERTER
#define INVERTER_PIN_UART2 PB2 // PB2 used as inverter select GPIO
#define INVERTER_PIN_UART2_RX PB2 // PB2 used as inverter select GPIO
#define MPU6000_CS_PIN PC1
#define MPU6000_SPI_BUS BUS_SPI2
#define USE_IMU_MPU6000
#define IMU_MPU6000_ALIGN CW270_DEG
// MPU6000 interrupts
#define USE_EXTI
#define GYRO_INT_EXTI PC0
#define USE_MPU_DATA_READY_SIGNAL
//*************** MAG *****************************
#define USE_MAG
#define MAG_I2C_BUS BUS_I2C3
#define USE_MAG_HMC5883
#define USE_MAG_MAG3110
#define USE_MAG_QMC5883
#define USE_MAG_AK8963
#define USE_MAG_AK8975
...
Of note:
TARGET_BOARD_IDENTIFIER
this should be unique in the first 4 bytes. If the mythicalQUARKVISION_V2
existed, it would need a separate ID. For example:
#if defined(QUARKVISION_V2)
# define TARGET_BOARD_IDENTIFIER "QVV2"
#else
# define TARGET_BOARD_IDENTIFIER "QRKV"
#endif
This pattern is required for each variation and the features affected by the variation.
The file fragment then defines hardware options:
- Pins, Busses
- Sensors, for example the
#define USE_MAG
stanza which defines theMAG_I2C_BUS
I2C bus for the compass, and the different compass types supported on this board.
There will similar stanzas for all the available sensor components.
target.c
target.c
defines the timer and channel usage. The association between timers and channels is provided by the vendor MCU documentation. This defines an array of timerHardware_t
, in turn defined by the DEF_TIM
(define timer) macro.
...
timerHardware_t timerHardware[] = {
DEF_TIM(TIM1, CH3, PA10, TIM_USE_PPM, 0, 0), // S1_IN_PPM A01
DEF_TIM(TIM8, CH2, PC7, TIM_USE_ANY, 0, 0), // SSERIAL1 RX c07
DEF_TIM(TIM8, CH1, PC6, TIM_USE_ANY, 0, 0), // SSERIAL1 TX
DEF_TIM(TIM2, CH1, PA15, 0, 0, 0), // LED A15
DEF_TIM(TIM3, CH3, PB0, TIM_USE_OUTPUT_AUTO, 0, 0), // S1_OUT
DEF_TIM(TIM3, CH4, PB1, TIM_USE_OUTPUT_AUTO, 0, 0), // S2_OUT
DEF_TIM(TIM12, CH1, PB14, TIM_USE_OUTPUT_AUTO, 0, 0), // S3_OUT
DEF_TIM(TIM12, CH2, PB15, TIM_USE_OUTPUT_AUTO, 0, 0), // S4_OUT
DEF_TIM(TIM11, CH1, PB9, TIM_USE_OUTPUT_AUTO, 0, 0), // S5_OUT
DEF_TIM(TIM10, CH1, PB8, TIM_USE_OUTPUT_AUTO, 0, 0), // S6_OUT
DEF_TIM(TIM3, CH2, PB5, TIM_USE_OUTPUT_AUTO, 0, 0), // S7_OUT
DEF_TIM(TIM3, CH1, PB4, TIM_USE_OUTPUT_AUTO, 0, 0), // S8_OUT
DEF_TIM(TIM8, CH3, PC8, TIM_USE_OUTPUT_AUTO, 0, 0), // S9_OUT
DEF_TIM(TIM2, CH2, PB3, TIM_USE_OUTPUT_AUTO, 0, 0), // S10_OUT
};
...
The parameters are:
TIMn
: The timerCHn
: The channelPxy
: The hardware (MCU) pin- The usage function(s) available in this pin. Note that each timer is assigned a rate defined by function, so it is inadvisable to have both
MOTOR
andSERVO
definition on the same timer.TIM_USE_OUTPUT_AUTO
will let INAV assign the output to eitherMOTOR
orSERVO
automatically. - The final two parameters (
flags
,dmavar
are hardware specific / required for DMA (e.g. DSHOT), which is turn is defined by#define USE_DSHOT
intarget.h
. See vendor's technical definitions perhaps compared to comparable targets. The example target here does not defineUSE_DSHOT
and the values are 0. These parameters provide a DMA descriptor table compatible with Betaflight.
Adding a new source file
If a new source file is added outside of the target/NAME
directory, it must be added to the top level src/main/CMakeLists.txt
.
Further reading
- Read the fine source, base your target / changes on a supported target with similar characteristics
- Read the developer / build environment documentation
Other recommendations
Use a separate branch
$ git checkout -b my_super_special_branch
This will isolate your work from the base repo and facilitate making a pull request if you decide to contribute your changes back to the project.
Building
Build the target.
$ make -j $(nproc) QUARKVISION
## or (using ninja as the build manager)
$ ninja QUARKVISION
...
[365/366] Linking C executable bin/QUARKVISION.elf
Memory region Used Size Region Size %age Used
FLASH: 519160 B 896 KB 56.58%
FLASH_CONFIG: 0 GB 128 KB 0.00%
RAM: 76476 B 128 KB 58.35%
CCM: 13852 B 64 KB 21.14%
BACKUP_SRAM: 0 GB 4 KB 0.00%
MEMORY_B1: 0 GB 0 GB
[366/366] cd /home/jrh/Projects/fc/ina.../inav/build/inav_6.0.0_QUARKVISION.hex
Fix any errors / warnings
If you changes introduce compiler warnings, please fix them. Submissions (pull requests) with compiler errors / warnings will not be accepted. If your changes overflow the flash size, consider removing unwanted features in target.h
. Your target.h
can always #undef
generic features from src/main/target/common.h
(e.g. unwanted RX or telemetry options).
Commit your changes
You can now commit the changes to your branch, e.g. git commit -a -m "my descriptive commit message"
; otherwise if one wanted to update to the upstream the source tree (e.g.)
git pull
git will complain that there are uncommitted changes and won't perform the update.
- Commit to your private branch as above ; or
$ git reset --hard
before pulling ; or- Stash away the original files and restore them after pulling.
The developer documentation has more information on synchronising a custom branch with upstream Github.
Other tools and resources
Migrate Betaflight Targets
There is a script in the repo that can help automate conversion of Betaflight targets to INAV. The developer, @mosca, will be grateful for any reports of success (or failure).
Paweł Spychalski has also made YouTube videos on the subject.