Table of Contents
Since BetaFlight 4.0, creating a new target can be resumed to fill up a configuration file. However, making a working pinout for the STM32 require a more indeep knowledge of the microcontroleur internal structure.
We will cover the whole process in this post, based on my TankFC project.
Building a STM32 pinout
Flight controller interfaces
A flight controller can be seen as a central micro-processor (STM32F3, F4, F7 etc) with a lot of component around it, onboard or external. Each of those component communicates with the micro-processor through an interface.
We can see that different interface are used. Some are widespread standard (I2C, UART, SPI), and other have been specifically developped for Betaflight, like DSHOT. I will not enter into the details of each interface, there is plenty of ressource of the internet already.
Just remenber that for a given interface, a component using it must be connected to STM32’s pins that support that interface.
STM32F7 peripheral mapping
Now it’s time to dive into the STM32 internals. Here the internal block diagram of a STM32F1 chip (you don’t want to see the F7 diagram..). Each block represent a peripheral, i.e an hardware block that the Cortex-M processor can configure to perform a specific task. Example of peripheral used in a flight controller are:
- and many other
In order to communicate with the outside world, those peripherals must be linked to I/O pads of the IC. By default, all pins are configured as GPIO (General purpose I/O). But not every pins can be linked to every peripheral. This information can be found in the reference manual of each specific STM32 used(ex for STM32F722).
A huge array gives the function that can be attributed to each pin. On the example below, the pin PA1 (which is on the pad 15 for a LQFP64 package) can be used for either ADC input, TIM2, TIM1, UART4_TX, etc..
We will now check for each component of a flight controller it’s requirement when capturing the schematic. All example below are from my TankFC using a STM32F722, but it will be very similar with others STM32 devices.
The Betaflight code use a 8Mhz quartz for clocking the STM32. This quartz have dedicated pins.
Same for the USB data line, there is dedicated pins that must be used.
OSD IC MAX7456
This IC communicates by SPI with the STM32. Pick a SPI block, and use all the SPI signals from that block. The CS (Chip Select) signal can just use any GPIO. The example below shows a configuration using SPI3, and PA15 as a GPIO for CS.
The flash chip communicates by SPI as well. Same procedure as the OSD IC, just don’t reuse the same SPI block.
Most of the gyroscope IC communicates by SPI. If the gyro IC has an interruption line, you can connect it to any pin.
Those sensors usually use I2C to communicate. Here is an example using the I2C1 block:
For analog sensor input, pins with analog capabilitie must be used.
Vtx SmartAudio/ Tramp
Those protocols use an UART interface. Only the Tx line is used. Pick a pin that can be mapped to an USARTx_TX function.
External GPS modules communicate by UART with the STM32, and use both Tx and Rx line of the same UART block. Caution, the Tx line of the STM32 must be connected to the Rx line of the GPS, and vice-versa.
There is two type of interface for controlling FPV camera:
- UART interface (using both Tx and Rx). Mostly found for Split camera type
- Joystick emulation. Use a dedicated timer for it (i.e not used for anything else). More info here.
To get telemetry from the ESC, use a dedicated UART. Connect it to the Rx pin only.
Several protocol have been used to control ESC, the most used right now is DSHOT. All of these protocols are based on timer block. Each timer have several output channel (CHx). For motor output, any timer and any channel can be used. Several channel of the same timer can also be used.
This component is more tricky to interface due to the number of protocol and manufacturer available. First of all, only UART based protocol will be covered here. Second, on F7 chip, UART can be inverted by software, so I won’t make the distinction between inverted and uninverted protocol. Check out Oscar Liang blog for more details about RC protocol.
Crossfire: For Crossfire, you need an UART, both Tx and Rx.
SBUS, IBUS, etc: For those protocols, you need only the Rx pin of an UART.
S.Port: For telemetry protocol like S.Port, you need the Tx line of an UART. Caution, it’s need to be a dedicated UART, you cannot use the same UART as SBUS for example.
F.Port: To avoid using two UART, FrSky released F.Port, a half-duplex protocol that combine Rx link and telemetry. It uses only the Tx line of an UART.
Some other component can be controlled by the STM32:
- Status LED: Connect to any pin
- PIT mode control: Connect to any pin
- Buzzer : Connect to a timer capable pin
- Boot button: Use the dedicated pin called “BOOT0”
Creating the Betaflight target
In Betaflight 4.0, the Unified target system was introduced. Before that, each target had it’s own specific binary file to flash into the STM32. With the unified target system, there is only one binary for each type of STM32. All the specific I/O mapping of a target is done through the CLI. So to create a new target, you only need to fill a TARGETNAME.config file that will be pasted into the CLI to configure the board with the correct pinout.
There is already a tutorial on the Betaflight repo to create an unifed target from a legacy target. I will details here the creation of a unified targer from scratch. To start, create a new file. Change it extension to “.config“, and open it with any text editor.
First, we link every pin to their function using the ressource command.
Timer pins need a bit more configuration:
DMA ressource assignement are also in the reference manual of the STM32.
Next, we configure each component to use the right interface. The orientation of the gyroscope on the board must also be precised.
The motor output are disabled by default, as a DSHOT signal sent to an old PWM ESC may spin the motor unintentionnaly.
That the very basic setup to get a new pinout working. More parameters can be then tuned through the GUI and added to the .config file.
Flashing a new unified target
If your configuration file haven’t been added to the Betaflight repository (I think only commercialy available boards can be added), follow these step:
- Plug the board in DFU mode (boot button pressed)
- In Betaflight configurator, flash the board with the target corresponding to the board STM32. For a STM32F722, it will be “STM32F7x2”
- Once its flashed, connect to the board and copy paste your config file in the CLI. Save.
- Reboot the board. The status LED should work now. Check that everything works as expected.
And that’s it. Once the configuration file is done and tested, you can submit a pull request so that your target will be accessible from the Betaflight Configurator.
I hope this post will help anyone making a new flight controller. Please note that this method come from my understanding of how Betaflight works, and based on the documentation and code I’ve found. It worked very well for my TankFC board, but it may not be 100% exact or error free. Let me know if you find anything incorrect.
2 thoughts on “Creating a Betaflight target from scratch”
Hi, is it really required that 8 Mhz crystal or as you know STM32’s have own crystal rates and these rates are OK for designs? Thanks.
Indeed STM32F7 can run from an internal oscillator. However I don’t know if the standard Betaflight is configured that way. I assumed it was neccessary as every flight controller I’ve seen have this 8Mhz crystal. You better ask on the betaflight project for confirmation I think.