Creating your own platform can be a good way of saving work by …
- Tailoring a config that is specific to your product or project!
- To make sure you have sensible default values for parameters
- Or to make sure that the initialization is done correctly
If you contribute it to the main Bitcraze repository it is also a way to distribute your work! So how do you do it? Follow these steps!
Add your platform to Kconfig
To make it possible to select your platform for the build you need to add it to
a Kconfig
file. You can find the platform selection in the root Kconfig
file.
Right now the selction looks like:
menu "Platform configuration"
choice
prompt "Platform to build"
default CONFIG_PLATFORM_CF2
config PLATFORM_CF2
bool "Build for CF2"
select SENSORS_BMI088_BMP3XX
select SENSORS_MPU9250_LPS25H
config PLATFORM_BOLT
bool "Build for Bolt"
select SENSORS_BMI088_BMP3XX
select SENSORS_BMI088_SPI
config PLATFORM_TAG
bool "Build for the roadrunner"
select SENSORS_BMI088_BMP3XX
endchoice
Let’s add our own platform, RINCEWIND
, which has the same sensors as the Bolt.
menu "Platform configuration"
choice
prompt "Platform to build"
default CONFIG_PLATFORM_CF2
config PLATFORM_CF2
bool "Build for CF2"
select SENSORS_BMI088_BMP3XX
select SENSORS_MPU9250_LPS25H
config PLATFORM_BOLT
bool "Build for Bolt"
select SENSORS_BMI088_BMP3XX
select SENSORS_BMI088_SPI
config PLATFORM_TAG
bool "Build for the roadrunner"
select SENSORS_BMI088_BMP3XX
config PLATFORM_RINCEWIND
bool "Build for the Rincewind platform"
select SENSORS_BMI088_BMP3XX
select SENSORS_BMI088_SPI
endchoice
This creates the CONFIG_PLATFORM_RINCEWIND
variable, usable both from C code as a define (when you include autoconf.h
) as well as an environment variable usable from the Makefiles and the Kbuild files.
Add a init source file to Kbuild
We need to add a entry point for your platform. The way the build system determines which platform init file to include is found in the src/platform/src/Kbuild
file:
obj-$(CONFIG_PLATFORM_BOLT) += platform_bolt.o
obj-$(CONFIG_PLATFORM_CF2) += platform_cf2.o
obj-$(CONFIG_PLATFORM_CF21BL) += platform_cf21bl.o
obj-$(CONFIG_PLATFORM_TAG) += platform_tag.o
obj-y += platform.o
obj-y += platform_stm32f4.o
obj-y += platform_utils.o
Let’s add RINCEWIND
:
obj-$(CONFIG_PLATFORM_BOLT) += platform_bolt.o
obj-$(CONFIG_PLATFORM_CF2) += platform_cf2.o
obj-$(CONFIG_PLATFORM_CF21BL) += platform_cf21bl.o
obj-$(CONFIG_PLATFORM_TAG) += platform_tag.o
obj-$(CONFIG_PLATFORM_RINCEWIND) += platform_rincewind.o
obj-y += platform.o
obj-y += platform_stm32f4.o
obj-y += platform_utils.o
We will base the src/platform/src/platform_rincewind.c
file on the bolt:
#define DEBUG_MODULE "PLATFORM"
#include <string.h>
#include "platform.h"
#include "exti.h"
#include "nvic.h"
#include "debug.h"
static platformConfig_t configs[] = {
#ifdef CONFIG_SENSORS_BMI088_SPI
{
.deviceType = "CB10",
.deviceTypeName = "Rincewind",
.sensorImplementation = SensorImplementation_bmi088_spi_bmp3xx,
.physicalLayoutAntennasAreClose = false,
.motorMap = motorMapBoltBrushless,
}
#endif
};
const platformConfig_t* platformGetListOfConfigurations(int* nrOfConfigs) {
*nrOfConfigs = sizeof(configs) / sizeof(platformConfig_t);
return configs;
}
void platformInitHardware() {
// Low level init: Clock and Interrupt controller
nvicInit();
// EXTI interrupts
extiInit();
}
const char* platformConfigGetPlatformName() {
return "Rincewind";
}
The platformInitHardware()
and platformGetListOfConfigurations()
functions is called by platform.c
as part of general init of the device.
Add platform default parameter values
Your platform need to define suitable default values to (persistent) parameters. To do this we will need to create a src/platform/interface/platform_rincewind.h
and make sure that this gets included when we build for the RINCEWIND
platform. This is done by adding to the src/platform/interface/platform_defaults.h
:
#pragma once
#define __INCLUDED_FROM_PLATFORM_DEFAULTS__
#ifdef CONFIG_PLATFORM_CF2
#include "platform_defaults_cf2.h"
#endif
#ifdef CONFIG_PLATFORM_CF21BL
#include "platform_defaults_cf21bl.h"
#endif
#ifdef CONFIG_PLATFORM_BOLT
#include "platform_defaults_bolt.h"
#endif
#ifdef CONFIG_PLATFORM_TAG
#include "platform_defaults_tag.h"
#endif
Becomes:
#pragma once
#define __INCLUDED_FROM_PLATFORM_DEFAULTS__
#ifdef CONFIG_PLATFORM_CF2
#include "platform_defaults_cf2.h"
#endif
#ifdef CONFIG_PLATFORM_CF21BL
#include "platform_defaults_cf21bl.h"
#endif
#ifdef CONFIG_PLATFORM_BOLT
#include "platform_defaults_bolt.h"
#endif
#ifdef CONFIG_PLATFORM_TAG
#include "platform_defaults_tag.h"
#endif
#ifdef CONFIG_RINCEWIND
#include "platform_defaults_bolt.h"
#include "platform_defaults_rincewind.h"
#endif
We base it on the default parameters for the Bolt. To determine how to add content to platform_defaults_rincewind.h
please check what is added to the existing platforms.
Add a platform default config
To make it easier for people to build for RINCEWIND
we can add a defconfig
for it. This is done by adding a file in the configs/
folder. Let us look at bolt_defconfig
:
CONFIG_PLATFORM_BOLT=y
CONFIG_ESTIMATOR_AUTO_SELECT=y
CONFIG_CONTROLLER_AUTO_SELECT=y
Based on this a start of rincewind_defconfig
could be:
CONFIG_PLATFORM_RINCEWIND=y
CONFIG_ESTIMATOR_AUTO_SELECT=y
CONFIG_CONTROLLER_AUTO_SELECT=y
Then RINCEWIND
platform could be built by:
$ make rincewind_defconfig
make[1]: Entering directory '/home/jonasdn/sandbox/kbuild-firmware/build'
GEN ./Makefile
#
# configuration written to .config
#
make[1]: Leaving directory '/home/jonasdn/sandbox/kbuild-firmware/build'
$ make -j 12
[...]
Need a different power distribution?
Suppose our new platform is a car with 4 wheels, then we will need a new power distribution function, that is
the translation from roll, pitch and yaw to motor power. The default implementation can be found in
src/modules/src/power_distribution_quadrotor.c
but now we need to write a new function that works for cars.
The first step is to add a car power distrbution setting to the configuration.
In the standard configuration, the quadrotor power distribution is the only option and it is used by all platforms.
Edit src/modules/src/Kconfig
and
find the location where the power distribution is configured
choice
prompt "Type of power distribution"
default POWER_DISTRIBUTION_QUADROTOR
config POWER_DISTRIBUTION_QUADROTOR
bool "Quadrotor power distribution"
depends on PLATFORM_CF2 || PLATFORM_BOLT || PLATFORM_TAG
help
Power distribution function for quadrotors
endchoice
Now add a new car distribution setting and make it available for your platform.
choice
prompt "Type of power distribution"
default POWER_DISTRIBUTION_QUADROTOR
config POWER_DISTRIBUTION_QUADROTOR
bool "Quadrotor power distribution"
depends on PLATFORM_CF2 || PLATFORM_BOLT || PLATFORM_TAG
help
Power distribution function for quadrotors
config POWER_DISTRIBUTION_CAR
bool "Car power distribution"
depends on PLATFORM_RINCEWIND
help
Power distribution function for cars
endchoice
The next step is to add an implementation of the power distribution function. Copy
power_distribution_quadrotor.c
into a new file, power_distribution_car.c
and modify the
powerDistribution()
function to fit your needs. Also modify the powerDistributionCap()
, this function is responsible
for limiting the thrust to the valid range [0 - UINT16_MAX].
The final step is to add the c file to the build. Open src/modules/src/Kbuild
and add your new file.
obj-$(CONFIG_POWER_DISTRIBUTION_CAR) += power_distribution_car.o
And you are done! You have created your own platform, good job!