Merge pull request #2481 from paparazzi/crazyflie_2.1-integration

Crazyflie 2.1 integration
This commit is contained in:
Gautier Hattenberger
2020-01-13 23:32:22 +01:00
committed by GitHub
38 changed files with 5697 additions and 28 deletions
@@ -0,0 +1,219 @@
<!DOCTYPE airframe SYSTEM "../../airframe.dtd">
<!-- Crazyflie 2.1 -->
<airframe name="Crazyflie2">
<firmware name="rotorcraft">
<configure name="PERIODIC_FREQUENCY" value="1000"/>
<configure name="RTOS_DEBUG" value="0"/>
<target name="ap" board="crazyflie_2.1">
<module name="gps" type="datalink"/>
</target>
<target name="nps" board="pc">
<module name="gps" type="ublox"/>
<module name="fdm" type="jsbsim"/>
</target>
<module name="motor_mixing"/>
<module name="actuators" type="pwm"/>
<module name="syslink_dl"/>
<module name="radio_control" type="datalink"/>
<module name="telemetry" type="transparent"/>
<module name="imu" type="bmi088_i2c">
<configure name="IMU_BMI088_I2C_DEV" value="i2c3"/>
<define name="IMU_BMI088_GYRO_I2C_ADDR" value="BMI088_GYRO_ADDR_ALT"/>
<define name="IMU_BMI088_Y_SIGN" value="-1"/>
<define name="IMU_BMI088_Z_SIGN" value="-1"/>
</module>
<module name="stabilization" type="int_quat"/>
<module name="ahrs" type="madgwick">
<configure name="AHRS_PROPAGATE_FREQUENCY" value="1000"/>
<!--configure name="USE_MAGNETOMETER" value="FALSE"/-->
</module>
<module name="ins"/>
<module name="sys_mon"/>
<module name="air_data"/>
<module name="baro_bmp3">
<configure name="BMP3_I2C_DEV" value="i2c3"/>
<define name="AIR_DATA_BARO_ABS_ID" value="BARO_BMP3_SENDER_ID"/>
<define name="BMP3_SLAVE_ADDR" value="BMP3_I2C_ADDR_ALT"/>
</module>
</firmware>
<firmware name="test_chibios">
<target name="test_sys_time_timer" board="crazyflie_2.1"/>
<target name="test_led" board="crazyflie_2.1"/>
<target name="test_sys_gpio" board="crazyflie_2.1"/>
</firmware>
<commands>
<axis name="ROLL" failsafe_value="0"/>
<axis name="PITCH" failsafe_value="0"/>
<axis name="YAW" failsafe_value="0"/>
<axis name="THRUST" failsafe_value="0"/>
</commands>
<servos driver="Pwm">
<servo name="FRONT_LEFT" no="4" min="0" neutral="20" max="255"/>
<servo name="FRONT_RIGHT" no="1" min="0" neutral="20" max="255"/>
<servo name="BACK_RIGHT" no="2" min="0" neutral="20" max="255"/>
<servo name="BACK_LEFT" no="3" min="0" neutral="20" max="255"/>
</servos>
<section name="MIXING" prefix="MOTOR_MIXING_">
<define name="TYPE" value="QUAD_X"/>
</section>
<command_laws>
<call fun="motor_mixing_run(autopilot.motors_on,FALSE,values)"/>
<set servo="FRONT_LEFT" value="motor_mixing.commands[MOTOR_FRONT_LEFT]"/>
<set servo="FRONT_RIGHT" value="motor_mixing.commands[MOTOR_FRONT_RIGHT]"/>
<set servo="BACK_RIGHT" value="motor_mixing.commands[MOTOR_BACK_RIGHT]"/>
<set servo="BACK_LEFT" value="motor_mixing.commands[MOTOR_BACK_LEFT]"/>
</command_laws>
<section name="IMU" prefix="IMU_">
<define name="ACCEL_X_NEUTRAL" value="-19"/>
<define name="ACCEL_Y_NEUTRAL" value="-12"/>
<define name="ACCEL_Z_NEUTRAL" value="58"/>
<define name="ACCEL_X_SENS" value="1.83754430011" integer="16"/>
<define name="ACCEL_Y_SENS" value="1.8445793586" integer="16"/>
<define name="ACCEL_Z_SENS" value="1.84794644385" integer="16"/>
<!-- replace this with your own calibration -->
<!--define name="MAG_X_NEUTRAL" value="-179"/>
<define name="MAG_Y_NEUTRAL" value="-21"/>
<define name="MAG_Z_NEUTRAL" value="79"/>
<define name="MAG_X_SENS" value="4.17334785618" integer="16"/>
<define name="MAG_Y_SENS" value="3.98885954135" integer="16"/>
<define name="MAG_Z_SENS" value="4.40442339014" integer="16"/-->
<define name="BODY_TO_IMU_PHI" value="0." unit="deg"/>
<define name="BODY_TO_IMU_THETA" value="0." unit="deg"/>
<define name="BODY_TO_IMU_PSI" value="0." unit="deg"/>
</section>
<section name="AHRS" prefix="AHRS_">
<define name="H_X" value="0.3770441"/>
<define name="H_Y" value="0.0193986"/>
<define name="H_Z" value="0.9259921"/>
<!-- Use GPS heading instead of magneto -->
<define name="USE_GPS_HEADING" value="1"/>
<define name="HEADING_UPDATE_GPS_MIN_SPEED" value="0"/>
</section>
<section name="INS" prefix="INS_">
</section>
<section name="STABILIZATION_RATE" prefix="STABILIZATION_RATE_">
<!-- setpoints -->
<define name="SP_MAX_P" value="10000"/>
<define name="SP_MAX_Q" value="10000"/>
<define name="SP_MAX_R" value="10000"/>
<define name="DEADBAND_P" value="20"/>
<define name="DEADBAND_Q" value="20"/>
<define name="DEADBAND_R" value="200"/>
<define name="REF_TAU" value="4"/>
<!-- feedback -->
<define name="GAIN_P" value="400"/>
<define name="GAIN_Q" value="400"/>
<define name="GAIN_R" value="350"/>
<define name="IGAIN_P" value="75"/>
<define name="IGAIN_Q" value="75"/>
<define name="IGAIN_R" value="50"/>
<!-- feedforward -->
<define name="DDGAIN_P" value="300"/>
<define name="DDGAIN_Q" value="300"/>
<define name="DDGAIN_R" value="300"/>
</section>
<section name="STABILIZATION_ATTITUDE" prefix="STABILIZATION_ATTITUDE_">
<!-- setpoints -->
<define name="SP_MAX_PHI" value="45." unit="deg"/>
<define name="SP_MAX_THETA" value="45." unit="deg"/>
<define name="SP_MAX_R" value="90." unit="deg/s"/>
<define name="DEADBAND_A" value="0"/>
<define name="DEADBAND_E" value="0"/>
<define name="DEADBAND_R" value="250"/>
<!-- reference -->
<define name="REF_OMEGA_P" value="400" unit="deg/s"/>
<define name="REF_ZETA_P" value="0.85"/>
<define name="REF_MAX_P" value="400." unit="deg/s"/>
<define name="REF_MAX_PDOT" value="RadOfDeg(8000.)"/>
<define name="REF_OMEGA_Q" value="400" unit="deg/s"/>
<define name="REF_ZETA_Q" value="0.85"/>
<define name="REF_MAX_Q" value="400." unit="deg/s"/>
<define name="REF_MAX_QDOT" value="RadOfDeg(8000.)"/>
<define name="REF_OMEGA_R" value="250" unit="deg/s"/>
<define name="REF_ZETA_R" value="0.85"/>
<define name="REF_MAX_R" value="180." unit="deg/s"/>
<define name="REF_MAX_RDOT" value="RadOfDeg(1800.)"/>
<!-- feedback -->
<define name="PHI_PGAIN" value="300"/>
<define name="PHI_DGAIN" value="200"/>
<define name="PHI_IGAIN" value="100"/>
<define name="THETA_PGAIN" value="300"/>
<define name="THETA_DGAIN" value="200"/>
<define name="THETA_IGAIN" value="100"/>
<define name="PSI_PGAIN" value="400"/>
<define name="PSI_DGAIN" value="200"/>
<define name="PSI_IGAIN" value="10"/>
<!-- feedforward -->
<define name="PHI_DDGAIN" value="300"/>
<define name="THETA_DDGAIN" value="300"/>
<define name="PSI_DDGAIN" value="300"/>
</section>
<section name="GUIDANCE_V" prefix="GUIDANCE_V_">
<define name="HOVER_KP" value="150"/>
<define name="HOVER_KD" value="80"/>
<define name="HOVER_KI" value="20"/>
<!-- NOMINAL_HOVER_THROTTLE sets a fixed value instead of the adaptive estimation -->
<!--define name="NOMINAL_HOVER_THROTTLE" value="0.5"/-->
</section>
<section name="GUIDANCE_H" prefix="GUIDANCE_H_">
<define name="MAX_BANK" value="20" unit="deg"/>
<define name="PGAIN" value="50"/>
<define name="DGAIN" value="100"/>
<define name="AGAIN" value="70"/>
<define name="IGAIN" value="20"/>
</section>
<section name="SIMULATOR" prefix="NPS_">
<define name="ACTUATOR_NAMES" value="nw_motor, ne_motor, se_motor, sw_motor" type="string[]"/>
<define name="JSBSIM_MODEL" value="simple_x_quad_ccw" type="string"/>
<define name="SENSORS_PARAMS" value="nps_sensors_params_default.h" type="string"/>
</section>
<section name="AUTOPILOT">
<define name="MODE_MANUAL" value="AP_MODE_ATTITUDE_DIRECT"/>
<define name="MODE_AUTO1" value="AP_MODE_HOVER_Z_HOLD"/>
<define name="MODE_AUTO2" value="AP_MODE_NAV"/>
</section>
<section name="BAT">
<define name="CATASTROPHIC_BAT_LEVEL" value="3.1" unit="V"/>
<define name="CRITIC_BAT_LEVEL" value="3.3" unit="V"/>
<define name="LOW_BAT_LEVEL" value="3.6" unit="V"/>
<define name="MAX_BAT_LEVEL" value="4.2" unit="V"/>
</section>
</airframe>
+87
View File
@@ -0,0 +1,87 @@
# Hey Emacs, this is a -*- makefile -*-
#
# crazyflie_2.1.makefile
#
# https://www.bitcraze.io/crazyflie-2-1/
#
# based on STM32F4
# only compatible with PPRZ/ChibiOS
#
BOARD=crazyflie
BOARD_VERSION=2.1
BOARD_DIR=$(BOARD)/chibios/v$(BOARD_VERSION)
BOARD_CFG=\"boards/$(BOARD_DIR)/$(BOARD).h\"
ARCH=chibios
## FPU on F4
USE_FPU=softfp
$(TARGET).CFLAGS += -DSTM32F4 -DPPRZLINK_ENABLE_FD -DUSE_HARD_FAULT_RECOVERY
##############################################################################
# Architecture or project specific options
#
# Define project name here (target)
PROJECT = $(TARGET)
# Project specific files and paths (see Makefile.chibios for details)
CHIBIOS_BOARD_PLATFORM = STM32F4xx/platform.mk
CHIBIOS_BOARD_LINKER = STM32F405xG.ld
CHIBIOS_BOARD_STARTUP = startup_stm32f4xx.mk
##############################################################################
# Compiler settings
#
MCU = cortex-m4
# -----------------------------------------------------------------------
# default flash mode is via usb dfu bootloader (luftboot)
# other possibilities: DFU-UTIL, SWD, JTAG_BMP, STLINK, SERIAL
FLASH_MODE ?= DFU-UTIL
# while the crazyflie doesn't have luftboot, it has a bootloader until same offset
# see also https://wiki.bitcraze.io/projects:crazyflie2:development:dfu
HAS_LUFTBOOT ?= 1
ifeq (,$(findstring $(HAS_LUFTBOOT),0 FALSE))
$(TARGET).CFLAGS+=-DLUFTBOOT
$(TARGET).LDFLAGS+=-Wl,-Ttext=0x8004000
DFU_ADDR = 0x8004000
endif
#
# default LED configuration
#
RADIO_CONTROL_LED ?= 3
BARO_LED ?= none
AHRS_ALIGNER_LED ?= 2
GPS_LED ?= 4
SYS_TIME_LED ?= 1
CHARGING_LED ?= 5
#
# default uart configuration
#
# Over NRF/Syslink
MODEM_PORT ?= syslink
# External port
#MODEM_PORT ?= UART3
#MODEM_BAUD ?= B57600
#
# default actuator configuration
#
# you can use different actuators by adding a configure option to your firmware section
# e.g. <configure name="ACTUATORS" value="actuators_ppm/>
# and by setting the correct "driver" attribute in servo section
# e.g. <servo driver="Ppm">
#
ACTUATORS ?= actuators_pwm
+3
View File
@@ -61,6 +61,7 @@
<board name="openpilot_revo.*"/>
<board name="chimera_.*"/>
<board name="tawaki_.*"/>
<board name="crazyflie_.*"/>
</boards>
</mode>
<mode name="STLink (SWD)">
@@ -75,6 +76,7 @@
<board name="openpilot_revo.*"/>
<board name="chimera_.*"/>
<board name="tawaki_.*"/>
<board name="crazyflie_.*"/>
</boards>
</mode>
<mode name="BlackMagic Probe (SWD)">
@@ -95,6 +97,7 @@
<board name="chimera_.*"/>
<board name="tawaki_.*"/>
<board name="vms_ecu_.*"/>
<board name="crazyflie_.*"/>
</boards>
</mode>
<mode name="BlackMagic Probe (SWD_NOPWR)">
+54
View File
@@ -0,0 +1,54 @@
<!DOCTYPE module SYSTEM "module.dtd">
<module name="ahrs_madgwick" dir="ahrs">
<doc>
<description>
AHRS using IMU (accel, gyro) only with Madwick implementation.
</description>
<configure name="AHRS_ALIGNER_LED" value="1" description="LED number to indicate AHRS alignment, none to disable (default is board dependent)"/>
<define name="AHRS_MADWICK_IMU_ID" value="ABI_BROADCAST" description="ABI sender id of IMU to use"/>
</doc>
<settings>
<dl_settings>
<dl_settings NAME="madwick">
<dl_setting MAX="1" MIN="1" STEP="1" VAR="ahrs_madgwick.reset" shortname="reset"/>
</dl_settings>
</dl_settings>
</settings>
<header>
<file name="ahrs.h" dir="subsystems"/>
</header>
<makefile target="!sim|fbw">
<configure name="USE_MAGNETOMETER" default="0"/>
<define name="USE_MAGNETOMETER" cond="ifeq (,$(findstring $(USE_MAGNETOMETER),0 FALSE))"/>
<define name="AHRS_ALIGNER_LED" value="$(AHRS_ALIGNER_LED)" cond="ifneq ($(AHRS_ALIGNER_LED),none)"/>
<define name="USE_AHRS"/>
<define name="USE_AHRS_ALIGNER"/>
<file name="ahrs.c" dir="subsystems"/>
<file name="ahrs_aligner.c" dir="subsystems/ahrs"/>
<file name="ahrs_madgwick.c"/>
<file name="ahrs_madgwick_wrapper.c"/>
<raw>
ifdef SECONDARY_AHRS
ifneq (,$(findstring $(SECONDARY_AHRS), madwick))
# this is the secondary AHRS
$(TARGET).CFLAGS += -DAHRS_SECONDARY_TYPE_H=\"modules/ahrs/ahrs_madgwick_wrapper.h\"
$(TARGET).CFLAGS += -DSECONDARY_AHRS=ahrs_madgwick
else
# this is the primary AHRS
$(TARGET).CFLAGS += -DAHRS_TYPE_H=\"modules/ahrs/ahrs_madgwick_wrapper.h\"
$(TARGET).CFLAGS += -DPRIMARY_AHRS=ahrs_madgwick
endif
else
# plain old single AHRS usage
$(TARGET).CFLAGS += -DAHRS_TYPE_H=\"modules/ahrs/ahrs_madgwick_wrapper.h\"
endif
</raw>
</makefile>
</module>
+41
View File
@@ -0,0 +1,41 @@
<!DOCTYPE module SYSTEM "module.dtd">
<module name="imu_bmi088_i2c" dir="imu">
<doc>
<description>
IMU with BMI088 via I2C.
</description>
<configure name="IMU_BMI088_I2C_DEV" value="i2c3" description="I2C device to use for BMI088"/>
<define name="IMU_BMI088_GYRO_RANGE" value="BMI088_GYRO_RANGE_1000" description="gyroscope range setting"/>
<define name="IMU_BMI088_GYRO_ODR" value="BMI088_GYRO_ODR_400_BW_47" description="gyroscope output data rate"/>
<define name="IMU_BMI088_GYRO_I2C_ADDR" value="BMI088_GYRO_ADDR|BMI088_GYRO_ADDR_ALT" description="I2C address of the gyro"/>
<define name="IMU_BMI088_ACCEL_RANGE" value="BMI088_ACCEL_RANGE_6G" description="accelerometer range setting"/>
<define name="IMU_BMI088_ACCEL_ODR" value="BMI088_ACCEL_ODR_400" description="accelerometer output data rate"/>
<define name="IMU_BMI088_ACCEL_I2C_ADDR" value="BMI088_ACCEL_ADDR|BMI088_ACCEL_ADDR_ALT" description="I2C address of the accelerometer"/>
<define name="IMU_BMI088_CHAN_X" value="0" description="channel index"/>
<define name="IMU_BMI088_CHAN_Y" value="1" description="channel index"/>
<define name="IMU_BMI088_CHAN_Z" value="2" description="channel index"/>
</doc>
<autoload name="imu_common"/>
<autoload name="imu_nps"/>
<header>
<file name="imu_bmi088_i2c.h"/>
</header>
<init fun="imu_bmi088_init()"/>
<periodic fun="imu_bmi088_periodic()"/>
<event fun="imu_bmi088_event()"/>
<makefile target="!sim|nps|fbw">
<configure name="IMU_BMI088_I2C_DEV" default="i2c3" case="lower|upper"/>
<define name="IMU_BMI088_I2C_DEV" value="$(IMU_BMI088_I2C_DEV_LOWER)"/>
<define name="USE_$(IMU_BMI088_I2C_DEV_UPPER)"/>
<define name="IMU_TYPE_H" value="modules/imu/imu_bmi088_i2c.h" type="string"/>
<file name="bmi088.c" dir="peripherals"/>
<file name="bmi088_i2c.c" dir="peripherals"/>
<file name="imu_bmi088_i2c.c"/>
</makefile>
</module>
+32
View File
@@ -0,0 +1,32 @@
<!DOCTYPE module SYSTEM "module.dtd">
<module name="syslink" dir="datalink/bitcraze" task="datalink">
<doc>
<description>
Bitcraze syslink module
</description>
<configure name="SYSLINK_PORT" value="UARTX" description="Select syslink port"/>
<configure name="SYSLINK_BAUD" value="B1000000" description="Syslink baudrate"/>
</doc>
<autoload name="telemetry" type="nps"/>
<autoload name="telemetry" type="sim"/>
<header>
<file name="syslink_dl.h"/>
</header>
<init fun="syslink_dl_init()"/>
<periodic fun="syslink_dl_periodic()" freq="2"/>
<event fun="syslink_dl_event()"/>
<makefile target="!fbw|sim|nps|hitl">
<configure name="SYSLINK_PORT" default="uart6" case="upper|lower"/>
<configure name="SYSLINK_BAUD" default="B1000000" case="upper|lower"/>
<define name="SYSLINK_DEV" value="$(SYSLINK_PORT_LOWER)"/>
<define name="USE_$(SYSLINK_PORT_UPPER)"/>
<define name="$(SYSLINK_PORT_UPPER)_BAUD" value="$(SYSLINK_BAUD)"/>
<define name="USE_UART_SOFT_FLOW_CONTROL"/>
<define name="USE_SYSLINK"/>
<define name="CHARGING_LED" value="$(CHARGING_LED)" cond="ifneq ($(CHARGING_LED),none)"/>
<file name="syslink_dl.c"/>
<file name="syslink.c"/>
</makefile>
</module>
+2
View File
@@ -0,0 +1,2 @@
<program command="sw/ground_segment/python/bitcraze/crazyradio2ivy.py" name="Crazyradio/IVY bridge" />
+86
View File
@@ -0,0 +1,86 @@
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
* STM32F405xG memory setup.
* Note: Use of ram1 and ram2 is mutually exclusive with use of ram0.
*/
MEMORY
{
flash0 : org = 0x08004000, len = 1M
flash1 : org = 0x00000000, len = 0
flash2 : org = 0x00000000, len = 0
flash3 : org = 0x00000000, len = 0
flash4 : org = 0x00000000, len = 0
flash5 : org = 0x00000000, len = 0
flash6 : org = 0x00000000, len = 0
flash7 : org = 0x00000000, len = 0
ram0 : org = 0x20000000, len = 128k /* SRAM1 + SRAM2 */
ram1 : org = 0x20000000, len = 112k /* SRAM1 */
ram2 : org = 0x2001C000, len = 16k /* SRAM2 */
ram3 : org = 0x00000000, len = 0
ram4 : org = 0x10000000, len = 64k /* CCM SRAM */
ram5 : org = 0x40024000, len = 4k /* BCKP SRAM */
ram6 : org = 0x00000000, len = 0
ram7 : org = 0x00000000, len = 0
}
/* For each data/text section two region are defined, a virtual region
and a load region (_LMA suffix).*/
/* Flash region to be used for exception vectors.*/
REGION_ALIAS("VECTORS_FLASH", flash0);
REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
/* Flash region to be used for constructors and destructors.*/
REGION_ALIAS("XTORS_FLASH", flash0);
REGION_ALIAS("XTORS_FLASH_LMA", flash0);
/* Flash region to be used for code text.*/
REGION_ALIAS("TEXT_FLASH", flash0);
REGION_ALIAS("TEXT_FLASH_LMA", flash0);
/* Flash region to be used for read only data.*/
REGION_ALIAS("RODATA_FLASH", flash0);
REGION_ALIAS("RODATA_FLASH_LMA", flash0);
/* Flash region to be used for various.*/
REGION_ALIAS("VARIOUS_FLASH", flash0);
REGION_ALIAS("VARIOUS_FLASH_LMA", flash0);
/* Flash region to be used for RAM(n) initialization data.*/
REGION_ALIAS("RAM_INIT_FLASH_LMA", flash0);
/* RAM region to be used for Main stack. This stack accommodates the processing
of all exceptions and interrupts.*/
REGION_ALIAS("MAIN_STACK_RAM", ram0);
/* RAM region to be used for the process stack. This is the stack used by
the main() function.*/
REGION_ALIAS("PROCESS_STACK_RAM", ram0);
/* RAM region to be used for data segment.*/
REGION_ALIAS("DATA_RAM", ram0);
REGION_ALIAS("DATA_RAM_LMA", flash0);
/* RAM region to be used for BSS segment.*/
REGION_ALIAS("BSS_RAM", ram0);
/* RAM region to be used for the default heap.*/
REGION_ALIAS("HEAP_RAM", ram0);
/* Generic rules inclusion.*/
INCLUDE rules.ld
+48 -26
View File
@@ -51,8 +51,12 @@ struct SerialInit {
semaphore_t *tx_sem;
mutex_t *rx_mtx;
mutex_t *tx_mtx;
ioportid_t cts_port;
uint16_t cts_pin;
};
#define SERIAL_INIT_NULL { NULL, NULL, NULL, NULL, NULL, 0, 0 }
/**
* RX handler
*/
@@ -80,19 +84,32 @@ static void handle_uart_rx(struct uart_periph *p)
static void handle_uart_tx(struct uart_periph *p)
{
// check if more data to send
// TODO send by block with sdWrite (be careful with circular buffer)
// not compatible with soft flow control
struct SerialInit *init_struct = (struct SerialInit *)(p->init_struct);
chSemWait(init_struct->tx_sem);
p->tx_running = true;
while (p->tx_insert_idx != p->tx_extract_idx) {
#if USE_UART_SOFT_FLOW_CONTROL
if (init_struct->cts_port != 0) {
// wait for CTS line to be set to send next byte
while (gpio_get(init_struct->cts_port, init_struct->cts_pin) == 1) ;
}
#endif
uint8_t data = p->tx_buf[p->tx_extract_idx];
p->tx_running = true;
sdWrite((SerialDriver *)p->reg_addr, &data, sizeof(data));
p->tx_running = false;
// TODO send by block (be careful with circular buffer)
sdPut((SerialDriver *)p->reg_addr, data);
chMtxLock(init_struct->tx_mtx);
p->tx_extract_idx++;
p->tx_extract_idx %= UART_TX_BUFFER_SIZE;
chMtxUnlock(init_struct->tx_mtx);
#if USE_UART_SOFT_FLOW_CONTROL
if (init_struct->cts_port != 0) {
// wait for physical transfer to be completed
while ((((SerialDriver *)p->reg_addr)->usart->SR & USART_SR_TC) == 0) ;
}
#endif
}
p->tx_running = false;
}
#if USE_UART1
@@ -116,7 +133,7 @@ static SerialConfig usart1_config = {
0 /* USART CR3 */
};
static struct SerialInit uart1_init_struct = { NULL, NULL, NULL, NULL, NULL };
static struct SerialInit uart1_init_struct = SERIAL_INIT_NULL;
// Threads RX and TX
#if USE_UART1_RX
@@ -218,7 +235,7 @@ static SerialConfig usart2_config = {
#endif
};
static struct SerialInit uart2_init_struct = { NULL, NULL, NULL, NULL, NULL };
static struct SerialInit uart2_init_struct = SERIAL_INIT_NULL;
// Threads RX and TX
#if USE_UART2_RX
@@ -277,13 +294,13 @@ void uart2_init(void)
uart2_init_struct.rx_mtx = &uart2_rx_mtx;
uart2_init_struct.rx_sem = &uart2_rx_sem;
chThdCreateStatic(wa_thd_uart2_rx, sizeof(wa_thd_uart2_rx),
NORMALPRIO, thd_uart2_rx, NULL);
NORMALPRIO + 1, thd_uart2_rx, NULL);
#endif
#if USE_UART2_TX
uart2_init_struct.tx_mtx = &uart2_tx_mtx;
uart2_init_struct.tx_sem = &uart2_tx_sem;
chThdCreateStatic(wa_thd_uart2_tx, sizeof(wa_thd_uart2_tx),
NORMALPRIO, thd_uart2_tx, NULL);
NORMALPRIO + 1, thd_uart2_tx, NULL);
#endif
}
@@ -310,7 +327,7 @@ static SerialConfig usart3_config = {
0 /* USART CR3 */
};
static struct SerialInit uart3_init_struct = { NULL, NULL, NULL, NULL, NULL };
static struct SerialInit uart3_init_struct = SERIAL_INIT_NULL;
// Threads RX and TX
#if USE_UART3_RX
@@ -369,13 +386,13 @@ void uart3_init(void)
uart3_init_struct.rx_mtx = &uart3_rx_mtx;
uart3_init_struct.rx_sem = &uart3_rx_sem;
chThdCreateStatic(wa_thd_uart3_rx, sizeof(wa_thd_uart3_rx),
NORMALPRIO, thd_uart3_rx, NULL);
NORMALPRIO + 1, thd_uart3_rx, NULL);
#endif
#if USE_UART3_TX
uart3_init_struct.tx_mtx = &uart3_tx_mtx;
uart3_init_struct.tx_sem = &uart3_tx_sem;
chThdCreateStatic(wa_thd_uart3_tx, sizeof(wa_thd_uart3_tx),
NORMALPRIO, thd_uart3_tx, NULL);
NORMALPRIO + 1, thd_uart3_tx, NULL);
#endif
}
@@ -402,7 +419,7 @@ static SerialConfig usart4_config = {
0 /* USART CR3 */
};
static struct SerialInit uart4_init_struct = { NULL, NULL, NULL, NULL, NULL };
static struct SerialInit uart4_init_struct = SERIAL_INIT_NULL;
// Threads RX and TX
#if USE_UART4_RX
@@ -461,13 +478,13 @@ void uart4_init(void)
uart4_init_struct.rx_mtx = &uart4_rx_mtx;
uart4_init_struct.rx_sem = &uart4_rx_sem;
chThdCreateStatic(wa_thd_uart4_rx, sizeof(wa_thd_uart4_rx),
NORMALPRIO, thd_uart4_rx, NULL);
NORMALPRIO + 1, thd_uart4_rx, NULL);
#endif
#if USE_UART4_TX
uart4_init_struct.tx_mtx = &uart4_tx_mtx;
uart4_init_struct.tx_sem = &uart4_tx_sem;
chThdCreateStatic(wa_thd_uart4_tx, sizeof(wa_thd_uart4_tx),
NORMALPRIO, thd_uart4_tx, NULL);
NORMALPRIO + 1, thd_uart4_tx, NULL);
#endif
}
@@ -494,7 +511,7 @@ static SerialConfig usart5_config = {
0 /* USART CR3 */
};
static struct SerialInit uart5_init_struct = { NULL, NULL, NULL, NULL, NULL };
static struct SerialInit uart5_init_struct = SERIAL_INIT_NULL;
// Threads RX and TX
#if USE_UART5_RX
@@ -553,13 +570,13 @@ void uart5_init(void)
uart5_init_struct.rx_mtx = &uart5_rx_mtx;
uart5_init_struct.rx_sem = &uart5_rx_sem;
chThdCreateStatic(wa_thd_uart5_rx, sizeof(wa_thd_uart5_rx),
NORMALPRIO, thd_uart5_rx, NULL);
NORMALPRIO + 1, thd_uart5_rx, NULL);
#endif
#if USE_UART5_TX
uart5_init_struct.tx_mtx = &uart5_tx_mtx;
uart5_init_struct.tx_sem = &uart5_tx_sem;
chThdCreateStatic(wa_thd_uart5_tx, sizeof(wa_thd_uart5_tx),
NORMALPRIO, thd_uart5_tx, NULL);
NORMALPRIO + 1, thd_uart5_tx, NULL);
#endif
}
@@ -586,7 +603,7 @@ static SerialConfig usart6_config = {
0 /* USART CR3 */
};
static struct SerialInit uart6_init_struct = { NULL, NULL, NULL, NULL, NULL };
static struct SerialInit uart6_init_struct = SERIAL_INIT_NULL;
// Threads RX and TX
#if USE_UART6_RX
@@ -645,13 +662,18 @@ void uart6_init(void)
uart6_init_struct.rx_mtx = &uart6_rx_mtx;
uart6_init_struct.rx_sem = &uart6_rx_sem;
chThdCreateStatic(wa_thd_uart6_rx, sizeof(wa_thd_uart6_rx),
NORMALPRIO, thd_uart6_rx, NULL);
NORMALPRIO + 1, thd_uart6_rx, NULL);
#endif
#if USE_UART6_TX
uart6_init_struct.tx_mtx = &uart6_tx_mtx;
uart6_init_struct.tx_sem = &uart6_tx_sem;
chThdCreateStatic(wa_thd_uart6_tx, sizeof(wa_thd_uart6_tx),
NORMALPRIO, thd_uart6_tx, NULL);
NORMALPRIO + 1, thd_uart6_tx, NULL);
#endif
#if defined UART6_GPIO_CTS && defined UART6_GPIO_PORT_CTS
uart6_init_struct.cts_pin = UART6_GPIO_CTS;
uart6_init_struct.cts_port = UART6_GPIO_PORT_CTS;
#endif
}
@@ -678,7 +700,7 @@ static SerialConfig usart7_config = {
0 /* USART CR3 */
};
static struct SerialInit uart7_init_struct = { NULL, NULL, NULL, NULL, NULL };
static struct SerialInit uart7_init_struct = SERIAL_INIT_NULL;
// Threads RX and TX
#if USE_UART7_RX
@@ -737,13 +759,13 @@ void uart7_init(void)
uart7_init_struct.rx_mtx = &uart7_rx_mtx;
uart7_init_struct.rx_sem = &uart7_rx_sem;
chThdCreateStatic(wa_thd_uart7_rx, sizeof(wa_thd_uart7_rx),
NORMALPRIO, thd_uart7_rx, NULL);
NORMALPRIO + 1, thd_uart7_rx, NULL);
#endif
#if USE_UART7_TX
uart7_init_struct.tx_mtx = &uart7_tx_mtx;
uart7_init_struct.tx_sem = &uart7_tx_sem;
chThdCreateStatic(wa_thd_uart7_tx, sizeof(wa_thd_uart7_tx),
NORMALPRIO, thd_uart7_tx, NULL);
NORMALPRIO + 1, thd_uart7_tx, NULL);
#endif
}
@@ -770,7 +792,7 @@ static SerialConfig usart8_config = {
0 /* USART CR3 */
};
static struct SerialInit uart8_init_struct = { NULL, NULL, NULL, NULL, NULL };
static struct SerialInit uart8_init_struct = SERIAL_INIT_NULL;
// Threads RX and TX
#if USE_UART8_RX
@@ -829,13 +851,13 @@ void uart8_init(void)
uart8_init_struct.rx_mtx = &uart8_rx_mtx;
uart8_init_struct.rx_sem = &uart8_rx_sem;
chThdCreateStatic(wa_thd_uart8_rx, sizeof(wa_thd_uart8_rx),
NORMALPRIO, thd_uart8_rx, NULL);
NORMALPRIO + 1, thd_uart8_rx, NULL);
#endif
#if USE_UART8_TX
uart8_init_struct.tx_mtx = &uart8_tx_mtx;
uart8_init_struct.tx_sem = &uart8_tx_sem;
chThdCreateStatic(wa_thd_uart8_tx, sizeof(wa_thd_uart8_tx),
NORMALPRIO, thd_uart8_tx, NULL);
NORMALPRIO + 1, thd_uart8_tx, NULL);
#endif
}
@@ -48,6 +48,7 @@
#define B115200 115200
#define B230400 230400
#define B921600 921600
#define B1000000 1000000
#define B1500000 1500000
#define B3000000 3000000
#define UART_SPEED(_def) _def
@@ -44,7 +44,7 @@
* in milliseconds to microseconds (required by pwmEnableChannel())
*/
#ifndef PWM_CMD_TO_US
#define PWM_CMD_TO_US(_t) (1000000 * _t / PWM_FREQUENCY)
#define PWM_CMD_TO_US(_t) (PWM_FREQUENCY * _t / 1000000)
#endif
int32_t actuators_pwm_values[ACTUATORS_PWM_NB];
@@ -0,0 +1,263 @@
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
* This file has been automatically generated using ChibiStudio board
* generator plugin. Do not edit manually.
*/
#include "hal.h"
#include "stm32_gpio.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/**
* @brief Type of STM32 GPIO port setup.
*/
typedef struct {
uint32_t moder;
uint32_t otyper;
uint32_t ospeedr;
uint32_t pupdr;
uint32_t odr;
uint32_t afrl;
uint32_t afrh;
} gpio_setup_t;
/**
* @brief Type of STM32 GPIO initialization data.
*/
typedef struct {
#if STM32_HAS_GPIOA || defined(__DOXYGEN__)
gpio_setup_t PAData;
#endif
#if STM32_HAS_GPIOB || defined(__DOXYGEN__)
gpio_setup_t PBData;
#endif
#if STM32_HAS_GPIOC || defined(__DOXYGEN__)
gpio_setup_t PCData;
#endif
#if STM32_HAS_GPIOD || defined(__DOXYGEN__)
gpio_setup_t PDData;
#endif
#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
gpio_setup_t PEData;
#endif
#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
gpio_setup_t PFData;
#endif
#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
gpio_setup_t PGData;
#endif
#if STM32_HAS_GPIOH || defined(__DOXYGEN__)
gpio_setup_t PHData;
#endif
#if STM32_HAS_GPIOI || defined(__DOXYGEN__)
gpio_setup_t PIData;
#endif
#if STM32_HAS_GPIOJ || defined(__DOXYGEN__)
gpio_setup_t PJData;
#endif
#if STM32_HAS_GPIOK || defined(__DOXYGEN__)
gpio_setup_t PKData;
#endif
} gpio_config_t;
/**
* @brief STM32 GPIO static initialization data.
*/
static const gpio_config_t gpio_default_config = {
#if STM32_HAS_GPIOA
{VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR,
VAL_GPIOA_ODR, VAL_GPIOA_AFRL, VAL_GPIOA_AFRH},
#endif
#if STM32_HAS_GPIOB
{VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR,
VAL_GPIOB_ODR, VAL_GPIOB_AFRL, VAL_GPIOB_AFRH},
#endif
#if STM32_HAS_GPIOC
{VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR,
VAL_GPIOC_ODR, VAL_GPIOC_AFRL, VAL_GPIOC_AFRH},
#endif
#if STM32_HAS_GPIOD
{VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR,
VAL_GPIOD_ODR, VAL_GPIOD_AFRL, VAL_GPIOD_AFRH},
#endif
#if STM32_HAS_GPIOE
{VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR,
VAL_GPIOE_ODR, VAL_GPIOE_AFRL, VAL_GPIOE_AFRH},
#endif
#if STM32_HAS_GPIOF
{VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR,
VAL_GPIOF_ODR, VAL_GPIOF_AFRL, VAL_GPIOF_AFRH},
#endif
#if STM32_HAS_GPIOG
{VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR,
VAL_GPIOG_ODR, VAL_GPIOG_AFRL, VAL_GPIOG_AFRH},
#endif
#if STM32_HAS_GPIOH
{VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR,
VAL_GPIOH_ODR, VAL_GPIOH_AFRL, VAL_GPIOH_AFRH},
#endif
#if STM32_HAS_GPIOI
{VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR,
VAL_GPIOI_ODR, VAL_GPIOI_AFRL, VAL_GPIOI_AFRH},
#endif
#if STM32_HAS_GPIOJ
{VAL_GPIOJ_MODER, VAL_GPIOJ_OTYPER, VAL_GPIOJ_OSPEEDR, VAL_GPIOJ_PUPDR,
VAL_GPIOJ_ODR, VAL_GPIOJ_AFRL, VAL_GPIOJ_AFRH},
#endif
#if STM32_HAS_GPIOK
{VAL_GPIOK_MODER, VAL_GPIOK_OTYPER, VAL_GPIOK_OSPEEDR, VAL_GPIOK_PUPDR,
VAL_GPIOK_ODR, VAL_GPIOK_AFRL, VAL_GPIOK_AFRH}
#endif
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) {
gpiop->OTYPER = config->otyper;
gpiop->OSPEEDR = config->ospeedr;
gpiop->PUPDR = config->pupdr;
gpiop->ODR = config->odr;
gpiop->AFRL = config->afrl;
gpiop->AFRH = config->afrh;
gpiop->MODER = config->moder;
}
static void stm32_gpio_init(void) {
/* Enabling GPIO-related clocks, the mask comes from the
registry header file.*/
rccResetAHB1(STM32_GPIO_EN_MASK);
rccEnableAHB1(STM32_GPIO_EN_MASK, true);
/* Initializing all the defined GPIO ports.*/
#if STM32_HAS_GPIOA
gpio_init(GPIOA, &gpio_default_config.PAData);
#endif
#if STM32_HAS_GPIOB
gpio_init(GPIOB, &gpio_default_config.PBData);
#endif
#if STM32_HAS_GPIOC
gpio_init(GPIOC, &gpio_default_config.PCData);
#endif
#if STM32_HAS_GPIOD
gpio_init(GPIOD, &gpio_default_config.PDData);
#endif
#if STM32_HAS_GPIOE
gpio_init(GPIOE, &gpio_default_config.PEData);
#endif
#if STM32_HAS_GPIOF
gpio_init(GPIOF, &gpio_default_config.PFData);
#endif
#if STM32_HAS_GPIOG
gpio_init(GPIOG, &gpio_default_config.PGData);
#endif
#if STM32_HAS_GPIOH
gpio_init(GPIOH, &gpio_default_config.PHData);
#endif
#if STM32_HAS_GPIOI
gpio_init(GPIOI, &gpio_default_config.PIData);
#endif
#if STM32_HAS_GPIOJ
gpio_init(GPIOJ, &gpio_default_config.PJData);
#endif
#if STM32_HAS_GPIOK
gpio_init(GPIOK, &gpio_default_config.PKData);
#endif
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Early initialization code.
* @details GPIO ports and system clocks are initialized before everything
* else.
*/
void __early_init(void) {
stm32_gpio_init();
stm32_clock_init();
}
#if HAL_USE_SDC || defined(__DOXYGEN__)
/**
* @brief SDC card detection.
*/
bool sdc_lld_is_card_inserted(SDCDriver *sdcp) {
(void)sdcp;
return !palReadLine(LINE_SDIO_DETECT);
}
/**
* @brief SDC card write protection detection.
*/
bool sdc_lld_is_write_protected(SDCDriver *sdcp) {
(void)sdcp;
return false;
}
#endif /* HAL_USE_SDC */
#if HAL_USE_MMC_SPI || defined(__DOXYGEN__)
/**
* @brief MMC_SPI card detection.
*/
bool mmc_lld_is_card_inserted(MMCDriver *mmcp) {
(void)mmcp;
/* TODO: Fill the implementation.*/
return true;
}
/**
* @brief MMC_SPI card write protection detection.
*/
bool mmc_lld_is_write_protected(MMCDriver *mmcp) {
(void)mmcp;
/* TODO: Fill the implementation.*/
return false;
}
#endif
/**
* @brief Board-specific initialization code.
* @todo Add your board-specific code, if any.
*/
void boardInit(void) {
}
@@ -0,0 +1,96 @@
MCU_MODEL = STM32F405RGTx
CHIBIOS_VERSION = 3.0
HEADER
/*
* Board identifier.
*/
#define BOARD_ST_CRAZYFLIE
#define BOARD_NAME "Bitcraze Crazyflie 2.1"
/*
* Board oscillators-related settings.
* NOTE: LSE fitted.
*/
#if !defined(STM32_LSECLK)
#define STM32_LSECLK 32768
#endif
#if !defined(STM32_HSECLK)
#define STM32_HSECLK 8000000
#endif
/*
* Board voltages.
* Required for performance limits calculation.
*/
#define STM32_VDD 300
/*
* MCU type as defined in the ST header file stm32f4xx.h.
*/
#define STM32F405xx
/*
* AHB_CLK
*/
#define AHB_CLK STM32_HCLK
CONFIG
# PIN NAME PERIPH_TYPE AF_NUMBER or
# PIN NAME FUNCTION PUSHPULL|OPENDRAIN PIN_SPEED PULLUP|PULLDOWN|FLOATING LEVEL_LOW|LEVEL_HIGH AF_NUMBER
# simplified config for INPUT and OUTPUT
# PIN NAME INPUT PULLUP|PULLDOWN|FLOATING
# PIN NAME OUTPUT PUSHPULL|OPENDRAIN PIN_SPEED PULLUP|PULLDOWN|FLOATING LEVEL_LOW|LEVEL_HIGH
#
# PIN_SPEED : SPEED_VERYLOW, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH
# PERIPH_TYPE : SYS, ADC, PWM, ICU, I2C, SPI, UART, OTG, ETH, SDIO, SDIOCK,
#
# SYSTEM
A13 STM_SWIO SYS AF:SYS_JTMS-SWDIO
A14 STM_SWCLK SYS AF:SYS_JTCK-SWCLK
H00 OSC_IN SYS AF:RCC_OSC_IN
H01 OSC_OUT SYS AF:RCC_OSC_OUT
DEFAULT INPUT PUSHPULL SPEED_VERYLOW PULLDOWN LEVEL_LOW AF0
# ACTIVE PINS
PA01 MOTOR1 PWM AF:TIM2_CH2
PA02 E_TX2 UART AF:USART2_TX
PA03 E_RX2 UART AF:USART2_RX
PA04 NRF_FLOW_CTRL INPUT FLOATING
PA05 E_SCK SPI AF:SPI1_SCK
PA06 E_MISO SPI AF:SPI1_MISO
PA07 E_MOSI SPI AF:SPI1_MOSI
PA08 IMU_SCL I2C AF:I2C3_SCL
PA10 USB_ID OTG AF:USB_OTG_FS_ID
PA11 USB_DM OTG AF:USB_OTG_FS_DM
PA12 USB_DP OTG AF:USB_OTG_FS_DP
PA15 MOTOR3 PWM AF:TIM2_CH1
PB02 BOOT1 INPUT FLOATING
#PB03 STM_SW0 INPUT FLOATING FIXME in system section ?
PB04 E_CS1 INPUT FLOATING
PB05 E_CS2 INPUT FLOATING
PB06 E_SCL I2C AF:I2C1_SCL
PB07 E_SDA I2C AF:I2C1_SDA
PB08 E_CS3 INPUT FLOATING
PB09 MOTOR4 PWM AF:TIM4_CH4
PB11 MOTOR2 PWM AF:TIM2_CH4
PB13 NRF_SWCLK INPUT FLOATING
PB15 NRF_SWIO INPUT FLOATING
PC00 LED_RED_L LED
PC01 LED_GREEN_L LED
PC02 LED_GREEN_R LED
PC03 LED_RED_R LED
PC06 NRF_TX UART AF:USART6_TX
PC07 NRF_RX UART AF:USART6_RX
PC09 IMU_SDA I2C AF:I2C3_SDA
PC10 E_TX1 UART AF:USART3_TX
PC11 E_RX1 UART AF:USART3_RX
PC12 E_CS0 INPUT FLOATING
PD02 LED_BLUE_L LED
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,20 @@
#
# ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Required include directories
BOARDINC = $(CHIBIOS_BOARD_DIR)
# List of all the board related files.
BOARDSRC = ${BOARDINC}/board.c
@@ -0,0 +1,357 @@
#ifndef CONFIG_CRAZYFLIE_2_1_H
#define CONFIG_CRAZYFLIE_2_1_H
#define BOARD_CRAZYFLIE
/**
* ChibiOS board file
*/
#include "boards/crazyflie/chibios/v2.1/board.h"
/**
* PPRZ definitions
*/
/*
* AHB_CLK
*/
#define AHB_CLK STM32_HCLK
/*
* LEDs
*/
#ifndef USE_LED_1
#define USE_LED_1 1
#endif
#define LED_1_GPIO LED_RED_R_PORT
#define LED_1_GPIO_PIN LED_RED_R
#define LED_1_GPIO_ON gpio_clear
#define LED_1_GPIO_OFF gpio_set
#ifndef USE_LED_2
#define USE_LED_2 1
#endif
#define LED_2_GPIO LED_RED_L_PORT
#define LED_2_GPIO_PIN LED_RED_L
#define LED_2_GPIO_ON gpio_clear
#define LED_2_GPIO_OFF gpio_set
#ifndef USE_LED_3
#define USE_LED_3 1
#endif
#define LED_3_GPIO LED_GREEN_R_PORT
#define LED_3_GPIO_PIN LED_GREEN_R
#define LED_3_GPIO_ON gpio_clear
#define LED_3_GPIO_OFF gpio_set
#ifndef USE_LED_4
#define USE_LED_4 1
#endif
#define LED_4_GPIO LED_GREEN_L_PORT
#define LED_4_GPIO_PIN LED_GREEN_L
#define LED_4_GPIO_ON gpio_clear
#define LED_4_GPIO_OFF gpio_set
#ifndef USE_LED_5
#define USE_LED_5 1
#endif
#define LED_5_GPIO LED_BLUE_L_PORT
#define LED_5_GPIO_PIN LED_BLUE_L
#define LED_5_GPIO_ON gpio_set
#define LED_5_GPIO_OFF gpio_clear
/*
* ADCs
*/
// TODO for AUX
// No VBAT monitoring ?
/*
* PWM defines
*/
// SRVa connectors, activated in PWM mode by default
#ifndef USE_PWM1
#define USE_PWM1 1
#endif
#if USE_PWM1
#define PWM_SERVO_1 1
#define PWM_SERVO_1_GPIO MOTOR1_PORT
#define PWM_SERVO_1_PIN MOTOR1
#define PWM_SERVO_1_AF AF_MOTOR1
#define PWM_SERVO_1_DRIVER PWMD2
#define PWM_SERVO_1_CHANNEL 1
#define PWM_SERVO_1_ACTIVE PWM_OUTPUT_ACTIVE_HIGH
#else
#define PWM_SERVO_1_ACTIVE PWM_OUTPUT_DISABLED
#endif
#ifndef USE_PWM2
#define USE_PWM2 1
#endif
#if USE_PWM2
#define PWM_SERVO_2 2
#define PWM_SERVO_2_GPIO MOTOR2_PORT
#define PWM_SERVO_2_PIN MOTOR2
#define PWM_SERVO_2_AF AF_MOTOR2
#define PWM_SERVO_2_DRIVER PWMD2
#define PWM_SERVO_2_CHANNEL 3
#define PWM_SERVO_2_ACTIVE PWM_OUTPUT_ACTIVE_HIGH
#else
#define PWM_SERVO_2_ACTIVE PWM_OUTPUT_DISABLED
#endif
#ifndef USE_PWM3
#define USE_PWM3 1
#endif
#if USE_PWM3
#define PWM_SERVO_3 3
#define PWM_SERVO_3_GPIO MOTOR3_PORT
#define PWM_SERVO_3_PIN MOTOR3
#define PWM_SERVO_3_AF AF_MOTOR3
#define PWM_SERVO_3_DRIVER PWMD2
#define PWM_SERVO_3_CHANNEL 0
#define PWM_SERVO_3_ACTIVE PWM_OUTPUT_ACTIVE_HIGH
#else
#define PWM_SERVO_3_ACTIVE PWM_OUTPUT_DISABLED
#endif
#ifndef USE_PWM4
#define USE_PWM4 1
#endif
#if USE_PWM4
#define PWM_SERVO_4 4
#define PWM_SERVO_4_GPIO MOTOR4_PORT
#define PWM_SERVO_4_PIN MOTOR4
#define PWM_SERVO_4_AF AF_MOTOR4
#define PWM_SERVO_4_DRIVER PWMD4
#define PWM_SERVO_4_CHANNEL 3
#define PWM_SERVO_4_ACTIVE PWM_OUTPUT_ACTIVE_HIGH
#else
#define PWM_SERVO_4_ACTIVE PWM_OUTPUT_DISABLED
#endif
// servo index starting at 1 + regular servos + aux servos
// so NB = 1+4
#define ACTUATORS_PWM_NB 5
// PWM control of brushed motors
// Freq = 84 MHz (corresponding to prescaler of 0)
// Period = 256 (corresponding to 8bit resolution for command at ~328 kHz))
// as indicated in Crazyflie source code, 328 kHz offers better natural filtering
// than 128 kHz
// It is also needed to redefined PWM_CMD_TO_US to get the proper converstion
// from command to clock pulses number
#define PWM_CMD_TO_US(_t) (_t)
#ifdef STM32_PWM_USE_TIM2
#define PWM_CONF_TIM2 STM32_PWM_USE_TIM2
#else
#define PWM_CONF_TIM2 1
#endif
#define PWM_CONF2_DEF { \
84000000, \
256, \
NULL, \
{ \
{ PWM_SERVO_3_ACTIVE, NULL }, \
{ PWM_SERVO_1_ACTIVE, NULL }, \
{ PWM_OUTPUT_DISABLED, NULL }, \
{ PWM_SERVO_2_ACTIVE, NULL }, \
}, \
0, \
0 \
}
#ifdef STM32_PWM_USE_TIM4
#define PWM_CONF_TIM4 STM32_PWM_USE_TIM4
#else
#define PWM_CONF_TIM4 1
#endif
#define PWM_CONF4_DEF { \
84000000, \
256, \
NULL, \
{ \
{ PWM_OUTPUT_DISABLED, NULL }, \
{ PWM_OUTPUT_DISABLED, NULL }, \
{ PWM_OUTPUT_DISABLED, NULL }, \
{ PWM_SERVO_4_ACTIVE, NULL }, \
}, \
0, \
0 \
}
/**
* UART2 E_TX2
*/
#define UART2_GPIO_PORT_TX E_TX2_PORT
#define UART2_GPIO_TX E_TX2
#define UART2_GPIO_PORT_RX E_RX2_PORT
#define UART2_GPIO_RX E_RX2
#define UART2_GPIO_AF AF_E_RX2
#ifndef UART2_HW_FLOW_CONTROL
#define UART2_HW_FLOW_CONTROL FALSE
#endif
/**
* UART3 E_TX1
*/
#define UART3_GPIO_PORT_TX E_TX1_PORT
#define UART3_GPIO_TX E_TX1
#define UART3_GPIO_PORT_RX E_RX1_PORT
#define UART3_GPIO_RX E_RX1
#define UART3_GPIO_AF AF_E_RX1
/**
* UART6 NRF
*/
#define UART6_GPIO_PORT_TX NRF_TX_PORT
#define UART6_GPIO_TX NRF_TX
#define UART6_GPIO_PORT_RX NRF_RX_PORT
#define UART6_GPIO_RX NRF_RX
#define UART6_GPIO_AF AF_NRF_RX
#define UART6_GPIO_PORT_CTS NRF_FLOW_CTRL_PORT
#define UART6_GPIO_CTS NRF_FLOW_CTRL
/**
* I2C defines
*/
// Digital noise filter: 0 disabled, [0x1 - 0xF] enable up to n t_I2CCLK
#define STM32_CR1_DNF(n) ((n & 0x0f) << 8)
// Timing register
#define I2C_FAST_400KHZ_DNF0_100NS_PCLK54MHZ_TIMINGR (STM32_TIMINGR_PRESC(0U) | \
STM32_TIMINGR_SCLDEL(10U) | STM32_TIMINGR_SDADEL(0U) | \
STM32_TIMINGR_SCLH(34U) | STM32_TIMINGR_SCLL(86U))
#define I2C_STD_100KHZ_DNF0_100NS_PCLK54MHZ_TIMINGR (STM32_TIMINGR_PRESC(1U) | \
STM32_TIMINGR_SCLDEL(9U) | STM32_TIMINGR_SDADEL(0U) | \
STM32_TIMINGR_SCLH(105U) | STM32_TIMINGR_SCLL(153U))
// Internal I2C (IMU, baro)
#ifndef I2C3_CLOCK_SPEED
#define I2C3_CLOCK_SPEED 400000
#endif
#if I2C3_CLOCK_SPEED == 400000
#define I2C3_DUTY_CYCLE FAST_DUTY_CYCLE_2
#elif I2C3_CLOCK_SPEED == 100000
#define I2C3_DUTY_CYCLE STD_DUTY_CYCLE
#else
#error "Invalid I2C3 clock speed"
#endif
#define I2C3_CFG_DEF { \
OPMODE_I2C, \
I2C3_CLOCK_SPEED, \
I2C3_DUTY_CYCLE, \
}
// External I2C
#ifndef I2C1_CLOCK_SPEED
#define I2C1_CLOCK_SPEED 400000
#endif
#if I2C1_CLOCK_SPEED == 400000
#define I2C1_DUTY_CYCLE FAST_DUTY_CYCLE_2
#elif I2C1_CLOCK_SPEED == 100000
#define I2C1_DUTY_CYCLE STD_DUTY_CYCLE
#else
#error "Invalid I2C1 clock speed"
#endif
#define I2C1_CFG_DEF { \
OPMODE_I2C, \
I2C1_CLOCK_SPEED, \
I2C1_DUTY_CYCLE, \
}
/*
#ifndef I2C3_CLOCK_SPEED
#define I2C3_CLOCK_SPEED 400000
#endif
#if I2C3_CLOCK_SPEED == 400000
#define I2C3_CFG_DEF { \
.timingr = I2C_FAST_400KHZ_DNF0_100NS_PCLK54MHZ_TIMINGR, \
.cr1 = STM32_CR1_DNF(0), \
.cr2 = 0 \
}
#elif I2C3_CLOCK_SPEED == 100000
#define I2C3_CFG_DEF { \
.timingr = I2C_STD_100KHZ_DNF0_100NS_PCLK54MHZ_TIMINGR, \
.cr1 = STM32_CR1_DNF(0), \
.cr2 = 0 \
}
#else
#error "Unknown I2C3 clock speed"
#endif
// External I2C
#ifndef I2C1_CLOCK_SPEED
#define I2C1_CLOCK_SPEED 400000
#endif
#if I2C1_CLOCK_SPEED == 400000
#define I2C1_CFG_DEF { \
.timingr = I2C_FAST_400KHZ_DNF0_100NS_PCLK54MHZ_TIMINGR, \
.cr1 = STM32_CR1_DNF(0), \
.cr2 = 0 \
}
#elif I2C1_CLOCK_SPEED == 100000
#define I2C1_CFG_DEF { \
.timingr = I2C_STD_100KHZ_DNF0_100NS_PCLK54MHZ_TIMINGR, \
.cr1 = STM32_CR1_DNF(0), \
.cr2 = 0 \
}
#else
#error "Unknown I2C2 clock speed"
#endif
*/
/**
* SPI Config
*/
// External SPI
#define SPI1_GPIO_AF AF_E_SCK
#define SPI1_GPIO_PORT_MISO E_MISO_PORT
#define SPI1_GPIO_MISO E_MISO
#define SPI1_GPIO_PORT_MOSI E_MOSI_PORT
#define SPI1_GPIO_MOSI E_MOSI
#define SPI1_GPIO_PORT_SCK E_SCK_PORT
#define SPI1_GPIO_SCK E_SCK
#define SPI_SELECT_SLAVE0_PORT E_CS0_PORT
#define SPI_SELECT_SLAVE0_PIN E_CS0
#define SPI_SELECT_SLAVE1_PORT E_CS1_PORT
#define SPI_SELECT_SLAVE1_PIN E_CS1
#define SPI_SELECT_SLAVE2_PORT E_CS2_PORT
#define SPI_SELECT_SLAVE2_PIN E_CS2
#define SPI_SELECT_SLAVE3_PORT E_CS3_PORT
#define SPI_SELECT_SLAVE3_PIN E_CS3
/**
* Baro
*
* Apparently needed for backwards compatibility
* with the ancient onboard baro boards
*/
#ifndef USE_BARO_BOARD
#define USE_BARO_BOARD 0
#endif
/*
* Actuators for fixedwing
*/
/* Default actuators driver */
#define DEFAULT_ACTUATORS "subsystems/actuators/actuators_pwm.h"
#define ActuatorDefaultSet(_x,_y) ActuatorPwmSet(_x,_y)
#define ActuatorsDefaultInit() ActuatorsPwmInit()
#define ActuatorsDefaultCommit() ActuatorsPwmCommit()
#endif /* CONFIG_TAWAKI_1_00_H */
@@ -0,0 +1,362 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _MCUCONF_H_
#define _MCUCONF_H_
/*
* STM32F4xx drivers configuration.
* The following settings override the default settings present in
* the various device driver implementation headers.
* Note that the settings for each driver only have effect if the whole
* driver is enabled in halconf.h.
*
* IRQ priorities:
* 15...0 Lowest...Highest.
*
* DMA priorities:
* 0...3 Lowest...Highest.
*/
#define STM32F4xx_MCUCONF
/*
* HAL driver system settings.
*/
#define STM32_NO_INIT FALSE
#define STM32_HSI_ENABLED TRUE
#define STM32_LSI_ENABLED FALSE
#define STM32_HSE_ENABLED TRUE
#define STM32_LSE_ENABLED FALSE
#define STM32_CLOCK48_REQUIRED TRUE
#define STM32_SW STM32_SW_PLL
#define STM32_PLLSRC STM32_PLLSRC_HSE
#define STM32_PLLM_VALUE 8
#define STM32_PLLN_VALUE 336
#define STM32_PLLP_VALUE 2
#define STM32_PLLQ_VALUE 7
#define STM32_HPRE STM32_HPRE_DIV1
#define STM32_PPRE1 STM32_PPRE1_DIV4
#define STM32_PPRE2 STM32_PPRE2_DIV2
#define STM32_RTCSEL STM32_RTCSEL_HSEDIV
#define STM32_RTCPRE_VALUE 8
#define STM32_MCO1SEL STM32_MCO1SEL_HSI
#define STM32_MCO1PRE STM32_MCO1PRE_DIV1
#define STM32_MCO2SEL STM32_MCO2SEL_SYSCLK
#define STM32_MCO2PRE STM32_MCO2PRE_DIV5
#define STM32_I2SSRC STM32_I2SSRC_CKIN
#define STM32_PLLI2SN_VALUE 192
#define STM32_PLLI2SR_VALUE 5
#define STM32_PVD_ENABLE FALSE
#define STM32_PLS STM32_PLS_LEV0
#define STM32_BKPRAM_ENABLE FALSE
/*
* ADC driver system settings.
*/
#define STM32_ADC_ADCPRE ADC_CCR_ADCPRE_DIV8
#define STM32_ADC_USE_ADC1 TRUE
#define STM32_ADC_USE_ADC2 FALSE
#define STM32_ADC_USE_ADC3 FALSE
#define STM32_ADC_ADC1_DMA_STREAM STM32_DMA_STREAM_ID(2, 4)
#define STM32_ADC_ADC2_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
#define STM32_ADC_ADC3_DMA_STREAM STM32_DMA_STREAM_ID(2, 1)
#define STM32_ADC_ADC1_DMA_PRIORITY 2
#define STM32_ADC_ADC2_DMA_PRIORITY 2
#define STM32_ADC_ADC3_DMA_PRIORITY 2
#define STM32_ADC_IRQ_PRIORITY 6
#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 6
#define STM32_ADC_ADC2_DMA_IRQ_PRIORITY 6
#define STM32_ADC_ADC3_DMA_IRQ_PRIORITY 6
/*
* CAN driver system settings.
*/
#define STM32_CAN_USE_CAN1 FALSE
#define STM32_CAN_USE_CAN2 FALSE
#define STM32_CAN_CAN1_IRQ_PRIORITY 11
#define STM32_CAN_CAN2_IRQ_PRIORITY 11
/*
* DAC driver system settings.
*/
#define STM32_DAC_DUAL_MODE FALSE
#define STM32_DAC_USE_DAC1_CH1 FALSE
#define STM32_DAC_USE_DAC1_CH2 FALSE
#define STM32_DAC_DAC1_CH1_IRQ_PRIORITY 10
#define STM32_DAC_DAC1_CH2_IRQ_PRIORITY 10
#define STM32_DAC_DAC1_CH1_DMA_PRIORITY 2
#define STM32_DAC_DAC1_CH2_DMA_PRIORITY 2
#define STM32_DAC_DAC1_CH1_DMA_STREAM STM32_DMA_STREAM_ID(1, 5)
#define STM32_DAC_DAC1_CH2_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
/*
* EXT driver system settings.
*/
#define STM32_EXT_EXTI0_IRQ_PRIORITY 6
#define STM32_EXT_EXTI1_IRQ_PRIORITY 6
#define STM32_EXT_EXTI2_IRQ_PRIORITY 6
#define STM32_EXT_EXTI3_IRQ_PRIORITY 6
#define STM32_EXT_EXTI4_IRQ_PRIORITY 6
#define STM32_EXT_EXTI5_9_IRQ_PRIORITY 6
#define STM32_EXT_EXTI10_15_IRQ_PRIORITY 6
#define STM32_EXT_EXTI16_IRQ_PRIORITY 6
#define STM32_EXT_EXTI17_IRQ_PRIORITY 15
#define STM32_EXT_EXTI18_IRQ_PRIORITY 6
#define STM32_EXT_EXTI19_IRQ_PRIORITY 6
#define STM32_EXT_EXTI20_IRQ_PRIORITY 6
#define STM32_EXT_EXTI21_IRQ_PRIORITY 15
#define STM32_EXT_EXTI22_IRQ_PRIORITY 15
/*
* GPT driver system settings.
*/
#define STM32_GPT_USE_TIM1 FALSE
#define STM32_GPT_USE_TIM2 FALSE
#define STM32_GPT_USE_TIM3 FALSE
#define STM32_GPT_USE_TIM4 FALSE
#define STM32_GPT_USE_TIM5 FALSE
#define STM32_GPT_USE_TIM6 FALSE
#define STM32_GPT_USE_TIM7 FALSE
#define STM32_GPT_USE_TIM8 FALSE
#define STM32_GPT_USE_TIM9 FALSE
#define STM32_GPT_USE_TIM11 FALSE
#define STM32_GPT_USE_TIM12 FALSE
#define STM32_GPT_USE_TIM14 FALSE
#define STM32_GPT_TIM1_IRQ_PRIORITY 7
#define STM32_GPT_TIM2_IRQ_PRIORITY 7
#define STM32_GPT_TIM3_IRQ_PRIORITY 7
#define STM32_GPT_TIM4_IRQ_PRIORITY 7
#define STM32_GPT_TIM5_IRQ_PRIORITY 7
#define STM32_GPT_TIM6_IRQ_PRIORITY 7
#define STM32_GPT_TIM7_IRQ_PRIORITY 7
#define STM32_GPT_TIM8_IRQ_PRIORITY 7
#define STM32_GPT_TIM9_IRQ_PRIORITY 7
#define STM32_GPT_TIM11_IRQ_PRIORITY 7
#define STM32_GPT_TIM12_IRQ_PRIORITY 7
#define STM32_GPT_TIM14_IRQ_PRIORITY 7
/*
* I2C driver system settings.
*/
#if USE_I2C1
#define STM32_I2C_USE_I2C1 TRUE
#else
#define STM32_I2C_USE_I2C1 FALSE
#endif
#define STM32_I2C_USE_I2C2 FALSE
#if USE_I2C3
#define STM32_I2C_USE_I2C3 TRUE
#else
#define STM32_I2C_USE_I2C3 FALSE
#endif
#define STM32_I2C_BUSY_TIMEOUT 50
#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
#define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
#define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
#define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
#define STM32_I2C_I2C3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
#define STM32_I2C_I2C3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
#define STM32_I2C_I2C1_IRQ_PRIORITY 5
#define STM32_I2C_I2C2_IRQ_PRIORITY 5
#define STM32_I2C_I2C3_IRQ_PRIORITY 5
#define STM32_I2C_I2C1_DMA_PRIORITY 3
#define STM32_I2C_I2C2_DMA_PRIORITY 3
#define STM32_I2C_I2C3_DMA_PRIORITY 3
#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
/*
* ICU driver system settings.
*/
#define STM32_ICU_USE_TIM1 FALSE
#define STM32_ICU_USE_TIM2 FALSE
#define STM32_ICU_USE_TIM3 FALSE
#define STM32_ICU_USE_TIM4 FALSE
#define STM32_ICU_USE_TIM5 FALSE
#define STM32_ICU_USE_TIM8 FALSE
#define STM32_ICU_USE_TIM9 TRUE
#define STM32_ICU_TIM1_IRQ_PRIORITY 7
#define STM32_ICU_TIM2_IRQ_PRIORITY 7
#define STM32_ICU_TIM3_IRQ_PRIORITY 7
#define STM32_ICU_TIM4_IRQ_PRIORITY 7
#define STM32_ICU_TIM5_IRQ_PRIORITY 7
#define STM32_ICU_TIM8_IRQ_PRIORITY 7
#define STM32_ICU_TIM9_IRQ_PRIORITY 7
/*
* MAC driver system settings.
*/
#define STM32_MAC_TRANSMIT_BUFFERS 2
#define STM32_MAC_RECEIVE_BUFFERS 4
#define STM32_MAC_BUFFERS_SIZE 1522
#define STM32_MAC_PHY_TIMEOUT 100
#define STM32_MAC_ETH1_CHANGE_PHY_STATE TRUE
#define STM32_MAC_ETH1_IRQ_PRIORITY 13
#define STM32_MAC_IP_CHECKSUM_OFFLOAD 0
/*
* PWM driver system settings.
*/
#define STM32_PWM_USE_ADVANCED FALSE
#define STM32_PWM_USE_TIM1 FALSE // enable for WS2812
#ifndef STM32_PWM_USE_TIM2
#define STM32_PWM_USE_TIM2 TRUE
#endif
#define STM32_PWM_USE_TIM3 FALSE
#ifndef STM32_PWM_USE_TIM4
#define STM32_PWM_USE_TIM4 TRUE
#endif
#define STM32_PWM_USE_TIM5 FALSE
#define STM32_PWM_USE_TIM8 FALSE
#define STM32_PWM_USE_TIM9 FALSE
#define STM32_PWM_TIM1_IRQ_PRIORITY 7
#define STM32_PWM_TIM2_IRQ_PRIORITY 7
#define STM32_PWM_TIM3_IRQ_PRIORITY 7
#define STM32_PWM_TIM4_IRQ_PRIORITY 7
#define STM32_PWM_TIM5_IRQ_PRIORITY 7
#define STM32_PWM_TIM8_IRQ_PRIORITY 7
#define STM32_PWM_TIM9_IRQ_PRIORITY 7
/*
* SERIAL driver system settings.
*/
#define STM32_SERIAL_USE_USART1 FALSE
#if USE_UART2
#define STM32_SERIAL_USE_USART2 TRUE
#else
#define STM32_SERIAL_USE_USART2 FALSE
#endif
#if USE_UART3
#define STM32_SERIAL_USE_USART3 TRUE
#else
#define STM32_SERIAL_USE_USART3 FALSE
#endif
#define STM32_SERIAL_USE_UART4 FALSE
#define STM32_SERIAL_USE_UART5 FALSE
#if USE_UART6
#define STM32_SERIAL_USE_USART6 TRUE
#else
#define STM32_SERIAL_USE_USART6 FALSE
#endif
#define STM32_SERIAL_USART1_PRIORITY 12
#define STM32_SERIAL_USART2_PRIORITY 12
#define STM32_SERIAL_USART3_PRIORITY 12
#define STM32_SERIAL_UART4_PRIORITY 12
#define STM32_SERIAL_UART5_PRIORITY 12
#define STM32_SERIAL_USART6_PRIORITY 12
/*
* SPI driver system settings.
*/
#if USE_SPI1
#define STM32_SPI_USE_SPI1 TRUE
#else
#define STM32_SPI_USE_SPI1 FALSE
#endif
#define STM32_SPI_USE_SPI2 FALSE
#define STM32_SPI_USE_SPI3 FALSE
#define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0)
#define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5)
#define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
#define STM32_SPI_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
#define STM32_SPI_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
#define STM32_SPI_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
#define STM32_SPI_SPI1_DMA_PRIORITY 1
#define STM32_SPI_SPI2_DMA_PRIORITY 1
#define STM32_SPI_SPI3_DMA_PRIORITY 1
#define STM32_SPI_SPI1_IRQ_PRIORITY 10
#define STM32_SPI_SPI2_IRQ_PRIORITY 10
#define STM32_SPI_SPI3_IRQ_PRIORITY 10
#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
/*
* ST driver system settings.
*/
#define STM32_ST_IRQ_PRIORITY 8
#define STM32_ST_USE_TIMER 2
/*
* UART driver system settings.
*/
#define STM32_UART_USE_USART1 FALSE
#define STM32_UART_USE_USART2 FALSE
#define STM32_UART_USE_USART3 FALSE
#define STM32_UART_USE_UART4 FALSE
#define STM32_UART_USE_UART5 FALSE
#define STM32_UART_USE_USART6 FALSE
#define STM32_UART_USART1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5) // Not used: conflict SPI1
#define STM32_UART_USART1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
#define STM32_UART_USART2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5)
#define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
#define STM32_UART_USART3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 1)
#define STM32_UART_USART3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
#define STM32_UART_UART4_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
#define STM32_UART_UART4_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
#define STM32_UART_UART5_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
#define STM32_UART_UART5_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
#define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
#define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 6)
#define STM32_UART_USART1_IRQ_PRIORITY 12
#define STM32_UART_USART2_IRQ_PRIORITY 12
#define STM32_UART_USART3_IRQ_PRIORITY 12
#define STM32_UART_UART4_IRQ_PRIORITY 12
#define STM32_UART_UART5_IRQ_PRIORITY 12
#define STM32_UART_USART6_IRQ_PRIORITY 12
#define STM32_UART_USART1_DMA_PRIORITY 1
#define STM32_UART_USART2_DMA_PRIORITY 0
#define STM32_UART_USART3_DMA_PRIORITY 0
#define STM32_UART_UART4_DMA_PRIORITY 0
#define STM32_UART_UART5_DMA_PRIORITY 0
#define STM32_UART_USART6_DMA_PRIORITY 0
#define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure")
/*
* USB driver system settings.
*/
#define STM32_USB_USE_OTG1 TRUE // FS, DFU_BOOT
#define STM32_USB_USE_OTG2 FALSE // HS
#define STM32_USB_OTG1_IRQ_PRIORITY 14
#define STM32_USB_OTG2_IRQ_PRIORITY 14
#define STM32_USB_OTG1_RX_FIFO_SIZE 512
#define STM32_USB_OTG2_RX_FIFO_SIZE 512
#define STM32_USB_OTG_THREAD_PRIO HIGHPRIO
#define STM32_USB_OTG_THREAD_STACK_SIZE 256
#define STM32_USB_OTGFIFO_FILL_BASEPRI 0
/*
* SDC driver system settings.
*/
#define STM32_SDC_SDIO_DMA_STREAM STM32_DMA_STREAM_ID(2, 3)
#define STM32_SDC_SDIO_DMA_PRIORITY 3
#define STM32_SDC_SDIO_IRQ_PRIORITY 9
#define STM32_SDC_CLOCK_ACTIVATION_DELAY 10
#define STM32_SDC_SDIO_UNALIGNED_SUPPORT FALSE
#define STM32_SDC_WRITE_TIMEOUT_MS 250
#define STM32_SDC_READ_TIMEOUT_MS 15
/*
sdlog message buffer and queue configuration
*/
#define SDLOG_QUEUE_BUCKETS 1024
#define SDLOG_MAX_MESSAGE_LEN 300
#define SDLOG_NUM_FILES 2
#define SDLOG_ALL_BUFFERS_SIZE (SDLOG_NUM_FILES*8*1024)
#endif /* _MCUCONF_H_ */
+156
View File
@@ -0,0 +1,156 @@
/*
* Copyright (C) 2020 Gautier Hattenberger <gautier.hattenberger@enac.fr>
*
* This file is part of paparazzi.
*
* paparazzi 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 2, or (at your option)
* any later version.
*
* paparazzi 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 paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* @file modules/ahrs/ahrs_madgwick.h
* AHRS using Madgwick implementation
*
* See:
* https://x-io.co.uk/open-source-imu-and-ahrs-algorithms/
*/
#include "modules/ahrs/ahrs_madgwick.h"
#include "generated/airframe.h"
#include "math/pprz_algebra_float.h"
#include "subsystems/ahrs/ahrs_float_utils.h"
#ifndef AHRS_MADGWICK_BETA
#define AHRS_MADGWICK_BETA 0.1f // 2 * proportional gain
#endif
struct AhrsMadgwick ahrs_madgwick;
/* init state and measurements */
static inline void init_state(void)
{
float_quat_identity(&ahrs_madgwick.quat);
FLOAT_RATES_ZERO(ahrs_madgwick.bias);
FLOAT_VECT3_ZERO(ahrs_madgwick.accel);
}
void ahrs_madgwick_init(void)
{
// init state and measurements
init_state();
ahrs_madgwick.is_aligned = false;
ahrs_madgwick.reset = false;
}
void ahrs_madgwick_align(struct FloatRates *lp_gyro, struct FloatVect3 *lp_accel)
{
/* Compute an initial orientation from accel directly as quaternion */
ahrs_float_get_quat_from_accel(&ahrs_madgwick.quat, lp_accel);
/* use average gyro as initial value for bias */
ahrs_madgwick.bias = *lp_gyro;
// ins and ahrs are now running
ahrs_madgwick.is_aligned = true;
}
void ahrs_madgwick_propagate(struct FloatRates* gyro, float dt)
{
struct FloatQuat qdot;
// realign all the filter if needed
// a complete init cycle is required
if (ahrs_madgwick.reset) {
ahrs_madgwick.reset = false;
ahrs_madgwick.is_aligned = false;
init_state();
}
// unbias and rotate gyro
struct FloatRates gyro_unbiased;
RATES_DIFF(gyro_unbiased, *gyro, ahrs_madgwick.bias);
struct FloatRMat *body_to_imu_rmat = orientationGetRMat_f(&ahrs_madgwick.body_to_imu);
float_rmat_transp_ratemult(&ahrs_madgwick.rates, body_to_imu_rmat, &gyro_unbiased);
// Rate of change of quaternion from gyroscope
float_quat_derivative(&qdot, &ahrs_madgwick.rates, &ahrs_madgwick.quat);
// compute accel norm
float norm = float_vect3_norm(&ahrs_madgwick.accel);
// Compute feedback only if accelerometer measurement valid
// (avoids NaN in accelerometer normalisation)
if (norm > 0.01f) {
// Normalise accelerometer measurement
// direction of accel is inverted to comply with filter original frame
struct FloatVect3 a;
VECT3_SDIV(a, ahrs_madgwick.accel, -norm);
// Auxiliary variables to avoid repeated arithmetic
const float q1 = ahrs_madgwick.quat.qx;
const float q2 = ahrs_madgwick.quat.qy;
const float q3 = ahrs_madgwick.quat.qz;
const float _2q0 = 2.0f * ahrs_madgwick.quat.qi;
const float _2q1 = 2.0f * ahrs_madgwick.quat.qx;
const float _2q2 = 2.0f * ahrs_madgwick.quat.qy;
const float _2q3 = 2.0f * ahrs_madgwick.quat.qz;
const float _4q0 = 4.0f * ahrs_madgwick.quat.qi;
const float _4q1 = 4.0f * ahrs_madgwick.quat.qx;
const float _4q2 = 4.0f * ahrs_madgwick.quat.qy;
const float _8q1 = 8.0f * ahrs_madgwick.quat.qx;
const float _8q2 = 8.0f * ahrs_madgwick.quat.qy;
const float q0q0 = ahrs_madgwick.quat.qi * ahrs_madgwick.quat.qi;
const float q1q1 = ahrs_madgwick.quat.qx * ahrs_madgwick.quat.qx;
const float q2q2 = ahrs_madgwick.quat.qy * ahrs_madgwick.quat.qy;
const float q3q3 = ahrs_madgwick.quat.qz * ahrs_madgwick.quat.qz;
// Gradient decent algorithm corrective step
const float s0 = _4q0 * q2q2 + _2q2 * a.x + _4q0 * q1q1 - _2q1 * a.y;
const float s1 = _4q1 * q3q3 - _2q3 * a.x + 4.0f * q0q0 * q1 - _2q0 * a.y - _4q1 + _8q1 * q1q1 + _8q1 * q2q2 + _4q1 * a.z;
const float s2 = 4.0f * q0q0 * q2 + _2q0 * a.x + _4q2 * q3q3 - _2q3 * a.y - _4q2 + _8q2 * q1q1 + _8q2 * q2q2 + _4q2 * a.z;
const float s3 = 4.0f * q1q1 * q3 - _2q1 * a.x + 4.0f * q2q2 * q3 - _2q2 * a.y;
const float beta_inv_grad_norm = AHRS_MADGWICK_BETA / sqrtf(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3);
// Apply feedback step
qdot.qi -= s0 * beta_inv_grad_norm;
qdot.qx -= s1 * beta_inv_grad_norm;
qdot.qy -= s2 * beta_inv_grad_norm;
qdot.qz -= s3 * beta_inv_grad_norm;
}
// Integrate rate of change of quaternion to yield quaternion
ahrs_madgwick.quat.qi += qdot.qi * dt;
ahrs_madgwick.quat.qx += qdot.qx * dt;
ahrs_madgwick.quat.qy += qdot.qy * dt;
ahrs_madgwick.quat.qz += qdot.qz * dt;
// Normalise quaternion
float_quat_normalize(&ahrs_madgwick.quat);
}
void ahrs_madgwick_update_accel(struct FloatVect3* accel)
{
ahrs_madgwick.accel = *accel;
}
void ahrs_madgwick_set_body_to_imu_quat(struct FloatQuat *q_b2i)
{
orientationSetQuat_f(&ahrs_madgwick.body_to_imu, q_b2i);
if (!ahrs_madgwick.is_aligned) {
/* Set ltp_to_imu so that body is zero */
ahrs_madgwick.quat = *q_b2i;
}
}
+57
View File
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2020 Gautier Hattenberger <gautier.hattenberger@enac.fr>
*
* This file is part of paparazzi.
*
* paparazzi 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 2, or (at your option)
* any later version.
*
* paparazzi 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 paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* @file modules/ahrs/ahrs_madgwick.h
* AHRS using Madgwick implementation
*
* See:
* https://x-io.co.uk/open-source-imu-and-ahrs-algorithms/
*/
#ifndef AHRS_MADGWICK_H
#define AHRS_MADGWICK_H
#include "subsystems/ahrs.h"
#include "math/pprz_algebra_float.h"
#include "math/pprz_orientation_conversion.h"
/** Madgwick filter structure
*/
struct AhrsMadgwick {
struct FloatQuat quat; ///< Estimated attitude (quaternion)
struct FloatRates rates; ///< Measured gyro rates
struct FloatRates bias; ///< Gyro bias (from alignment)
struct FloatVect3 accel; ///< Measured accelerometers
struct OrientationReps body_to_imu; ///< body_to_imu rotation
bool reset; ///< flag to request reset/reinit the filter
bool is_aligned; ///< aligned flag
};
extern struct AhrsMadgwick ahrs_madgwick;
extern void ahrs_madgwick_init(void);
extern void ahrs_madgwick_set_body_to_imu_quat(struct FloatQuat *q_b2i);
extern void ahrs_madgwick_align(struct FloatRates *lp_gyro, struct FloatVect3 *lp_accel);
extern void ahrs_madgwick_propagate(struct FloatRates* gyro, float dt);
extern void ahrs_madgwick_update_accel(struct FloatVect3* accel);
#endif /* AHRS_MADGWICK_H */
@@ -0,0 +1,222 @@
/*
* Copyright (C) 2020 Gautier Hattenberger <gautier.hattenberger@enac.fr>
*
* This file is part of paparazzi.
*
* paparazzi 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 2, or (at your option)
* any later version.
*
* paparazzi 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 Paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* @file modules/ahrs/ahrs_madgwick_wrapper.c
*
* Paparazzi specific wrapper to run Madgwick ahrs filter.
*/
#include "modules/ahrs/ahrs_madgwick_wrapper.h"
#include "subsystems/ahrs.h"
#include "subsystems/abi.h"
#include "mcu_periph/sys_time.h"
#include "message_pragmas.h"
#include "state.h"
#ifndef AHRS_MADGWICK_OUTPUT_ENABLED
#define AHRS_MADGWICK_OUTPUT_ENABLED TRUE
#endif
PRINT_CONFIG_VAR(AHRS_MADGWICK_OUTPUT_ENABLED)
/** if TRUE with push the estimation results to the state interface */
static bool ahrs_madgwick_output_enabled;
/** last gyro msg timestamp */
static uint32_t ahrs_madgwick_last_stamp = 0;
static uint8_t ahrs_madgwick_id = AHRS_COMP_ID_MADGWICK;
static void compute_body_orientation_and_rates(void);
#if PERIODIC_TELEMETRY
#include "subsystems/datalink/telemetry.h"
static void send_att(struct transport_tx *trans, struct link_device *dev)
{
/* compute eulers in int (IMU frame) */
struct FloatEulers ltp_to_imu_euler;
float_eulers_of_quat(&ltp_to_imu_euler, &ahrs_madgwick.quat);
struct Int32Eulers eulers_imu;
EULERS_BFP_OF_REAL(eulers_imu, ltp_to_imu_euler);
/* compute Eulers in int (body frame) */
struct FloatQuat ltp_to_body_quat;
struct FloatQuat *body_to_imu_quat = orientationGetQuat_f(&ahrs_madgwick.body_to_imu);
float_quat_comp_inv(&ltp_to_body_quat, &ahrs_madgwick.quat, body_to_imu_quat);
struct FloatEulers ltp_to_body_euler;
float_eulers_of_quat(&ltp_to_body_euler, &ltp_to_body_quat);
struct Int32Eulers eulers_body;
EULERS_BFP_OF_REAL(eulers_body, ltp_to_body_euler);
pprz_msg_send_AHRS_EULER_INT(trans, dev, AC_ID,
&eulers_imu.phi,
&eulers_imu.theta,
&eulers_imu.psi,
&eulers_body.phi,
&eulers_body.theta,
&eulers_body.psi,
&ahrs_madgwick_id);
}
static void send_filter_status(struct transport_tx *trans, struct link_device *dev)
{
uint8_t mde = 3;
uint16_t val = 0;
if (!ahrs_madgwick.is_aligned) { mde = 2; }
uint32_t t_diff = get_sys_time_usec() - ahrs_madgwick_last_stamp;
/* set lost if no new gyro measurements for 50ms */
if (t_diff > 50000) { mde = 5; }
pprz_msg_send_STATE_FILTER_STATUS(trans, dev, AC_ID, &ahrs_madgwick_id, &mde, &val);
}
#endif
/*
* ABI bindings
*/
/** IMU (gyro, accel) */
#ifndef AHRS_MADGWICK_IMU_ID
#define AHRS_MADGWICK_IMU_ID ABI_BROADCAST
#endif
PRINT_CONFIG_VAR(AHRS_MADGWICK_IMU_ID)
/** magnetometer */
#ifndef AHRS_MADGWICK_MAG_ID
#define AHRS_MADGWICK_MAG_ID AHRS_MADGWICK_IMU_ID
#endif
PRINT_CONFIG_VAR(AHRS_MADGWICK_MAG_ID)
static abi_event gyro_ev;
static abi_event accel_ev;
static abi_event aligner_ev;
static abi_event body_to_imu_ev;
/**
* Call ahrs_madgwick_propagate on new gyro measurements.
* Since acceleration measurement is also needed for propagation,
* use the last stored accel from #ahrs_madgwick_accel.
*/
static void gyro_cb(uint8_t sender_id __attribute__((unused)),
uint32_t stamp, struct Int32Rates *gyro)
{
struct FloatRates gyro_f;
RATES_FLOAT_OF_BFP(gyro_f, *gyro);
#if USE_AUTO_AHRS_FREQ || !defined(AHRS_PROPAGATE_FREQUENCY)
PRINT_CONFIG_MSG("Calculating dt for AHRS Madgwick propagation.")
/* timestamp in usec when last callback was received */
static uint32_t last_stamp = 0;
if (last_stamp > 0 && ahrs_madgwick.is_aligned) {
float dt = (float)(stamp - last_stamp) * 1e-6;
ahrs_madgwick_propagate(&gyro_f, dt);
compute_body_orientation_and_rates();
}
last_stamp = stamp;
#else
PRINT_CONFIG_MSG("Using fixed AHRS_PROPAGATE_FREQUENCY for AHRS Madgwick propagation.")
PRINT_CONFIG_VAR(AHRS_PROPAGATE_FREQUENCY)
const float dt = 1. / (AHRS_PROPAGATE_FREQUENCY);
if (ahrs_madgwick.is_aligned) {
ahrs_madgwick_propagate(&gyro_f, dt);
compute_body_orientation_and_rates();
}
#endif
ahrs_madgwick_last_stamp = stamp;
}
static void accel_cb(uint8_t sender_id __attribute__((unused)),
uint32_t stamp __attribute__((unused)),
struct Int32Vect3 *accel)
{
if (ahrs_madgwick.is_aligned) {
struct FloatVect3 accel_f;
ACCELS_FLOAT_OF_BFP(accel_f, *accel);
ahrs_madgwick_update_accel(&accel_f);
}
}
static void aligner_cb(uint8_t __attribute__((unused)) sender_id,
uint32_t stamp __attribute__((unused)),
struct Int32Rates *lp_gyro, struct Int32Vect3 *lp_accel,
struct Int32Vect3 *lp_mag __attribute__((unused)))
{
if (!ahrs_madgwick.is_aligned) {
/* convert to float */
struct FloatRates gyro_f;
RATES_FLOAT_OF_BFP(gyro_f, *lp_gyro);
struct FloatVect3 accel_f;
ACCELS_FLOAT_OF_BFP(accel_f, *lp_accel);
ahrs_madgwick_align(&gyro_f, &accel_f);
compute_body_orientation_and_rates();
}
}
static void body_to_imu_cb(uint8_t sender_id __attribute__((unused)),
struct FloatQuat *q_b2i_f)
{
ahrs_madgwick_set_body_to_imu_quat(q_b2i_f);
}
static bool ahrs_madgwick_enable_output(bool enable)
{
ahrs_madgwick_output_enabled = enable;
return ahrs_madgwick_output_enabled;
}
/**
* Compute body orientation and rates from imu orientation and rates
*/
static void compute_body_orientation_and_rates(void)
{
if (ahrs_madgwick_output_enabled) {
/* Compute LTP to BODY quaternion */
struct FloatQuat ltp_to_body_quat;
struct FloatQuat *body_to_imu_quat = orientationGetQuat_f(&ahrs_madgwick.body_to_imu);
float_quat_comp_inv(&ltp_to_body_quat, &ahrs_madgwick.quat, body_to_imu_quat);
/* Set state */
stateSetNedToBodyQuat_f(&ltp_to_body_quat);
/* compute body rates */
stateSetBodyRates_f(&ahrs_madgwick.rates);
}
}
void ahrs_madgwick_register(void)
{
ahrs_madgwick_output_enabled = AHRS_MADGWICK_OUTPUT_ENABLED;
ahrs_madgwick_init();
ahrs_register_impl(ahrs_madgwick_enable_output);
/*
* Subscribe to scaled IMU measurements and attach callbacks
*/
AbiBindMsgIMU_GYRO_INT32(AHRS_MADGWICK_IMU_ID, &gyro_ev, gyro_cb);
AbiBindMsgIMU_ACCEL_INT32(AHRS_MADGWICK_IMU_ID, &accel_ev, accel_cb);
AbiBindMsgIMU_LOWPASSED(AHRS_MADGWICK_IMU_ID, &aligner_ev, aligner_cb);
AbiBindMsgBODY_TO_IMU_QUAT(AHRS_MADGWICK_IMU_ID, &body_to_imu_ev, body_to_imu_cb);
#if PERIODIC_TELEMETRY
register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_AHRS_EULER_INT, send_att);
register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_STATE_FILTER_STATUS, send_filter_status);
#endif
}
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2020 Gautier Hattenberger <gautier.hattenberger@enac.fr>
*
* This file is part of paparazzi.
*
* paparazzi 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 2, or (at your option)
* any later version.
*
* paparazzi 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 Paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* @file modules/ahrs/ahrs_madgwick_wrapper.h
*
* Paparazzi specific wrapper to run Madgwick ahrs filter.
*/
#ifndef AHRS_MADGWICK_WRAPPER_H
#define AHRS_MADGWICK_WRAPPER_H
#include "modules/ahrs/ahrs_madgwick.h"
#ifndef PRIMARY_AHRS
#define PRIMARY_AHRS ahrs_madgwick
#endif
extern void ahrs_madgwick_register(void);
#endif /* AHRS_MADGWICK_WRAPPER_H */
@@ -0,0 +1,75 @@
/*
* Copyright (C) 2019 Gautier Hattenberger <gautier.hattenberger@enac.fr>
*
* This file is part of paparazzi.
*
* paparazzi 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 2, or (at your option)
* any later version.
*
* paparazzi 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 paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* @file modules/datalink/bitcraze/crtp.h
*
* CRTP protocol for communication with bitcraze/crazyflie modems
*
* based on PX4 implementation
*/
#ifndef CRTP_H
#define CRTP_H
#include "std.h"
#define CRTP_PORT_CONSOLE 0x00
#define CRTP_PORT_PARAM 0x02
#define CRTP_PORT_COMMANDER 0x03
#define CRTP_PORT_MEM 0x04
#define CRTP_PORT_LOG 0x05
#define CRTP_PORT_PPRZLINK 0x09 // Non-standard port for transmitting pprzlink messages
#define CRTP_PORT_PLATFORM 0x0D
#define CRTP_PORT_DEBUG 0x0E
#define CRTP_PORT_LINK 0x0F
#define CRTP_NULL(x) (((x).header & 0xf3) == 0xf3)
// 1 byte header + 31 bytes data = 32 (max ESB packet size)
// With the NRF51, this could be increased to ~250, but the Crazyradio PA uses a NRF24 which can't do this
#define CRTP_MAX_DATA_SIZE 31
typedef struct {
uint8_t size; // Total size of this message, including the header (placed here to overlap with syslink length field)
union {
uint8_t header;
struct {
uint8_t channel : 2;
uint8_t link : 2;
uint8_t port : 4;
};
};
uint8_t data[CRTP_MAX_DATA_SIZE];
} __attribute__((packed)) crtp_message_t;
typedef struct {
float roll; // -20 to 20
float pitch;
float yaw; // -150 to 150
uint16_t thrust;
} crtp_commander;
#endif
@@ -0,0 +1,125 @@
/*
* Copyright (C) 2019 Gautier Hattenberger <gautier.hattenberger@enac.fr>
*
* This file is part of paparazzi.
*
* paparazzi 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 2, or (at your option)
* any later version.
*
* paparazzi 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 paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* @file modules/datalink/bitcraze/syslink.c
*
* Syslink protocol for communication with bitcraze/crazyflie NRF mcu
*
* based on PX4 implementation
*/
#include "syslink.h"
const char *syslink_stx = "\xbc\xcf";
void syslink_parse_init(syslink_parse_state *state)
{
state->state = SYSLINK_STATE_START;
state->index = 0;
}
bool syslink_parse_char(syslink_parse_state *state, uint8_t c, syslink_message_t *msg)
{
switch (state->state) {
case SYSLINK_STATE_START:
if (c == syslink_stx[state->index]) {
state->index++;
} else {
state->index = 0;
}
if (syslink_stx[state->index] == '\x00') {
state->state = SYSLINK_STATE_TYPE;
}
break;
case SYSLINK_STATE_TYPE:
msg->type = c;
state->state = SYSLINK_STATE_LENGTH;
break;
case SYSLINK_STATE_LENGTH:
msg->length = c;
if (c > SYSLINK_MAX_DATA_LEN) { // Too long
state->state = SYSLINK_STATE_START;
} else {
state->state = c > 0 ? SYSLINK_STATE_DATA : SYSLINK_STATE_CKSUM;
}
state->index = 0;
break;
case SYSLINK_STATE_DATA:
msg->data[state->index++] = c;
if (state->index >= msg->length) {
state->state = SYSLINK_STATE_CKSUM;
state->index = 0;
syslink_compute_cksum(msg);
}
break;
case SYSLINK_STATE_CKSUM:
if (c != msg->cksum[state->index]) {
// fail checksum
state->state = SYSLINK_STATE_START;
state->index = 0;
break;
}
state->index++;
if (state->index >= (int)sizeof(msg->cksum)) {
state->state = SYSLINK_STATE_START;
state->index = 0;
return true; // message is correct, return true
}
break;
}
return false;
}
/*
Computes Fletcher 8bit checksum per RFC1146
A := A + D[i]
B := B + A
*/
void syslink_compute_cksum(syslink_message_t *msg)
{
uint8_t a = 0, b = 0;
uint8_t *Di = (uint8_t *)msg, *end = Di + (2 + msg->length) * sizeof(uint8_t);
while (Di < end) {
a = a + *Di;
b = b + a;
++Di;
}
msg->cksum[0] = a;
msg->cksum[1] = b;
}
@@ -0,0 +1,119 @@
/*
* Copyright (C) 2019 Gautier Hattenberger <gautier.hattenberger@enac.fr>
*
* This file is part of paparazzi.
*
* paparazzi 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 2, or (at your option)
* any later version.
*
* paparazzi 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 paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* @file modules/datalink/bitcraze/syslink.h
*
* Syslink protocol for communication with bitcraze/crazyflie NRF mcu
*
* based on PX4 implementation
*/
#ifndef SYSLINK_H
#define SYSLINK_H
#include <stdint.h>
#include <stdbool.h>
#define SYSLINK_GROUP 0xF0
#define SYSLINK_RADIO 0x00
#define SYSLINK_RADIO_RAW 0x00
#define SYSLINK_RADIO_CHANNEL 0x01
#define SYSLINK_RADIO_DATARATE 0x02
#define SYSLINK_RADIO_CONTWAVE 0x03
#define SYSLINK_RADIO_RSSI 0x04
#define SYSLINK_RADIO_ADDRESS 0x05
#define SYSLINK_PM 0x10
#define SYSLINK_PM_SOURCE 0x10
#define SYSLINK_PM_ONOFF_SWITCHOFF 0x11
#define SYSLINK_PM_BATTERY_VOLTAGE 0x12
#define SYSLINK_PM_BATTERY_STATE 0x13
#define SYSLINK_PM_BATTERY_AUTOUPDATE 0x14
#define SYSLINK_OW 0x20
#define SYSLINK_OW_SCAN 0x20
#define SYSLINK_OW_GETINFO 0x21
#define SYSLINK_OW_READ 0x22
#define SYSLINK_OW_WRITE 0x23
// Limited by the CRTP packet which is limited by the ESB protocol used by the NRF
#define SYSLINK_MAX_DATA_LEN 32
#define SYSLINK_RADIO_RATE_250K 0
#define SYSLINK_RADIO_RATE_1M 1
#define SYSLINK_RADIO_RATE_2M 2
typedef struct {
uint8_t type;
uint8_t length;
uint8_t data[SYSLINK_MAX_DATA_LEN];
uint8_t cksum[2];
} __attribute__((packed)) syslink_message_t;
typedef enum {
SYSLINK_STATE_START = 0,
SYSLINK_STATE_TYPE,
SYSLINK_STATE_LENGTH,
SYSLINK_STATE_DATA,
SYSLINK_STATE_CKSUM
} syslink_state_t;
typedef struct {
syslink_state_t state;
int index;
} syslink_parse_state;
extern const char *syslink_stx;
#ifdef __cplusplus
extern "C" {
#endif
/** Init syslink parser
*
* @param state pointer to state structure
*/
extern void syslink_parse_init(syslink_parse_state *state);
/** Parse one byte
*
* @param state pointer to state structure
* @param c next byte to parse
* @param msg pointer to message structure
* @return true if a full message was parsed
*/
extern bool syslink_parse_char(syslink_parse_state *state, uint8_t c, syslink_message_t *msg);
/** Compute syslink checksum
*
* @param msg pointer to message structure
*/
extern void syslink_compute_cksum(syslink_message_t *msg);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,422 @@
/*
* Copyright (C) 2019 Gautier Hattenberger <gautier.hattenberger@enac.fr>
*
* This file is part of paparazzi.
*
* paparazzi 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 2, or (at your option)
* any later version.
*
* paparazzi 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 paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* @file modules/datalink/bitcraze/syslink_dl.c
*
* Syslink protocol handling and functionalities
*
*/
#include "modules/datalink/bitcraze/syslink_dl.h"
#include "subsystems/electrical.h"
#include "mcu_periph/uart.h"
#include <string.h>
#include "led.h"
struct syslink_dl syslink;
/** Protect syslink TX with Mutex when using RTOS */
#include "pprz_mutex.h"
PPRZ_MUTEX(syslink_tx_mtx);
/** Send a syslink message
*/
static void send_message(syslink_message_t *msg)
{
syslink_compute_cksum(msg);
uint8_t buf[sizeof(syslink_message_t)];
buf[0] = syslink_stx[0];
buf[1] = syslink_stx[1];
buf[2] = msg->type;
buf[3] = msg->length;
for (int i = 0; i < msg->length; i++) {
buf[4+i] = msg->data[i];
}
buf[msg->length+4] = msg->cksum[0];
buf[msg->length+5] = msg->cksum[1];
uart_put_buffer(&(SYSLINK_DEV), 0, buf, msg->length+6);
//uart_put_buffer(&(SYSLINK_DEV), 0, (uint8_t*)syslink_stx, 2);
//uart_put_buffer(&(SYSLINK_DEV), 0, (uint8_t*)(&msg->type), sizeof(msg->type));
//uart_put_buffer(&(SYSLINK_DEV), 0, (uint8_t*)(&msg->length), sizeof(msg->length));
//uart_put_buffer(&(SYSLINK_DEV), 0, (uint8_t*)(&msg->data), msg->length);
//uart_put_buffer(&(SYSLINK_DEV), 0, (uint8_t*)(&msg->cksum), sizeof(msg->cksum));
}
/**
* Handle battery message
*/
static void handle_battery(syslink_message_t *msg)
{
if (msg->length != 9) {
return;
}
// check flag
uint8_t flags = msg->data[0];
syslink.charging = (bool) (flags & 1);
syslink.powered = (bool) (flags & 2);
// update voltage
float vbat;
memcpy(&vbat, &msg->data[1], sizeof(float));
if (syslink.powered && vbat > 3.f) {
electrical.vsupply = vbat; // remove 0 reading when powered on USB ?
} else if (!syslink.powered) {
electrical.vsupply = vbat; // running on battery
}
}
/**
* Handle various raw messages
*/
static void handle_raw_other(syslink_message_t *msg)
{
// This function doesn't actually do anything
// It is just here to return null responses to most standard messages
// Setup order from the cflib-python is
// - platform link source (name, protocol version)
// - log TOC
// - mem update
// - param TOC
// -> call connected callback and start getting data
// - update param if needed
crtp_message_t *c = (crtp_message_t *) &msg->length;
if (c->port == CRTP_PORT_LOG) {
if (c->channel == 0) { // Table of Contents Access
uint8_t cmd = c->data[0];
if (cmd == 0) { // GET_ITEM
//int id = c->data[1];
memset(&c->data[2], 0, 3);
c->data[2] = 1; // type
c->size = 1 + 5;
send_message(msg);
} else if (cmd == 1) { // GET_INFO
memset(&c->data[1], 0, 7);
c->size = 1 + 8;
send_message(msg);
}
}
else if (c->channel == 1) { // Log control
c->data[2] = 0; // Success
c->size = 3 + 1;
// resend message
send_message(msg);
}
else if (c->channel == 2) { // Log data
// nothing
}
}
else if (c->port == CRTP_PORT_MEM) {
if (c->channel == 0) { // Info
int cmd = c->data[0];
if (cmd == 1) { // GET_NBR_OF_MEMS
c->data[1] = 0;
c->size = 2 + 1;
// resend message
send_message(msg);
}
}
}
else if (c->port == CRTP_PORT_PARAM) {
if (c->channel == 0) { // TOC Access
c->data[1] = 0; // Last parameter (id = 0)
memset(&c->data[2], 0, 10);
c->size = 1 + 8;
send_message(msg);
}
else if (c->channel == 1) { // Param read
// 0 is ok
c->data[1] = 0; // value
c->size = 1 + 2;
send_message(msg);
}
}
else if (c->port == CRTP_PORT_LINK) {
if (c->channel == 0) { // Echo
send_message(msg);
}
else if (c->channel == 1) { // Reply platform name
c->size = CRTP_MAX_DATA_SIZE;
bzero(c->data, CRTP_MAX_DATA_SIZE);
strcpy((char *)c->data, "Bitcraze PPRZ");
send_message(msg);
}
}
else {
// TODO handle error ?
}
}
/**
* Handle raw datalink
*
* From Bitcraze documentation:
*
* This packet carries the raw radio packet. The NRF51 acts as a radio bridge.
* Because the NRF51 does not have much memory and the STM32 is capable of bursting
* a lot of data a flow control rules has been made: The STM32 is allowed to send
* a RADIO_RAW packet only when one RADIO_RAW packet has been received.
*
* The NRF51 is regularly sending CRTP NULL packet or empty packets to the STM32
* to get the communication working both ways.
*
* Note: So far RADIO_RAW is the only syslink packet that has flow control constrain,
* all other packets can be sent full duplex at any moment.
*/
static void handle_raw(syslink_message_t *msg)
{
crtp_message_t *c = (crtp_message_t *) &msg->length;
if (CRTP_NULL(*c)) {
if (c->size >= 3) {
//handle_bootloader(sys);
}
}
else if (c->port == CRTP_PORT_COMMANDER) {
//crtp_commander *cmd = (crtp_commander *) &c->data[0];
// TODO set RC from cmd message
}
else if (c->port == CRTP_PORT_PPRZLINK) {
// fill rx buffer with CRTP data
uint8_t data_size = c->size;
uint16_t available = SYSLINK_RX_BUF_LEN - syslink.device.char_available(&syslink);
if (available > data_size) {
// enough room to add new bytes
if ((uint16_t)syslink.rx_insert_idx + (uint16_t)data_size < SYSLINK_RX_BUF_LEN) {
// copy in one block
memcpy(&syslink.rx_buf[syslink.rx_insert_idx], c->data, data_size);
} else {
// copy in two parts
uint16_t split = SYSLINK_RX_BUF_LEN - syslink.rx_insert_idx;
memcpy(&syslink.rx_buf[syslink.rx_insert_idx], c->data, split);
memcpy(&syslink.rx_buf[0], &c->data[split], data_size - split);
}
syslink.rx_insert_idx = (syslink.rx_insert_idx + data_size) % SYSLINK_RX_BUF_LEN;
}
}
else {
handle_raw_other(msg);
}
// send next raw message if fifo is not empty
if (syslink.tx_extract_idx != syslink.tx_insert_idx) {
PPRZ_MUTEX_LOCK(syslink_tx_mtx);
syslink_message_t msg_raw;
msg_raw.type = SYSLINK_RADIO_RAW;
memcpy(&msg_raw.length, &syslink.msg_tx[syslink.tx_extract_idx], sizeof(crtp_message_t));
send_message(&msg_raw);
// move fifo indexes
syslink.tx_extract_idx++;
if (syslink.tx_extract_idx == CRTP_BUF_LEN) {
syslink.tx_extract_idx = 0;
}
PPRZ_MUTEX_UNLOCK(syslink_tx_mtx);
}
}
static void handle_radio(syslink_message_t *msg)
{
if (msg->type == SYSLINK_RADIO_RSSI) {
uint8_t rssi = msg->data[0]; // Between 40 and 100 meaning -40 dBm to -100 dBm
syslink.rssi = 140 - rssi * 100 / (100 - 40);
}
else if (msg->type == SYSLINK_RADIO_CHANNEL) {
// ack radio channel
}
else if (msg->type == SYSLINK_RADIO_DATARATE) {
// ack radio datarate
}
else if (msg->type == SYSLINK_RADIO_ADDRESS) {
// ack radio address
}
}
/** New RX message
*/
static void handle_new_msg(syslink_message_t *msg)
{
if (msg->type == SYSLINK_PM_ONOFF_SWITCHOFF) {
// power button is hit
// don't do anything for now ?
}
else if (msg->type == SYSLINK_PM_BATTERY_STATE) {
handle_battery(msg);
}
else if (msg->type == SYSLINK_RADIO_RAW) {
handle_raw(msg);
}
else if ((msg->type & SYSLINK_GROUP) == SYSLINK_RADIO) {
handle_radio(msg);
}
else if ((msg->type & SYSLINK_GROUP) == SYSLINK_OW) {
// one-wire memory access
// don't do anything for now
}
else {
// handle errors ?
}
}
/**
* Implementation of syslink as generic device
*/
// check free space: nb of CRTP slots x space in a slot
static bool syslink_check_free_space(struct syslink_dl *s, long *fd UNUSED, uint16_t len)
{
int16_t slots = s->tx_extract_idx - s->tx_insert_idx;
if (slots <= 0) {
slots += CRTP_BUF_LEN;
}
uint16_t space = (uint16_t)(CRTP_MAX_DATA_SIZE * (slots - 1)) >= len;
if (space > 0) {
PPRZ_MUTEX_LOCK(syslink_tx_mtx);
}
return space;
}
// implementation of put_buffer, fill CRTP slots
static void syslink_put_buffer(struct syslink_dl *s, long fd UNUSED, const uint8_t *data, uint16_t len)
{
uint16_t buf_rem = len;
// fill slots until they are full
// we assume that the available space have been check before
while (buf_rem > 0) {
// get current slot
crtp_message_t *c = &s->msg_tx[s->tx_insert_idx];
if (c->size < CRTP_MAX_DATA_SIZE) {
// fill current buffer
uint16_t data_size = Min(buf_rem, CRTP_MAX_DATA_SIZE - c->size);
memcpy(&c->data[c->size - sizeof(c->header)], &data[len - buf_rem], data_size);
c->size += data_size;
buf_rem -= data_size;
}
else {
// start a new slot
uint8_t tmp = (s->tx_insert_idx + 1) % CRTP_BUF_LEN;
if (tmp == s->tx_extract_idx) {
// no more slots
// this should be be possible when check_free_space is called before
return;
}
crtp_message_t *c = &s->msg_tx[tmp];
uint16_t data_size = Min(buf_rem, CRTP_MAX_DATA_SIZE);
memcpy(c->data, &data[len - buf_rem], data_size);
c->size = sizeof(c->header) + data_size;
buf_rem -= data_size;
s->tx_insert_idx = tmp;
}
}
}
// implementation of put_byte using put_buffer
static void syslink_put_byte(struct syslink_dl *s, long fd, const uint8_t b)
{
syslink_put_buffer(s, fd, &b, 1);
}
// send_message is not needed as messages are stored in a fifo
static void syslink_send_message(struct syslink_dl *s UNUSED, long fd UNUSED)
{
PPRZ_MUTEX_UNLOCK(syslink_tx_mtx); // release mutex
}
static uint8_t syslink_getch(struct syslink_dl *s)
{
uint8_t ret = s->rx_buf[s->rx_extract_idx];
s->rx_extract_idx = (s->rx_extract_idx + 1) % SYSLINK_RX_BUF_LEN;
return ret;
}
static uint16_t syslink_char_available(struct syslink_dl *s)
{
int16_t available = s->rx_insert_idx - s->rx_extract_idx;
if (available < 0) {
available += SYSLINK_RX_BUF_LEN;
}
return (uint16_t)available;
}
/** Init function */
void syslink_dl_init(void)
{
syslink_parse_init(&syslink.state);
syslink.tx_insert_idx = 0;
syslink.tx_extract_idx = 0;
syslink.rssi = 0;
syslink.charging = false;
syslink.powered = false;
for (int i = 0; i < CRTP_BUF_LEN; i++) {
// prepare raw pprzlink datalink headers
syslink.msg_tx[i].header = 0;
syslink.msg_tx[i].port = CRTP_PORT_PPRZLINK;
syslink.msg_tx[i].channel = i % 4;
syslink.msg_tx[i].size = sizeof(syslink.msg_tx[i].header);
}
// generic device
syslink.device.periph = (void *)(&syslink);
syslink.device.check_free_space = (check_free_space_t) syslink_check_free_space;
syslink.device.put_byte = (put_byte_t) syslink_put_byte;
syslink.device.put_buffer = (put_buffer_t) syslink_put_buffer;
syslink.device.send_message = (send_message_t) syslink_send_message;
syslink.device.char_available = (char_available_t) syslink_char_available;
syslink.device.get_byte = (get_byte_t) syslink_getch;
// init mutex if needed
PPRZ_MUTEX_INIT(syslink_tx_mtx);
}
/** Periodic function */
void syslink_dl_periodic(void)
{
#ifdef CHARGING_LED
if (syslink.charging) {
LED_TOGGLE(CHARGING_LED);
}
else if (syslink.powered) {
LED_ON(CHARGING_LED);
}
else {
LED_OFF(CHARGING_LED);
}
#endif
}
/** Datalink event */
void syslink_dl_event(void)
{
while (uart_char_available(&(SYSLINK_DEV))) {
uint8_t ch = uart_getch(&(SYSLINK_DEV));
if (syslink_parse_char(&syslink.state, ch, &syslink.msg_rx)) {
handle_new_msg(&syslink.msg_rx);
}
}
}
@@ -0,0 +1,70 @@
/*
* Copyright (C) 2019 Gautier Hattenberger <gautier.hattenberger@enac.fr>
*
* This file is part of paparazzi.
*
* paparazzi 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 2, or (at your option)
* any later version.
*
* paparazzi 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 paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* @file modules/datalink/bitcraze/syslink_dl.h
*
* Syslink protocol handling and functionalities
*
*/
#ifndef SYSLINK_DL_H
#define SYSLINK_DL_H
#include "modules/datalink/bitcraze/syslink.h"
#include "modules/datalink/bitcraze/crtp.h"
#include "pprzlink/pprzlink_device.h"
#define CRTP_BUF_LEN 16
#define SYSLINK_RX_BUF_LEN 256
struct syslink_dl {
// syslink structures
syslink_parse_state state; ///< syslink parser state
syslink_message_t msg_rx; ///< last received syslink message
crtp_message_t msg_tx[CRTP_BUF_LEN]; ///< queued crtp packets to be send
uint8_t tx_insert_idx; ///< tx insert index
uint8_t tx_extract_idx; ///< tx extract index
uint8_t rx_buf[SYSLINK_RX_BUF_LEN]; ///< received pprzlink bytes from syslink/crtp
uint8_t rx_insert_idx; ///< rx insert index
uint8_t rx_extract_idx; ///< rx extract index
// generic device to use pprzlink over syslink
struct link_device device;
// crazyflie state
uint8_t rssi;
bool charging; ///< battery charging
bool powered; ///< USB powered
};
extern struct syslink_dl syslink;
/** Init function */
extern void syslink_dl_init(void);
/** Periodic function */
extern void syslink_dl_periodic(void);
/** Datalink event */
extern void syslink_dl_event(void);
#endif
+3
View File
@@ -35,6 +35,9 @@
#if USE_UDP
#include "mcu_periph/udp.h"
#endif
#if USE_SYSLINK
#include "modules/datalink/bitcraze/syslink_dl.h"
#endif
/** PPRZ transport structure */
extern struct pprz_transport pprz_tp;
+145
View File
@@ -0,0 +1,145 @@
/*
* Copyright (C) 2019 Gautier Hattenberger <gautier.hattenberger@enac.fr>
*
* This file is part of paparazzi.
*
* paparazzi 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 2, or (at your option)
* any later version.
*
* paparazzi 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 paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* @file subsystems/imu/imu_bmi088_i2c.c
*
* IMU driver for the BMI088 using I2C
*
*/
#include "subsystems/imu.h"
#include "mcu_periph/i2c.h"
#include "mcu_periph/sys_time.h"
#include "subsystems/abi.h"
PRINT_CONFIG_VAR(IMU_BMI088_GYRO_RANGE)
PRINT_CONFIG_VAR(IMU_BMI088_ACCEL_RANGE)
#ifndef IMU_BMI088_GYRO_ODR
#define IMU_BMI088_GYRO_ODR BMI088_GYRO_ODR_1000_BW_116
#endif
PRINT_CONFIG_VAR(IMU_BMI088_GYRO_ODR)
#ifndef IMU_BMI088_ACCEL_ODR
#define IMU_BMI088_ACCEL_ODR BMI088_ACCEL_ODR_1600
#endif
PRINT_CONFIG_VAR(IMU_BMI088_ACCEL_ODR)
#ifndef IMU_BMI088_ACCEL_BW
#define IMU_BMI088_ACCEL_BW BMI088_ACCEL_BW_OSR4
#endif
PRINT_CONFIG_VAR(IMU_BMI088_ACCEL_BW)
#ifndef IMU_BMI088_GYRO_I2C_ADDR
#define IMU_BMI088_GYRO_I2C_ADDR BMI088_GYRO_ADDR
#endif
PRINT_CONFIG_VAR(IMU_BMI088_GYRO_I2C_ADDR)
#ifndef IMU_BMI088_ACCEL_I2C_ADDR
#define IMU_BMI088_ACCEL_I2C_ADDR BMI088_ACCEL_ADDR
#endif
PRINT_CONFIG_VAR(IMU_BMI088_ACCEL_I2C_ADDR)
// Default channels order
#ifndef IMU_BMI088_CHAN_X
#define IMU_BMI088_CHAN_X 0
#endif
PRINT_CONFIG_VAR(IMU_BMI088_CHAN_X)
#ifndef IMU_BMI088_CHAN_Y
#define IMU_BMI088_CHAN_Y 1
#endif
PRINT_CONFIG_VAR(IMU_BMI088_CHAN_Y)
#ifndef IMU_BMI088_CHAN_Z
#define IMU_BMI088_CHAN_Z 2
#endif
PRINT_CONFIG_VAR(IMU_BMI088_CHAN_Z)
#ifndef IMU_BMI088_X_SIGN
#define IMU_BMI088_X_SIGN 1
#endif
PRINT_CONFIG_VAR(IMU_BMI088_X_SIGN)
#ifndef IMU_BMI088_Y_SIGN
#define IMU_BMI088_Y_SIGN 1
#endif
PRINT_CONFIG_VAR(IMU_BMI088_Y_SIGN)
#ifndef IMU_BMI088_Z_SIGN
#define IMU_BMI088_Z_SIGN 1
#endif
PRINT_CONFIG_VAR(IMU_BMI088_Z_SIGN)
struct ImuBmi088 imu_bmi088;
void imu_bmi088_init(void)
{
/* BMI088 */
bmi088_i2c_init(&imu_bmi088.bmi, &(IMU_BMI088_I2C_DEV), IMU_BMI088_GYRO_I2C_ADDR, IMU_BMI088_ACCEL_I2C_ADDR);
// change the default configuration
imu_bmi088.bmi.config.gyro_range = IMU_BMI088_GYRO_RANGE;
imu_bmi088.bmi.config.gyro_odr = IMU_BMI088_GYRO_ODR;
imu_bmi088.bmi.config.accel_range = IMU_BMI088_ACCEL_RANGE;
imu_bmi088.bmi.config.accel_odr = IMU_BMI088_ACCEL_ODR;
imu_bmi088.bmi.config.accel_bw = IMU_BMI088_ACCEL_BW;
}
void imu_bmi088_periodic(void)
{
bmi088_i2c_periodic(&imu_bmi088.bmi);
}
void imu_bmi088_event(void)
{
uint32_t now_ts = get_sys_time_usec();
// If the BMI088 I2C transaction has succeeded: convert the data
bmi088_i2c_event(&imu_bmi088.bmi);
if (imu_bmi088.bmi.gyro_available) {
struct Int32Rates rates = {
IMU_BMI088_X_SIGN *(int32_t)(imu_bmi088.bmi.data_rates.value[IMU_BMI088_CHAN_X]),
IMU_BMI088_Y_SIGN *(int32_t)(imu_bmi088.bmi.data_rates.value[IMU_BMI088_CHAN_Y]),
IMU_BMI088_Z_SIGN *(int32_t)(imu_bmi088.bmi.data_rates.value[IMU_BMI088_CHAN_Z])
};
// unscaled vector
RATES_COPY(imu.gyro_unscaled, rates);
imu_bmi088.bmi.gyro_available = false;
imu_scale_gyro(&imu);
AbiSendMsgIMU_GYRO_INT32(IMU_BMI088_ID, now_ts, &imu.gyro);
}
if (imu_bmi088.bmi.accel_available) {
// set channel order
struct Int32Vect3 accel = {
IMU_BMI088_X_SIGN *(int32_t)(imu_bmi088.bmi.data_accel.value[IMU_BMI088_CHAN_X]),
IMU_BMI088_Y_SIGN *(int32_t)(imu_bmi088.bmi.data_accel.value[IMU_BMI088_CHAN_Y]),
IMU_BMI088_Z_SIGN *(int32_t)(imu_bmi088.bmi.data_accel.value[IMU_BMI088_CHAN_Z])
};
// unscaled vector
VECT3_COPY(imu.accel_unscaled, accel);
imu_bmi088.bmi.accel_available = false;
imu_scale_accel(&imu);
AbiSendMsgIMU_ACCEL_INT32(IMU_BMI088_ID, now_ts, &imu.accel);
}
}
+83
View File
@@ -0,0 +1,83 @@
/*
* Copyright (C) 2019 Gautier Hattenberger <gautier.hattenberger@enac.fr>
*
* This file is part of paparazzi.
*
* paparazzi 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 2, or (at your option)
* any later version.
*
* paparazzi 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 paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* @file subsystems/imu/imu_bmi088_i2c.h
*
* IMU driver for the BMI088 using I2C
*
*/
#ifndef IMU_BMI088_I2C_H
#define IMU_BMI088_I2C_H
#include "std.h"
#include "generated/airframe.h"
#include "subsystems/imu.h"
#include "peripherals/bmi088_i2c.h"
#ifndef IMU_BMI088_GYRO_RANGE
#define IMU_BMI088_GYRO_RANGE BMI088_GYRO_RANGE_1000
#endif
#ifndef IMU_BMI088_ACCEL_RANGE
#define IMU_BMI088_ACCEL_RANGE BMI088_ACCEL_RANGE_6G
#endif
// Set default sensitivity based on range if needed
#if !defined IMU_GYRO_P_SENS & !defined IMU_GYRO_Q_SENS & !defined IMU_GYRO_R_SENS
#define IMU_GYRO_P_SENS BMI088_GYRO_SENS[IMU_BMI088_GYRO_RANGE]
#define IMU_GYRO_P_SENS_NUM BMI088_GYRO_SENS_FRAC[IMU_BMI088_GYRO_RANGE][0]
#define IMU_GYRO_P_SENS_DEN BMI088_GYRO_SENS_FRAC[IMU_BMI088_GYRO_RANGE][1]
#define IMU_GYRO_Q_SENS BMI088_GYRO_SENS[IMU_BMI088_GYRO_RANGE]
#define IMU_GYRO_Q_SENS_NUM BMI088_GYRO_SENS_FRAC[IMU_BMI088_GYRO_RANGE][0]
#define IMU_GYRO_Q_SENS_DEN BMI088_GYRO_SENS_FRAC[IMU_BMI088_GYRO_RANGE][1]
#define IMU_GYRO_R_SENS BMI088_GYRO_SENS[IMU_BMI088_GYRO_RANGE]
#define IMU_GYRO_R_SENS_NUM BMI088_GYRO_SENS_FRAC[IMU_BMI088_GYRO_RANGE][0]
#define IMU_GYRO_R_SENS_DEN BMI088_GYRO_SENS_FRAC[IMU_BMI088_GYRO_RANGE][1]
#endif
// Set default sensitivity based on range if needed
#if !defined IMU_ACCEL_X_SENS & !defined IMU_ACCEL_Y_SENS & !defined IMU_ACCEL_Z_SENS
#define IMU_ACCEL_X_SENS BMI088_ACCEL_SENS[IMU_BMI088_ACCEL_RANGE]
#define IMU_ACCEL_X_SENS_NUM BMI088_ACCEL_SENS_FRAC[IMU_BMI088_ACCEL_RANGE][0]
#define IMU_ACCEL_X_SENS_DEN BMI088_ACCEL_SENS_FRAC[IMU_BMI088_ACCEL_RANGE][1]
#define IMU_ACCEL_Y_SENS BMI088_ACCEL_SENS[IMU_BMI088_ACCEL_RANGE]
#define IMU_ACCEL_Y_SENS_NUM BMI088_ACCEL_SENS_FRAC[IMU_BMI088_ACCEL_RANGE][0]
#define IMU_ACCEL_Y_SENS_DEN BMI088_ACCEL_SENS_FRAC[IMU_BMI088_ACCEL_RANGE][1]
#define IMU_ACCEL_Z_SENS BMI088_ACCEL_SENS[IMU_BMI088_ACCEL_RANGE]
#define IMU_ACCEL_Z_SENS_NUM BMI088_ACCEL_SENS_FRAC[IMU_BMI088_ACCEL_RANGE][0]
#define IMU_ACCEL_Z_SENS_DEN BMI088_ACCEL_SENS_FRAC[IMU_BMI088_ACCEL_RANGE][1]
#endif
struct ImuBmi088 {
struct Bmi088_I2c bmi;
};
extern struct ImuBmi088 imu_bmi088;
extern void imu_bmi088_init(void);
extern void imu_bmi088_periodic(void);
extern void imu_bmi088_event(void);
#endif /* IMU_BMI088_I2C_H */
+115
View File
@@ -0,0 +1,115 @@
/*
* Copyright (C) 2019 Gautier Hattenberger <gautier.hattenberger@enac.fr>
*
* This file is part of paparazzi.
*
* paparazzi 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 2, or (at your option)
* any later version.
*
* paparazzi 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 paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* @file peripherals/bmi088.c
*
* BMI088 driver common functions (I2C and SPI).
*
* Still needs the either I2C or SPI specific implementation.
*/
#include "peripherals/bmi088.h"
const float BMI088_GYRO_SENS[5] = {
BMI088_GYRO_SENS_2000,
BMI088_GYRO_SENS_1000,
BMI088_GYRO_SENS_500,
BMI088_GYRO_SENS_250,
BMI088_GYRO_SENS_125,
};
const int32_t BMI088_GYRO_SENS_FRAC[5][2] = {
{ BMI088_GYRO_SENS_2000_NUM, BMI088_GYRO_SENS_2000_DEN },
{ BMI088_GYRO_SENS_1000_NUM, BMI088_GYRO_SENS_1000_DEN },
{ BMI088_GYRO_SENS_500_NUM, BMI088_GYRO_SENS_500_DEN },
{ BMI088_GYRO_SENS_250_NUM, BMI088_GYRO_SENS_250_DEN },
{ BMI088_GYRO_SENS_125_NUM, BMI088_GYRO_SENS_125_DEN },
};
const float BMI088_ACCEL_SENS[4] = {
BMI088_ACCEL_SENS_3G,
BMI088_ACCEL_SENS_6G,
BMI088_ACCEL_SENS_12G,
BMI088_ACCEL_SENS_24G
};
const int32_t BMI088_ACCEL_SENS_FRAC[4][2] = {
{ BMI088_ACCEL_SENS_3G_NUM, BMI088_ACCEL_SENS_3G_DEN },
{ BMI088_ACCEL_SENS_6G_NUM, BMI088_ACCEL_SENS_6G_DEN },
{ BMI088_ACCEL_SENS_12G_NUM, BMI088_ACCEL_SENS_12G_DEN },
{ BMI088_ACCEL_SENS_24G_NUM, BMI088_ACCEL_SENS_24G_DEN }
};
void bmi088_set_default_config(struct Bmi088Config *c)
{
c->gyro_range = BMI088_DEFAULT_GYRO_RANGE;
c->gyro_odr = BMI088_DEFAULT_GYRO_ODR;
c->accel_range = BMI088_DEFAULT_ACCEL_RANGE;
c->accel_odr = BMI088_DEFAULT_ACCEL_ODR;
c->accel_bw = BMI088_DEFAULT_ACCEL_BW;
}
void bmi088_send_config(Bmi088ConfigSet bmi_set, void *bmi, struct Bmi088Config *config)
{
switch (config->init_status) {
case BMI088_CONF_ACCEL_RANGE:
/* configure accelerometer range */
bmi_set(bmi, BMI088_ACCEL_RANGE, config->accel_range, BMI088_CONFIG_ACCEL);
config->init_status++;
break;
case BMI088_CONF_ACCEL_ODR:
/* configure accelerometer odr and bw */
bmi_set(bmi, BMI088_ACCEL_CONF, ((config->accel_bw << 4) | config->accel_odr), BMI088_CONFIG_ACCEL);
config->init_status++;
break;
case BMI088_CONF_ACCEL_PWR_CONF:
/* switch on accel */
bmi_set(bmi, BMI088_ACCEL_PWR_CONF, BMI088_ACCEL_ACTIVE, BMI088_CONFIG_ACCEL);
config->init_status++;
break;
case BMI088_CONF_ACCEL_PWR_CTRL:
/* switch on accel */
bmi_set(bmi, BMI088_ACCEL_PWR_CTRl, BMI088_ACCEL_POWER_ON, BMI088_CONFIG_ACCEL);
config->init_status++;
break;
case BMI088_CONF_GYRO_RANGE:
/* configure gyro range */
bmi_set(bmi, BMI088_GYRO_RANGE, config->gyro_range, BMI088_CONFIG_GYRO);
config->init_status++;
break;
case BMI088_CONF_GYRO_ODR:
/* configure gyro odr */
bmi_set(bmi, BMI088_GYRO_BAND_WIDTH, config->gyro_odr, BMI088_CONFIG_GYRO);
config->init_status++;
break;
case BMI088_CONF_GYRO_PWR:
/* switch on gyro */
bmi_set(bmi, BMI088_GYRO_LPM_1, BMI088_GYRO_NORMAL, BMI088_CONFIG_GYRO);
config->init_status++;
break;
case BMI088_CONF_DONE:
config->initialized = true;
break;
default:
break;
}
}
+128
View File
@@ -0,0 +1,128 @@
/*
* Copyright (C) 2019 Gautier Hattenberger <gautier.hattenberger@enac.fr>
*
* This file is part of paparazzi.
*
* paparazzi 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 2, or (at your option)
* any later version.
*
* paparazzi 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 paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* @file peripherals/bmi088.h
*
* BMI088 driver common interface (I2C and SPI).
*/
#ifndef BMI088_H
#define BMI088_H
#include "std.h"
/* Include address and register definition */
#include "peripherals/bmi088_regs.h"
/// Default gyro full scale range +- 1000°/s
#define BMI088_DEFAULT_GYRO_RANGE BMI088_GYRO_RANGE_1000
/// Default gyro output rate
#define BMI088_DEFAULT_GYRO_ODR BMI088_GYRO_ODR_400_BW_47
/// Default accel full scale range +- 6g
#define BMI088_DEFAULT_ACCEL_RANGE BMI088_ACCEL_RANGE_6G
/// Default accel output rate
#define BMI088_DEFAULT_ACCEL_ODR BMI088_ACCEL_ODR_400
/// Default accel bandwidth
#define BMI088_DEFAULT_ACCEL_BW BMI088_ACCEL_BW_NORMAL
/** default gyro sensitivy from the datasheet
* sens = 1/ [LSB/(deg/s)] * pi/180 * 2^INT32_RATE_FRAC
* ex: BMI with 1000 deg/s has 32.8 LSB/(deg/s)
* sens = 1/32.8 * pi/180 * 4096 = 2.17953
*/
#define BMI088_GYRO_SENS_125 0.272442 // FIXME
#define BMI088_GYRO_SENS_125_NUM 19327
#define BMI088_GYRO_SENS_125_DEN 17735
#define BMI088_GYRO_SENS_250 0.544883
#define BMI088_GYRO_SENS_250_NUM 19327
#define BMI088_GYRO_SENS_250_DEN 35470
#define BMI088_GYRO_SENS_500 1.08977
#define BMI088_GYRO_SENS_500_NUM 57663
#define BMI088_GYRO_SENS_500_DEN 52913
#define BMI088_GYRO_SENS_1000 2.17953
#define BMI088_GYRO_SENS_1000_NUM 18271
#define BMI088_GYRO_SENS_1000_DEN 8383
#define BMI088_GYRO_SENS_2000 4.35906
#define BMI088_GYRO_SENS_2000_NUM 36542
#define BMI088_GYRO_SENS_2000_DEN 8383
// Get default sensitivity from a table
extern const float BMI088_GYRO_SENS[5];
// Get default sensitivity numerator and denominator from a table
extern const int32_t BMI088_GYRO_SENS_FRAC[5][2];
/** default accel sensitivy from the datasheet
* sens = 9.81 [m/s^2] / [LSB/g] * 2^INT32_ACCEL_FRAC
* ex: BMI with 8g has 4096 LSB/g
* sens = 9.81 [m/s^2] / 4096 [LSB/g] * 2^INT32_ACCEL_FRAC = 2.4525
*/
// FIXME
#define BMI088_ACCEL_SENS_3G 0.919687
#define BMI088_ACCEL_SENS_3G_NUM 9197
#define BMI088_ACCEL_SENS_3G_DEN 10000
#define BMI088_ACCEL_SENS_6G 1.83937
#define BMI088_ACCEL_SENS_6G_NUM 18394
#define BMI088_ACCEL_SENS_6G_DEN 10000
#define BMI088_ACCEL_SENS_12G 3.67875
#define BMI088_ACCEL_SENS_12G_NUM 36787
#define BMI088_ACCEL_SENS_12G_DEN 10000
#define BMI088_ACCEL_SENS_24G 7.3575
#define BMI088_ACCEL_SENS_24G_NUM 7357
#define BMI088_ACCEL_SENS_24G_DEN 1000
// Get default sensitivity from a table
extern const float BMI088_ACCEL_SENS[4];
// Get default sensitivity numerator and denominator from a table
extern const int32_t BMI088_ACCEL_SENS_FRAC[4][2];
enum Bmi088ConfStatus {
BMI088_CONF_UNINIT,
BMI088_CONF_ACCEL_RANGE,
BMI088_CONF_ACCEL_ODR,
BMI088_CONF_ACCEL_PWR_CONF,
BMI088_CONF_ACCEL_PWR_CTRL,
BMI088_CONF_GYRO_RANGE,
BMI088_CONF_GYRO_ODR,
BMI088_CONF_GYRO_PWR,
BMI088_CONF_DONE
};
#define BMI088_CONFIG_ACCEL 0
#define BMI088_CONFIG_GYRO 1
/// Configuration function prototype
typedef void (*Bmi088ConfigSet)(void *bmi, uint8_t _reg, uint8_t _val, uint8_t _type);
struct Bmi088Config {
enum Bmi088GyroRanges gyro_range; ///< deg/s Range
enum Bmi088GyroODR gyro_odr; ///< output data rate
enum Bmi088AccelRanges accel_range; ///< g Range
enum Bmi088AccelODR accel_odr; ///< output data rate
enum Bmi088AccelBW accel_bw; ///< bandwidth
enum Bmi088ConfStatus init_status; ///< init status
bool initialized; ///< config done flag
};
extern void bmi088_set_default_config(struct Bmi088Config *c);
/// Configuration sequence called once before normal use
extern void bmi088_send_config(Bmi088ConfigSet bmi_set, void *bmi, struct Bmi088Config *config);
#endif // BMI088_H
+158
View File
@@ -0,0 +1,158 @@
/*
* Copyright (C) 2019 Gautier Hattenberger <gautier.hattenberger@enac.fr>
*
* This file is part of paparazzi.
*
* paparazzi 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 2, or (at your option)
* any later version.
*
* paparazzi 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 paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* @file peripherals/bmi088_i2c.c
*
* Driver for the BMI088 using I2C.
*
*/
#include "peripherals/bmi088_i2c.h"
void bmi088_i2c_init(struct Bmi088_I2c *bmi, struct i2c_periph *i2c_p, uint8_t gyro_addr, uint8_t accel_addr)
{
/* set i2c_peripheral */
bmi->i2c_p = i2c_p;
/* slave address */
bmi->gyro_trans.slave_addr = gyro_addr;
bmi->accel_trans.slave_addr = accel_addr;
/* set inital status: Success or Done */
bmi->gyro_trans.status = I2CTransDone;
bmi->accel_trans.status = I2CTransDone;
/* set default BMI088 config options */
bmi088_set_default_config(&(bmi->config));
bmi->gyro_available = false;
bmi->accel_available = false;
bmi->config.initialized = false;
bmi->config.init_status = BMI088_CONF_UNINIT;
}
static void bmi088_i2c_write_to_reg(void *bmi, uint8_t _reg, uint8_t _val, uint8_t _type)
{
struct Bmi088_I2c *bmi_i2c = (struct Bmi088_I2c *)(bmi);
if (_type == BMI088_CONFIG_ACCEL) {
bmi_i2c->accel_trans.buf[0] = _reg;
bmi_i2c->accel_trans.buf[1] = _val;
i2c_transmit(bmi_i2c->i2c_p, &(bmi_i2c->accel_trans), bmi_i2c->accel_trans.slave_addr, 2);
} else if (_type == BMI088_CONFIG_GYRO) {
bmi_i2c->gyro_trans.buf[0] = _reg;
bmi_i2c->gyro_trans.buf[1] = _val;
i2c_transmit(bmi_i2c->i2c_p, &(bmi_i2c->gyro_trans), bmi_i2c->gyro_trans.slave_addr, 2);
}
}
// Configuration function called once before normal use
void bmi088_i2c_start_configure(struct Bmi088_I2c *bmi)
{
if (bmi->config.init_status == BMI088_CONF_UNINIT) {
bmi->config.init_status++;
if (bmi->accel_trans.status == I2CTransSuccess || bmi->accel_trans.status == I2CTransDone) {
bmi088_send_config(bmi088_i2c_write_to_reg, (void *)bmi, &(bmi->config));
}
}
}
void bmi088_i2c_read(struct Bmi088_I2c *bmi)
{
if (bmi->config.initialized &&
bmi->gyro_trans.status == I2CTransDone &&
bmi->accel_trans.status == I2CTransDone) {
/* read gyro */
bmi->gyro_trans.buf[0] = BMI088_GYRO_RATE_X_LSB;
i2c_transceive(bmi->i2c_p, &(bmi->gyro_trans), bmi->gyro_trans.slave_addr, 1, 6); //9);
/* read accel */
bmi->accel_trans.buf[0] = BMI088_ACCEL_X_LSB;
i2c_transceive(bmi->i2c_p, &(bmi->accel_trans), bmi->accel_trans.slave_addr, 1, 6); // 12);
}
}
#define Int16FromBuf(_buf,_idx) ((int16_t)((_buf[_idx+1]<<8) | _buf[_idx]))
void bmi088_i2c_event(struct Bmi088_I2c *bmi)
{
if (bmi->config.initialized) {
// Check gyro read
if (bmi->gyro_trans.status == I2CTransFailed) {
bmi->gyro_trans.status = I2CTransDone;
} else if (bmi->gyro_trans.status == I2CTransSuccess) {
// Successfull reading
//if (bit_is_set(bmi->gyro_trans.buf[8], 7)) {
// new data
bmi->data_rates.rates.p = Int16FromBuf(bmi->gyro_trans.buf, 0);
bmi->data_rates.rates.q = Int16FromBuf(bmi->gyro_trans.buf, 2);
bmi->data_rates.rates.r = Int16FromBuf(bmi->gyro_trans.buf, 4);
bmi->gyro_available = true;
//}
bmi->gyro_trans.status = I2CTransDone;
}
// Check accel read
if (bmi->accel_trans.status == I2CTransFailed) {
bmi->accel_trans.status = I2CTransDone;
} else if (bmi->accel_trans.status == I2CTransSuccess) {
// Successfull reading
//if (bit_is_set(bmi->accel_trans.buf[11], 7)) {
// new data
bmi->data_accel.vect.x = Int16FromBuf(bmi->accel_trans.buf, 0);
bmi->data_accel.vect.y = Int16FromBuf(bmi->accel_trans.buf, 2);
bmi->data_accel.vect.z = Int16FromBuf(bmi->accel_trans.buf, 4);
bmi->accel_available = true;
//}
bmi->accel_trans.status = I2CTransDone;
}
} else if (bmi->config.init_status != BMI088_CONF_UNINIT) { // Configuring but not yet initialized
if (bmi->config.init_status <= BMI088_CONF_ACCEL_PWR_CTRL) {
// Accel config not finished
switch (bmi->accel_trans.status) {
case I2CTransFailed:
bmi->config.init_status--; // Retry config (TODO max retry)
/* Falls through. */
case I2CTransSuccess:
case I2CTransDone:
bmi088_send_config(bmi088_i2c_write_to_reg, (void *)bmi, &(bmi->config));
break;
default:
break;
}
}
else {
// gyro config not finished
switch (bmi->gyro_trans.status) {
case I2CTransFailed:
bmi->config.init_status--; // Retry config (TODO max retry)
/* Falls through. */
case I2CTransSuccess:
case I2CTransDone:
bmi088_send_config(bmi088_i2c_write_to_reg, (void *)bmi, &(bmi->config));
if (bmi->config.initialized) {
bmi->gyro_trans.status = I2CTransDone;
}
break;
default:
break;
}
}
}
}
+70
View File
@@ -0,0 +1,70 @@
/*
* Copyright (C) 2019 Gautier Hattenberger <gautier.hattenberger@enac.fr>
*
* This file is part of paparazzi.
*
* paparazzi 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 2, or (at your option)
* any later version.
*
* paparazzi 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 paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* @file peripherals/bmi088_i2c.h
*
* Driver for the BMI088 using I2C.
*/
#ifndef BMI088_I2C_H
#define BMI088_I2C_H
#include "std.h"
#include "math/pprz_algebra_int.h"
#include "mcu_periph/i2c.h"
/* Include common BMI088 options and definitions */
#include "peripherals/bmi088.h"
struct Bmi088_I2c {
struct i2c_periph *i2c_p;
struct i2c_transaction gyro_trans; ///< i2c transaction for gyro
struct i2c_transaction accel_trans; ///< i2c transaction for accel
volatile bool gyro_available; ///< gyro data ready flag
volatile bool accel_available; ///< accel data ready flag
union {
struct Int16Vect3 vect; ///< accel data vector in accel coordinate system
int16_t value[3]; ///< accel data values accessible by channel index
} data_accel;
union {
struct Int16Rates rates; ///< rates data as angular rates in gyro coordinate system
int16_t value[3]; ///< rates data values accessible by channel index
} data_rates;
struct Bmi088Config config;
};
// Functions
extern void bmi088_i2c_init(struct Bmi088_I2c *bmi, struct i2c_periph *i2c_p, uint8_t gyro_addr, uint8_t accel_addr);
extern void bmi088_i2c_start_configure(struct Bmi088_I2c *bmi);
extern void bmi088_i2c_read(struct Bmi088_I2c *bmi);
extern void bmi088_i2c_event(struct Bmi088_I2c *bmi);
/// convenience function: read or start configuration if not already initialized
static inline void bmi088_i2c_periodic(struct Bmi088_I2c *bmi)
{
if (bmi->config.initialized) {
bmi088_i2c_read(bmi);
} else {
bmi088_i2c_start_configure(bmi);
}
}
#endif // BMI088_I2C_H
+180
View File
@@ -0,0 +1,180 @@
/*
* Copyright (C) 2019 Gautier Hattenberger <gaurier.hattenberger@enac.fr>
*
* This file is part of paparazzi.
*
* paparazzi 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 2, or (at your option)
* any later version.
*
* paparazzi 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 paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* @file peripherals/bmi088_regs.h
*
* Register and address definitions for BMI088.
*/
#ifndef BMI088_REGS_H
#define BMI088_REGS_H
/* default I2C address */
#define BMI088_ACCEL_ADDR (0x18<<1)
#define BMI088_ACCEL_ADDR_ALT (0x19<<1)
#define BMI088_ACCEL_CHIP_ID 0x00 // Default value 0x1E
#define BMI088_ACCEL_ERR_REG 0x02
#define BMI088_ACCEL_STATUS 0x03
#define BMI088_ACCEL_X_LSB 0x12
#define BMI088_ACCEL_X_MSB 0x13
#define BMI088_ACCEL_Y_LSB 0x14
#define BMI088_ACCEL_Y_MSB 0x15
#define BMI088_ACCEL_Z_LSB 0x16
#define BMI088_ACCEL_Z_MSB 0x17
#define BMI088_ACCEL_SENSOR_TIME_0 0x18
#define BMI088_ACCEL_SENSOR_TIME_1 0x19
#define BMI088_ACCEL_SENSOR_TIME_2 0x1A
#define BMI088_ACCEL_INT_STAT_1 0x1D
#define BMI088_ACCEL_TEMP_MSB 0x22
#define BMI088_ACCEL_TEMP_LSB 0x23
#define BMI088_ACCEL_CONF 0x40
#define BMI088_ACCEL_RANGE 0x41
#define BMI088_ACCEL_INT1_IO_CTRL 0x53
#define BMI088_ACCEL_INT2_IO_CTRL 0x54
#define BMI088_ACCEL_INT_MAP_DATA 0x58
#define BMI088_ACCEL_SELF_TEST 0x6D
#define BMI088_ACCEL_PWR_CONF 0x7C
#define BMI088_ACCEL_PWR_CTRl 0x7D
#define BMI088_ACCEL_SOFT_RESET 0x7E
#define BMI088_GYRO_ADDR (0x68<<1)
#define BMI088_GYRO_ADDR_ALT (0x69<<1)
#define BMI088_GYRO_CHIP_ID 0x00 // Default value 0x0F
#define BMI088_GYRO_RATE_X_LSB 0x02
#define BMI088_GYRO_RATE_X_MSB 0x03
#define BMI088_GYRO_RATE_Y_LSB 0x04
#define BMI088_GYRO_RATE_Y_MSB 0x05
#define BMI088_GYRO_RATE_Z_LSB 0x06
#define BMI088_GYRO_RATE_Z_MSB 0x07
#define BMI088_GYRO_INT_STAT_1 0x0A
#define BMI088_GYRO_RANGE 0x0F
#define BMI088_GYRO_BAND_WIDTH 0x10
#define BMI088_GYRO_LPM_1 0x11
#define BMI088_GYRO_SOFT_RESET 0x14
#define BMI088_GYRO_INT_CTRL 0x15
#define BMI088_GYRO_INT3_INT4_IO_CONF 0x16
#define BMI088_GYRO_INT3_INT4_IO_MAP 0x18
#define BMI088_GYRO_SELF_TEST 0x3C
/** Accel output range
*/
enum Bmi088AccelRanges
{
BMI088_ACCEL_RANGE_3G = 0x00,
BMI088_ACCEL_RANGE_6G = 0x01,
BMI088_ACCEL_RANGE_12G = 0x02,
BMI088_ACCEL_RANGE_24G = 0x03,
};
/** Accel outpur data rate
*/
enum Bmi088AccelODR
{
BMI088_ACCEL_ODR_12 = 0x05,
BMI088_ACCEL_ODR_25 = 0x06,
BMI088_ACCEL_ODR_50 = 0x07,
BMI088_ACCEL_ODR_100 = 0x08,
BMI088_ACCEL_ODR_200 = 0x09,
BMI088_ACCEL_ODR_400 = 0x0A,
BMI088_ACCEL_ODR_800 = 0x0B,
BMI088_ACCEL_ODR_1600 = 0x0C,
};
/** Accel bandwith
*/
enum Bmi088AccelBW
{
BMI088_ACCEL_BW_OSR4 = 0x08,
BMI088_ACCEL_BW_OSR2 = 0x09,
BMI088_ACCEL_BW_NORMAL = 0x0A,
};
/** Accel power type
*/
enum Bmi088AccelPowerType
{
BMI088_ACCEL_ACTIVE = 0x00,
BMI088_ACCEL_SUSPEND = 0x03,
};
/** Accel power control
*/
enum Bmi088AccelPowerCtrl
{
BMI088_ACCEL_POWER_OFF = 0x00,
BMI088_ACCEL_POWER_ON = 0x04,
};
/** Gyro output range
*/
enum Bmi088GyroRanges
{
BMI088_GYRO_RANGE_2000 = 0x00,
BMI088_GYRO_RANGE_1000 = 0x01,
BMI088_GYRO_RANGE_500 = 0x02,
BMI088_GYRO_RANGE_250 = 0x03,
BMI088_GYRO_RANGE_125 = 0x04,
};
/** Gyro output data rate and bandwidth
*/
enum Bmi088GyroODR
{
BMI088_GYRO_ODR_2000_BW_532 = 0x00,
BMI088_GYRO_ODR_2000_BW_230 = 0x01,
BMI088_GYRO_ODR_1000_BW_116 = 0x02,
BMI088_GYRO_ODR_400_BW_47 = 0x03,
BMI088_GYRO_ODR_200_BW_23 = 0x04,
BMI088_GYRO_ODR_100_BW_12 = 0x05,
BMI088_GYRO_ODR_200_BW_64 = 0x06,
BMI088_GYRO_ODR_100_BW_32 = 0x07,
};
/** Gyro power type
*/
enum Bmi088GyroPowerType
{
BMI088_GYRO_NORMAL = 0x00,
BMI088_GYRO_SUSPEND = 0x80,
BMI088_GYRO_DEEP_SUSPEND = 0x20,
};
#endif /* BMI088_REGS_H */
+4
View File
@@ -323,6 +323,10 @@
#define IMU_VECTORNAV_ID 18
#endif
#ifndef IMU_BMI088_ID
#define IMU_BMI088_ID 19
#endif
// prefiltering with OneEuro filter
#ifndef IMU_F1E_ID
#define IMU_F1E_ID 30
+1
View File
@@ -42,6 +42,7 @@
#define AHRS_COMP_ID_CHIMU 10
#define AHRS_COMP_ID_VECTORNAV 11
#define AHRS_COMP_ID_EKF2 12
#define AHRS_COMP_ID_MADGWICK 13
/* include actual (primary) implementation header */
#ifdef AHRS_TYPE_H
+172
View File
@@ -0,0 +1,172 @@
#!/usr/bin/env python3
"""
Bridge a Crazyflie connected to a Crazyradio to the Ivy software bus
with support of PPRZLINK messages
Requires 'pip3 install cflib'
As the ESB protocol works using PTX and PRX (Primary Transmitter/Reciever)
modes. Thus, data is only recieved as a response to a sent packet.
So, we need to constantly poll the receivers for bidirectional communication.
@author: Dennis Shtatnov (densht@gmail.com)
Gautier Hattenberger for Paparazzi UAV support
"""
# import struct
from os import path, getenv
import logging
import sys
import time
from cflib.crtp.crtpstack import CRTPPacket
from cflib.crtp import RadioDriver
# if PAPARAZZI_HOME not set, then assume the tree containing this
# file is a reasonable substitute
PPRZ_HOME = getenv("PAPARAZZI_HOME", path.normpath(path.join(path.dirname(path.abspath(__file__)), '../../../../')))
sys.path.append(PPRZ_HOME + "/var/lib/python")
from pprzlink.ivy import IvyMessagesInterface
from pprzlink.pprz_transport import PprzTransport
from pprzlink.message import PprzMessage
import pprzlink.messages_xml_map as messages_xml_map
CRTP_PORT_PPRZLINK = 9
# Only output errors from the logging framework
#logging.basicConfig(level=logging.DEBUG)
logging.basicConfig(level=logging.ERROR)
class RadioBridge:
def __init__(self, link_uri, msg_class='telemetry', verbose=False):
""" Initialize and run with the specified link_uri """
self.verbose = verbose
# Ivy interface and stream parser
self._ivy = IvyMessagesInterface("cf2ivy")
self._transport = PprzTransport(msg_class)
# Create a Crazyradio
self._driver = RadioDriver()
self._driver.connect(link_uri, self._link_quality_cb, self._link_error_cb)
if self.verbose:
print('Connecting to %s' % link_uri)
# Variable used to keep main loop occupied until disconnect
self.is_connected = True
# Bind to all messages from ac_id
def _forward_to_cf(ac_id, msg):
try:
data = self._transport.pack_pprz_msg(0, msg) # sender_id 0 = GCS
for i in range(0, len(data), 30):
pk = CRTPPacket()
pk.port = CRTP_PORT_PPRZLINK
pk.data = data[i:(i+30)]
self._driver.send_packet(pk)
if self.verbose:
print('Forward message', msg.name)
except:
if self.verbose:
print('Forward error for', ac_id)
messages_datalink = messages_xml_map.get_msgs("datalink")
for msg in messages_datalink:
self._ivy.subscribe(_forward_to_cf, PprzMessage("datalink", msg))
def shutdown(self):
if self.verbose:
print('closing cf2ivy interfaces')
self._ivy.shutdown()
self._driver.close()
def run(self):
pk = self._driver.receive_packet(0.1) # wait for next message with timeout
if pk is not None:
self._got_packet(pk)
def _got_packet(self, pk):
if pk.port == CRTP_PORT_PPRZLINK:
for c in pk.data:
if self._transport.parse_byte(bytes([c])):
(sender_id, _, _, msg) = self._transport.unpack()
if self.verbose:
print("Got message {} from {}".format(msg.name, sender_id))
# Forward message to Ivy bus
if self.is_connected:
self._ivy.send(msg, sender_id=sender_id)
def _link_quality_cb(self, quality):
pass
def _link_error_cb(self, msg):
if self.verbose:
print("Link error: {}".format(msg))
if __name__ == '__main__':
from argparse import ArgumentParser
parser = ArgumentParser(description="Crazyradio link for paparazzi")
parser.add_argument('-a','--address', default=None, help="URI address of Crazyflie")
parser.add_argument('-c','--chanel', default='80', help="URI chanel of Crazyflie (full URI will be 'radio://0/%(default)/2M'")
parser.add_argument('-u','--uri', default=None, help="URI of Crazyflie (chanel option will not be effective)")
parser.add_argument('-b','--bus', default=None, help="Ivy bus [default to system IVY bus]")
parser.add_argument('-s','--scan', action='store_true', help="Scan available Crazyflie at startup")
parser.add_argument('-v', '--verbose', dest='verbose', action='store_true', help="display debug messages")
args = parser.parse_args()
if args.scan:
import cflib.crtp
# Initialize the low-level drivers (don't list the debug drivers)
cflib.crtp.radiodriver.set_retries_before_disconnect(1500)
cflib.crtp.radiodriver.set_retries(3)
cflib.crtp.init_drivers(enable_debug_driver=False)
# Scan for Crazyflies and use the first one found
print('Scanning interfaces for Crazyflies...')
if args.address is not None:
address = int(args.address, 16)
else:
address = None # equivalent to default 0xE7E7E7E7E7
available = cflib.crtp.scan_interfaces(address)
if len(available) > 0:
print('Crazyflies found:')
for i in available:
print(' ',i[0])
else:
print('No radio. Leaving')
sys.exit(1)
bridge = None
link_uri = None
if args.uri is not None:
link_uri = args.uri
else:
link_uri = 'radio://0/' + args.chanel + '/2M'
try:
# Start radio to ivy bridge
bridge = RadioBridge(link_uri, verbose=args.verbose)
# The Crazyflie lib doesn't contain anything to keep the application alive,
# so this is where your application should do something. In our case we
# are just waiting until we are disconnected.
while bridge.is_connected:
bridge.run()
except KeyboardInterrupt:
pass
except Exception as e:
print("Failing with error:", e)
if bridge is not None:
bridge.is_connected = False
bridge.shutdown()
time.sleep(1)
sys.exit()